private static decimal GetScaleFactor(FactorFile factorFile, DataNormalizationMode mode, DateTime date) { switch (mode) { case DataNormalizationMode.Raw: return(1); case DataNormalizationMode.TotalReturn: case DataNormalizationMode.SplitAdjusted: return(factorFile.GetSplitFactor(date)); case DataNormalizationMode.Adjusted: return(factorFile.GetPriceScaleFactor(date)); default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// For backwards adjusted data the price is adjusted by a scale factor which is a combination of splits and dividends. /// This backwards adjusted price is used by default and fed as the current price. /// </summary> /// <param name="date">Current date of the backtest.</param> private void UpdateScaleFactors(DateTime date) { switch (_config.DataNormalizationMode) { case DataNormalizationMode.Raw: return; case DataNormalizationMode.TotalReturn: case DataNormalizationMode.SplitAdjusted: _config.PriceScaleFactor = _factorFile.GetSplitFactor(date); break; case DataNormalizationMode.Adjusted: _config.PriceScaleFactor = _factorFile.GetPriceScaleFactor(date); break; default: throw new ArgumentOutOfRangeException(); } }
/// <summary> /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// </summary> /// <param name="data">Slice object keyed by symbol containing the stock data</param> public override void OnData(Slice data) { if (!Portfolio.Invested) { SetHoldings(_aapl, 1); } if (data.Splits.ContainsKey(_aapl)) { Log(data.Splits[_aapl].ToString()); } if (data.Bars.ContainsKey(_aapl)) { var aaplData = data.Bars[_aapl]; // Assert our volume matches what we expect if (_expectedAdjustedVolume.MoveNext() && _expectedAdjustedVolume.Current != aaplData.Volume) { // Our values don't match lets try and give a reason why var dayFactor = _factorFile.GetSplitFactor(aaplData.Time); var probableAdjustedVolume = aaplData.Volume / dayFactor; if (_expectedAdjustedVolume.Current == probableAdjustedVolume) { throw new ArgumentException($"Volume was incorrect; but manually adjusted value is correct." + $" Adjustment by multiplying volume by {1 / dayFactor} is not occurring."); } else { throw new ArgumentException($"Volume was incorrect; even when adjusted manually by" + $" multiplying volume by {1 / dayFactor}. Data may have changed."); } } } if (data.QuoteBars.ContainsKey(_aapl)) { var aaplQuoteData = data.QuoteBars[_aapl]; // Assert our askSize matches what we expect if (_expectedAdjustedAskSize.MoveNext() && _expectedAdjustedAskSize.Current != aaplQuoteData.LastAskSize) { // Our values don't match lets try and give a reason why var dayFactor = _factorFile.GetSplitFactor(aaplQuoteData.Time); var probableAdjustedAskSize = aaplQuoteData.LastAskSize / dayFactor; if (_expectedAdjustedAskSize.Current == probableAdjustedAskSize) { throw new ArgumentException($"Ask size was incorrect; but manually adjusted value is correct." + $" Adjustment by multiplying size by {1 / dayFactor} is not occurring."); } else { throw new ArgumentException($"Ask size was incorrect; even when adjusted manually by" + $" multiplying size by {1 / dayFactor}. Data may have changed."); } } // Assert our bidSize matches what we expect if (_expectedAdjustedBidSize.MoveNext() && _expectedAdjustedBidSize.Current != aaplQuoteData.LastBidSize) { // Our values don't match lets try and give a reason why var dayFactor = _factorFile.GetSplitFactor(aaplQuoteData.Time); var probableAdjustedBidSize = aaplQuoteData.LastBidSize / dayFactor; if (_expectedAdjustedBidSize.Current == probableAdjustedBidSize) { throw new ArgumentException($"Bid size was incorrect; but manually adjusted value is correct." + $" Adjustment by multiplying size by {1 / dayFactor} is not occurring."); } else { throw new ArgumentException($"Bid size was incorrect; even when adjusted manually by" + $" multiplying size by {1 / dayFactor}. Data may have changed."); } } } }