From b1479a8c5c972220f2027df089f1651cbf125ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Wed, 20 Nov 2024 14:08:05 -0500 Subject: [PATCH 01/13] First draft of the solution --- Indicators/Stochastics.cs | 2 +- Tests/Indicators/StochasticTests.cs | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Indicators/Stochastics.cs b/Indicators/Stochastics.cs index a2bafa7f444c..3268d48a7f67 100644 --- a/Indicators/Stochastics.cs +++ b/Indicators/Stochastics.cs @@ -80,7 +80,7 @@ public Stochastic(string name, int period, int kPeriod, int dPeriod) () => { } ); - WarmUpPeriod = period; + WarmUpPeriod = period + 1; } /// diff --git a/Tests/Indicators/StochasticTests.cs b/Tests/Indicators/StochasticTests.cs index 844ac41da013..7055e3a08835 100644 --- a/Tests/Indicators/StochasticTests.cs +++ b/Tests/Indicators/StochasticTests.cs @@ -101,5 +101,30 @@ public void HandlesEqualMinAndMax() Assert.AreEqual(0m, stochastics.Current.Value); } } + + [Test] + public override void WarmsUpProperly() + { + var indicator = CreateIndicator(); + var period = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod - 1; + + if (!period.HasValue) + { + Assert.Ignore($"{indicator.Name} is not IIndicatorWarmUpPeriodProvider"); + return; + } + + var startDate = new DateTime(2019, 1, 1); + + for (var i = 0; i < period.Value; i++) + { + var input = GetInput(startDate, i); + indicator.Update(input); + Assert.AreEqual(i == period.Value - 1, indicator.IsReady); + } + + Assert.AreEqual(period.Value, indicator.Samples); + Assert.IsTrue(indicator.IsReady); + } } } \ No newline at end of file From e7dd446ab22f506ef6cba3961bff5a87f2eb44fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:32:19 -0500 Subject: [PATCH 02/13] Add regression tests --- ...catorWarmsUpProperlyRegressionAlgorithm.cs | 157 ++++++++++++++++++ ...catorWarmsUpProperlyRegressionAlgorithm.py | 58 +++++++ 2 files changed, 215 insertions(+) create mode 100644 Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs create mode 100644 Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py diff --git a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs new file mode 100644 index 000000000000..1b453e667fcd --- /dev/null +++ b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs @@ -0,0 +1,157 @@ +/* + * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. + * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +*/ + +using QuantConnect.Data; +using QuantConnect.Data.Consolidators; +using QuantConnect.Indicators; +using QuantConnect.Interfaces; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace QuantConnect.Algorithm.CSharp +{ + public class StochasticIndicatorWarmsUpProperlyRegressionAlgorithm: QCAlgorithm, IRegressionAlgorithmDefinition + { + private bool _dataPointsReceived; + private Symbol _spy; + private RelativeStrengthIndex _rsi; + private RelativeStrengthIndex _rsiHistory; + private Stochastic _sto; + private Stochastic _stoHistory; + + public override void Initialize() + { + SetStartDate(2020, 1, 1); + SetEndDate(2020, 2, 1); + + _dataPointsReceived = false; + _spy = AddEquity("SPY", Resolution.Hour).Symbol; + + var dailyConsolidator = new TradeBarConsolidator(TimeSpan.FromDays(1)); + _rsi = new RelativeStrengthIndex(14, MovingAverageType.Wilders); + _sto = new Stochastic("FIRST", 14, 3, 3); + RegisterIndicator(_spy, _rsi, dailyConsolidator); + RegisterIndicator(_spy, _sto, dailyConsolidator); + + WarmUpIndicator(_spy, _rsi, TimeSpan.FromDays(1)); + WarmUpIndicator(_spy, _sto, TimeSpan.FromDays(1)); + + _rsiHistory = new RelativeStrengthIndex(14, MovingAverageType.Wilders); + _stoHistory = new Stochastic("SECOND", 14, 3, 3); + RegisterIndicator(_spy, _rsiHistory, dailyConsolidator); + RegisterIndicator(_spy, _stoHistory, dailyConsolidator); + + var history = History(_spy, 15, Resolution.Daily); + foreach (var bar in history.Take(14)) + { + _rsiHistory.Update(bar.EndTime, bar.Close); + _stoHistory.Update(bar); + } + } + + public override void OnData(Slice slice) + { + if (IsWarmingUp) return; + + if (slice.ContainsKey(_spy)) + { + _dataPointsReceived = true; + + if (_rsi.Current.Value != _rsiHistory.Current.Value) + { + throw new RegressionTestException($"Values of indicators differ: {_rsi.Name}: {_rsi.Current.Value} | {_rsiHistory.Name}: {_rsiHistory.Current.Value}"); + } + + if (_sto.StochK.Current.Value != _stoHistory.StochK.Current.Value) + { + throw new RegressionTestException($"Stoch K values of indicators differ: {_sto.Name}.StochK: {_sto.StochK.Current.Value} | {_stoHistory.Name}.StochK: {_stoHistory.StochK.Current.Value}"); + } + + if (_sto.StochD.Current.Value != _stoHistory.StochD.Current.Value) + { + throw new RegressionTestException($"Stoch D values of indicators differ: {_sto.Name}.StochD: {_sto.StochD.Current.Value} | {_stoHistory.Name}.StochD: {_stoHistory.StochD.Current.Value}"); + } + } + } + + public override void OnEndOfAlgorithm() + { + if (!_dataPointsReceived) + { + throw new Exception("No data points received"); + } + } + + /// + /// This is used by the regression test system to indicate if the open source Lean repository has the required data to run this algorithm. + /// + public bool CanRunLocally { get; } = true; + + /// + /// This is used by the regression test system to indicate which languages this algorithm is written in. + /// + public List Languages { get; } = new() { Language.CSharp, Language.Python }; + + /// + /// Data Points count of all timeslices of algorithm + /// + public long DataPoints => 302; + + /// + /// Data Points count of the algorithm history + /// + public int AlgorithmHistoryDataPoints => 45; + + /// + /// Final status of the algorithm + /// + public AlgorithmStatus AlgorithmStatus => AlgorithmStatus.Completed; + + /// + /// This is used by the regression test system to indicate what the expected statistics are from running the algorithm + /// + public Dictionary ExpectedStatistics => new Dictionary + { + {"Total Orders", "0"}, + {"Average Win", "0%"}, + {"Average Loss", "0%"}, + {"Compounding Annual Return", "0%"}, + {"Drawdown", "0%"}, + {"Expectancy", "0"}, + {"Start Equity", "100000"}, + {"End Equity", "100000"}, + {"Net Profit", "0%"}, + {"Sharpe Ratio", "0"}, + {"Sortino Ratio", "0"}, + {"Probabilistic Sharpe Ratio", "0%"}, + {"Loss Rate", "0%"}, + {"Win Rate", "0%"}, + {"Profit-Loss Ratio", "0"}, + {"Alpha", "0"}, + {"Beta", "0"}, + {"Annual Standard Deviation", "0"}, + {"Annual Variance", "0"}, + {"Information Ratio", "-0.016"}, + {"Tracking Error", "0.101"}, + {"Treynor Ratio", "0"}, + {"Total Fees", "$0.00"}, + {"Estimated Strategy Capacity", "$0"}, + {"Lowest Capacity Asset", ""}, + {"Portfolio Turnover", "0%"}, + {"OrderListHash", "d41d8cd98f00b204e9800998ecf8427e"} + }; + } +} diff --git a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py new file mode 100644 index 000000000000..88274d8bc4ea --- /dev/null +++ b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py @@ -0,0 +1,58 @@ +from datetime import timedelta +from AlgorithmImports import * + + +class StochasticIndicatorWarmsUpProperlyRegressionAlgorithm(QCAlgorithm): + def initialize(self): + self.set_start_date(2020, 1, 1) # monday = holiday.. + self.set_end_date(2020, 2, 1) + self.set_cash(100000) + + self.data_points_received = False; + self.spy = self.add_equity("SPY", Resolution.HOUR).symbol + + self.daily_consolidator = TradeBarConsolidator(timedelta(days=1)) + + self._rsi = RelativeStrengthIndex(14, MovingAverageType.WILDERS) + self._sto = Stochastic("FIRST", 14, 3, 3) + self.register_indicator(self.spy, self._rsi, self.daily_consolidator) + self.register_indicator(self.spy, self._sto, self.daily_consolidator) + + # warm_up indicator + self.warm_up_indicator(self.spy, self._rsi, timedelta(days=1)) + self.warm_up_indicator(self.spy, self._sto, timedelta(days=1)) + + + self._rsi_history = RelativeStrengthIndex(14, MovingAverageType.WILDERS) + self._sto_history = Stochastic("SECOND", 14, 3, 3) + self.register_indicator(self.spy, self._rsi_history, self.daily_consolidator) + self.register_indicator(self.spy, self._sto_history, self.daily_consolidator) + + # history warm up + history = self.history[TradeBar](self.spy, 15, Resolution.DAILY) + count = 0 + for bar in history: + count+=1 + if count == 15: + break + self._rsi_history.update(bar.end_time, bar.close) + self._sto_history.update(bar) + + def on_data(self, data: Slice): + if self.is_warming_up: + return + + if data.contains_key(self.spy): + self.data_points_received = True + if self._rsi.current.value != self._rsi_history.current.value: + raise Exception(f"Values of indicators differ: {self._rsi.name}: {self._rsi.current.value} | {self._rsi_history.name}: {self._rsi_history.current.value}") + + if self._sto.stoch_k.current.value != self._sto_history.stoch_k.current.value: + raise Exception(f"Stoch K values of indicators differ: {self._sto.name}.StochK: {self._sto.stoch_k.current.value} | {self._sto_history.name}.StochK: {self._sto_history.stoch_k.current.value}") + + if self._sto.stoch_d.current.value != self._sto_history.stoch_d.current.value: + raise Exception(f"Stoch D values of indicators differ: {self._sto.name}.StochD: {self._sto.stoch_d.current.value} | {self._sto_history.name}.StochD: {self._sto_history.stoch_d.current.value}") + + def on_end_of_algorithm(self): + if not self.data_points_received: + raise Exception("No data points received") From 4a768396d99434e369c26560349488efef94a24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:12:28 -0500 Subject: [PATCH 03/13] Nit changes --- ...icatorWarmsUpProperlyRegressionAlgorithm.cs | 4 ++++ ...icatorWarmsUpProperlyRegressionAlgorithm.py | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs index 1b453e667fcd..12298c22ec96 100644 --- a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs +++ b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs @@ -23,6 +23,10 @@ namespace QuantConnect.Algorithm.CSharp { + /// + /// Regression algorithm that asserts Stochastic indicator, registered with a different resolution consolidator, + /// is warmed up properly by calling QCAlgorithm.WarmUpIndicator + /// public class StochasticIndicatorWarmsUpProperlyRegressionAlgorithm: QCAlgorithm, IRegressionAlgorithmDefinition { private bool _dataPointsReceived; diff --git a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py index 88274d8bc4ea..4981aa615c85 100644 --- a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py +++ b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py @@ -1,7 +1,23 @@ +# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. +# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + from datetime import timedelta from AlgorithmImports import * - +### +### Regression algorithm that asserts Stochastic indicator, registered with a different resolution consolidator, +### is warmed up properly by calling QCAlgorithm.WarmUpIndicator +### class StochasticIndicatorWarmsUpProperlyRegressionAlgorithm(QCAlgorithm): def initialize(self): self.set_start_date(2020, 1, 1) # monday = holiday.. From bf20c694e6485d655ca4a4e5ee8d9f55676d6c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:51:23 -0500 Subject: [PATCH 04/13] Solve root issue --- ...catorWarmsUpProperlyRegressionAlgorithm.cs | 6 +++-- ...catorWarmsUpProperlyRegressionAlgorithm.py | 6 ++--- Algorithm/QCAlgorithm.Indicators.cs | 17 ++++++++++--- Indicators/Stochastics.cs | 2 +- Tests/Indicators/StochasticTests.cs | 25 ------------------- 5 files changed, 20 insertions(+), 36 deletions(-) diff --git a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs index 12298c22ec96..e4b5fe42ac12 100644 --- a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs +++ b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs @@ -59,9 +59,11 @@ public override void Initialize() RegisterIndicator(_spy, _stoHistory, dailyConsolidator); var history = History(_spy, 15, Resolution.Daily); - foreach (var bar in history.Take(14)) + foreach (var bar in history) { _rsiHistory.Update(bar.EndTime, bar.Close); + if (_rsiHistory.Samples == 1) continue; + _stoHistory.Update(bar); } } @@ -117,7 +119,7 @@ public override void OnEndOfAlgorithm() /// /// Data Points count of the algorithm history /// - public int AlgorithmHistoryDataPoints => 45; + public int AlgorithmHistoryDataPoints => 44; /// /// Final status of the algorithm diff --git a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py index 4981aa615c85..86c2bc1f82b7 100644 --- a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py +++ b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py @@ -46,12 +46,10 @@ def initialize(self): # history warm up history = self.history[TradeBar](self.spy, 15, Resolution.DAILY) - count = 0 for bar in history: - count+=1 - if count == 15: - break self._rsi_history.update(bar.end_time, bar.close) + if self._rsi_history.samples == 1: + continue self._sto_history.update(bar) def on_data(self, data: Slice): diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index 8ba5d84b20e7..ebf2d398627d 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3053,6 +3053,10 @@ public void WarmUpIndicator(IEnumerable symbols, IndicatorBase indicator, TimeSpan period, Func selector = null) { var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator); + var historyRequest = CreateBarCountHistoryRequests(new[] { symbol }, + ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod, + period.ToHigherResolutionEquivalent(false), + dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)).Single(); if (history == Enumerable.Empty()) return; // assign default using cast @@ -3064,7 +3068,7 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase ind indicator.Update(input); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); } /// @@ -3113,6 +3117,11 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSp where T : class, IBaseData { var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator); + var historyRequest = CreateBarCountHistoryRequests(new[] { symbol }, + ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod, + period.ToHigherResolutionEquivalent(false), + dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)).Single(); + if (history == Enumerable.Empty()) return; // assign default using cast @@ -3124,7 +3133,7 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSp indicator.Update(selector(bar)); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); } private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator) @@ -3175,7 +3184,7 @@ private bool AssertIndicatorHasWarmupPeriod(IIndicator indicator) return true; } - private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action handler, IEnumerable history, bool identityConsolidator) + private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action handler, IEnumerable history, bool identityConsolidator, HistoryRequest historyRequest) where T : class, IBaseData { IDataConsolidator consolidator; @@ -3227,7 +3236,7 @@ private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action ha // Scan for time after we've pumped all the data through for this consolidator if (lastBar != null) { - consolidator.Scan(lastBar.EndTime); + consolidator.Scan(historyRequest.EndTimeLocal); } SubscriptionManager.RemoveConsolidator(symbol, consolidator); diff --git a/Indicators/Stochastics.cs b/Indicators/Stochastics.cs index 3268d48a7f67..a2bafa7f444c 100644 --- a/Indicators/Stochastics.cs +++ b/Indicators/Stochastics.cs @@ -80,7 +80,7 @@ public Stochastic(string name, int period, int kPeriod, int dPeriod) () => { } ); - WarmUpPeriod = period + 1; + WarmUpPeriod = period; } /// diff --git a/Tests/Indicators/StochasticTests.cs b/Tests/Indicators/StochasticTests.cs index 7055e3a08835..844ac41da013 100644 --- a/Tests/Indicators/StochasticTests.cs +++ b/Tests/Indicators/StochasticTests.cs @@ -101,30 +101,5 @@ public void HandlesEqualMinAndMax() Assert.AreEqual(0m, stochastics.Current.Value); } } - - [Test] - public override void WarmsUpProperly() - { - var indicator = CreateIndicator(); - var period = (indicator as IIndicatorWarmUpPeriodProvider)?.WarmUpPeriod - 1; - - if (!period.HasValue) - { - Assert.Ignore($"{indicator.Name} is not IIndicatorWarmUpPeriodProvider"); - return; - } - - var startDate = new DateTime(2019, 1, 1); - - for (var i = 0; i < period.Value; i++) - { - var input = GetInput(startDate, i); - indicator.Update(input); - Assert.AreEqual(i == period.Value - 1, indicator.IsReady); - } - - Assert.AreEqual(period.Value, indicator.Samples); - Assert.IsTrue(indicator.IsReady); - } } } \ No newline at end of file From 8cd8939df93c8ce0cd4359947aa030910c65d7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Wed, 27 Nov 2024 10:05:59 -0500 Subject: [PATCH 05/13] Improve regression tests --- ...sticIndicatorWarmsUpProperlyRegressionAlgorithm.cs | 11 ++++++++++- ...sticIndicatorWarmsUpProperlyRegressionAlgorithm.py | 5 +++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs index e4b5fe42ac12..6159f4956430 100644 --- a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs +++ b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs @@ -41,7 +41,6 @@ public override void Initialize() SetStartDate(2020, 1, 1); SetEndDate(2020, 2, 1); - _dataPointsReceived = false; _spy = AddEquity("SPY", Resolution.Hour).Symbol; var dailyConsolidator = new TradeBarConsolidator(TimeSpan.FromDays(1)); @@ -66,6 +65,16 @@ public override void Initialize() _stoHistory.Update(bar); } + + var indicators = new List() { _rsi, _sto, _rsiHistory, _stoHistory }; + + foreach (var indicator in indicators) + { + if (!indicator.IsReady) + { + throw new RegressionTestException($"{indicator.Name} should be ready, but it is not. Number of samples: {indicator.Samples}"); + } + } } public override void OnData(Slice slice) diff --git a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py index 86c2bc1f82b7..ffcc0b83f3ef 100644 --- a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py +++ b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py @@ -52,6 +52,11 @@ def initialize(self): continue self._sto_history.update(bar) + indicators = [self._rsi, self._sto, self._rsi_history, self._sto_history] + for indicator in indicators: + if not indicator.is_ready: + raise Exception(f"{indicator.name} should be ready, but it is not. Number of samples: {indicator.samples}") + def on_data(self, data: Slice): if self.is_warming_up: return From 46ee78c97216bfe781cbb27862038feda9b3418c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Wed, 27 Nov 2024 12:09:48 -0500 Subject: [PATCH 06/13] Reduce duplication --- Algorithm/QCAlgorithm.Indicators.cs | 32 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index ebf2d398627d..72b13cf9b1ab 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3052,11 +3052,7 @@ public void WarmUpIndicator(IEnumerable symbols, IndicatorBase indicator, TimeSpan period, Func selector = null) { - var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator); - var historyRequest = CreateBarCountHistoryRequests(new[] { symbol }, - ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod, - period.ToHigherResolutionEquivalent(false), - dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)).Single(); + var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator, out var historyRequests); if (history == Enumerable.Empty()) return; // assign default using cast @@ -3068,7 +3064,7 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase ind indicator.Update(input); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequests.Single()); } /// @@ -3116,12 +3112,7 @@ public void WarmUpIndicator(IEnumerable symbols, IndicatorBase ind public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSpan period, Func selector = null) where T : class, IBaseData { - var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator); - var historyRequest = CreateBarCountHistoryRequests(new[] { symbol }, - ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod, - period.ToHigherResolutionEquivalent(false), - dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)).Single(); - + var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator, out var historyRequests); if (history == Enumerable.Empty()) return; // assign default using cast @@ -3133,15 +3124,18 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSp indicator.Update(selector(bar)); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequests.Single()); } - private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator) + private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator, out IEnumerable historyRequests) { identityConsolidator = false; + historyRequests = null; + if (!AssertIndicatorHasWarmupPeriod(indicator)) { return Enumerable.Empty(); + } var periods = ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod; @@ -3158,7 +3152,10 @@ private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols try { - return History(symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)); + CheckPeriodBasedHistoryRequestResolution(symbols, resolution, null); + historyRequests = CreateBarCountHistoryRequests + (symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)); + return GetSlicesFromHistoryRequests(historyRequests); } catch (ArgumentException e) { @@ -3168,6 +3165,11 @@ private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols return Enumerable.Empty(); } + private IEnumerable GetSlicesFromHistoryRequests(IEnumerable historyRequests) + { + return History(historyRequests).Memoize(); + } + private bool AssertIndicatorHasWarmupPeriod(IIndicator indicator) { if (indicator is not IIndicatorWarmUpPeriodProvider) From 09cd2a5f038a254e8a4febf409d3bfa131332292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Wed, 27 Nov 2024 12:47:34 -0500 Subject: [PATCH 07/13] Nit change --- Algorithm/QCAlgorithm.Indicators.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index 72b13cf9b1ab..d6e2e66c8f9d 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3135,7 +3135,6 @@ private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols if (!AssertIndicatorHasWarmupPeriod(indicator)) { return Enumerable.Empty(); - } var periods = ((IIndicatorWarmUpPeriodProvider)indicator).WarmUpPeriod; From 0f8aace6d48784756976d4eea9dc30da2f9d8940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Wed, 27 Nov 2024 14:27:57 -0500 Subject: [PATCH 08/13] Improve implementation --- Algorithm/QCAlgorithm.Indicators.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index d6e2e66c8f9d..eb0b0cabcd10 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3052,7 +3052,7 @@ public void WarmUpIndicator(IEnumerable symbols, IndicatorBase indicator, TimeSpan period, Func selector = null) { - var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator, out var historyRequests); + var history = GetIndicatorWarmUpHistory(symbol, indicator, period, out var identityConsolidator, out var historyRequest); if (history == Enumerable.Empty()) return; // assign default using cast @@ -3064,7 +3064,7 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase ind indicator.Update(input); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequests.Single()); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); } /// @@ -3112,7 +3112,7 @@ public void WarmUpIndicator(IEnumerable symbols, IndicatorBase ind public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSpan period, Func selector = null) where T : class, IBaseData { - var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator, out var historyRequests); + var history = GetIndicatorWarmUpHistory(symbol, indicator, period, out var identityConsolidator, out var historyRequest); if (history == Enumerable.Empty()) return; // assign default using cast @@ -3124,13 +3124,13 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSp indicator.Update(selector(bar)); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequests.Single()); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); } - private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator, out IEnumerable historyRequests) + private IEnumerable GetIndicatorWarmUpHistory(Symbol symbol, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator, out HistoryRequest historyRequest) { identityConsolidator = false; - historyRequests = null; + historyRequest = null; if (!AssertIndicatorHasWarmupPeriod(indicator)) { @@ -3151,10 +3151,10 @@ private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols try { + var symbols = new[] { symbol }; CheckPeriodBasedHistoryRequestResolution(symbols, resolution, null); - historyRequests = CreateBarCountHistoryRequests - (symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)); - return GetSlicesFromHistoryRequests(historyRequests); + historyRequest = CreateBarCountHistoryRequests(symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)).Single(); + return GetSlicesFromHistoryRequests(historyRequest); } catch (ArgumentException e) { @@ -3164,9 +3164,9 @@ private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols return Enumerable.Empty(); } - private IEnumerable GetSlicesFromHistoryRequests(IEnumerable historyRequests) + private IEnumerable GetSlicesFromHistoryRequests(HistoryRequest historyRequest) { - return History(historyRequests).Memoize(); + return History(historyRequest).Memoize(); } private bool AssertIndicatorHasWarmupPeriod(IIndicator indicator) From d03b3190fadc85a7c8b66aeeff52e4f6ec6c1951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:32:27 -0500 Subject: [PATCH 09/13] Address suggestions --- ...catorWarmsUpProperlyRegressionAlgorithm.cs | 9 +++++-- ...catorWarmsUpProperlyRegressionAlgorithm.py | 2 +- Algorithm/QCAlgorithm.Indicators.cs | 25 ++++++------------- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs index 6159f4956430..deef686698e8 100644 --- a/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs +++ b/Algorithm.CSharp/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.cs @@ -57,12 +57,17 @@ public override void Initialize() RegisterIndicator(_spy, _rsiHistory, dailyConsolidator); RegisterIndicator(_spy, _stoHistory, dailyConsolidator); - var history = History(_spy, 15, Resolution.Daily); + var history = History(_spy, Math.Max(_rsiHistory.WarmUpPeriod, _stoHistory.WarmUpPeriod), Resolution.Daily); + + // Warm up RSI indicator foreach (var bar in history) { _rsiHistory.Update(bar.EndTime, bar.Close); - if (_rsiHistory.Samples == 1) continue; + } + // Warm up STO indicator + foreach (var bar in history.TakeLast(_stoHistory.WarmUpPeriod)) + { _stoHistory.Update(bar); } diff --git a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py index ffcc0b83f3ef..427033f21a46 100644 --- a/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py +++ b/Algorithm.Python/StochasticIndicatorWarmsUpProperlyRegressionAlgorithm.py @@ -45,7 +45,7 @@ def initialize(self): self.register_indicator(self.spy, self._sto_history, self.daily_consolidator) # history warm up - history = self.history[TradeBar](self.spy, 15, Resolution.DAILY) + history = self.history[TradeBar](self.spy, max(self._rsi_history.warm_up_period, self._sto_history.warm_up_period), Resolution.DAILY) for bar in history: self._rsi_history.update(bar.end_time, bar.close) if self._rsi_history.samples == 1: diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index eb0b0cabcd10..f69e3a2514ba 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3052,7 +3052,7 @@ public void WarmUpIndicator(IEnumerable symbols, IndicatorBase indicator, TimeSpan period, Func selector = null) { - var history = GetIndicatorWarmUpHistory(symbol, indicator, period, out var identityConsolidator, out var historyRequest); + var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator); if (history == Enumerable.Empty()) return; // assign default using cast @@ -3064,7 +3064,7 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase ind indicator.Update(input); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator); } /// @@ -3112,7 +3112,7 @@ public void WarmUpIndicator(IEnumerable symbols, IndicatorBase ind public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSpan period, Func selector = null) where T : class, IBaseData { - var history = GetIndicatorWarmUpHistory(symbol, indicator, period, out var identityConsolidator, out var historyRequest); + var history = GetIndicatorWarmUpHistory(new[] { symbol }, indicator, period, out var identityConsolidator); if (history == Enumerable.Empty()) return; // assign default using cast @@ -3124,13 +3124,12 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSp indicator.Update(selector(bar)); }; - WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator, historyRequest); + WarmUpIndicatorImpl(symbol, period, onDataConsolidated, history, identityConsolidator); } - private IEnumerable GetIndicatorWarmUpHistory(Symbol symbol, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator, out HistoryRequest historyRequest) + private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator) { identityConsolidator = false; - historyRequest = null; if (!AssertIndicatorHasWarmupPeriod(indicator)) { @@ -3151,10 +3150,7 @@ private IEnumerable GetIndicatorWarmUpHistory(Symbol symbol, IIndicator i try { - var symbols = new[] { symbol }; - CheckPeriodBasedHistoryRequestResolution(symbols, resolution, null); - historyRequest = CreateBarCountHistoryRequests(symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)).Single(); - return GetSlicesFromHistoryRequests(historyRequest); + return History(symbols, periods, resolution, dataNormalizationMode: GetIndicatorHistoryDataNormalizationMode(indicator)); } catch (ArgumentException e) { @@ -3164,11 +3160,6 @@ private IEnumerable GetIndicatorWarmUpHistory(Symbol symbol, IIndicator i return Enumerable.Empty(); } - private IEnumerable GetSlicesFromHistoryRequests(HistoryRequest historyRequest) - { - return History(historyRequest).Memoize(); - } - private bool AssertIndicatorHasWarmupPeriod(IIndicator indicator) { if (indicator is not IIndicatorWarmUpPeriodProvider) @@ -3185,7 +3176,7 @@ private bool AssertIndicatorHasWarmupPeriod(IIndicator indicator) return true; } - private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action handler, IEnumerable history, bool identityConsolidator, HistoryRequest historyRequest) + private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action handler, IEnumerable history, bool identityConsolidator) where T : class, IBaseData { IDataConsolidator consolidator; @@ -3237,7 +3228,7 @@ private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action ha // Scan for time after we've pumped all the data through for this consolidator if (lastBar != null) { - consolidator.Scan(historyRequest.EndTimeLocal); + consolidator.Scan(this.UtcTime.ConvertFromUtc(Securities[symbol].Exchange.TimeZone)); } SubscriptionManager.RemoveConsolidator(symbol, consolidator); From 883e597e8ce167b80fab8bedc36920f6c75309ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:07:02 -0500 Subject: [PATCH 10/13] Address requested improvements --- Algorithm/QCAlgorithm.Indicators.cs | 13 ++++++++++++- Tests/Algorithm/AlgorithmIndicatorsTests.cs | 11 +++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index f69e3a2514ba..3afa3fe5f43f 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3228,7 +3228,18 @@ private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action ha // Scan for time after we've pumped all the data through for this consolidator if (lastBar != null) { - consolidator.Scan(this.UtcTime.ConvertFromUtc(Securities[symbol].Exchange.TimeZone)); + DateTime currentTime = default; + if (Securities.TryGetValue(symbol, out var security)) + { + currentTime = security.LocalTime; + } + else + { + var timezone = MarketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType); + currentTime = this.UtcTime.ConvertFromUtc(timezone); + } + + consolidator.Scan(currentTime); } SubscriptionManager.RemoveConsolidator(symbol, consolidator); diff --git a/Tests/Algorithm/AlgorithmIndicatorsTests.cs b/Tests/Algorithm/AlgorithmIndicatorsTests.cs index 836d52f6f32b..1175b73154cc 100644 --- a/Tests/Algorithm/AlgorithmIndicatorsTests.cs +++ b/Tests/Algorithm/AlgorithmIndicatorsTests.cs @@ -330,6 +330,17 @@ public void IndicatorCanBeWarmedUpWithTimespan() Assert.IsTrue(indicator.Samples >= 100); } + [Test] + public void IndicatorCanBeWarmedUpWithoutSymbolInSecurities() + { + var referenceSymbol = Symbol.Create("IBM", SecurityType.Equity, Market.USA); + var indicator = new SimpleMovingAverage("SMA", 100); + _algorithm.SetDateTime(new DateTime(2013, 10, 11)); + Assert.DoesNotThrow(() => _algorithm.WarmUpIndicator(referenceSymbol, indicator, TimeSpan.FromMinutes(60))); + Assert.IsTrue(indicator.IsReady); + Assert.IsTrue(indicator.Samples >= 100); + } + [Test] public void PythonCustomIndicatorCanBeWarmedUpWithTimespan() { From 264a7c0eccec5a81495453a392696213e54f0f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:08:38 -0500 Subject: [PATCH 11/13] Nit change --- Algorithm/QCAlgorithm.Indicators.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index 3afa3fe5f43f..54756efb0d38 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3228,7 +3228,7 @@ private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action ha // Scan for time after we've pumped all the data through for this consolidator if (lastBar != null) { - DateTime currentTime = default; + DateTime currentTime; if (Securities.TryGetValue(symbol, out var security)) { currentTime = security.LocalTime; From 7c1e91be8e04a41eb0a511d248c8d7f30a8110d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Fri, 29 Nov 2024 13:39:23 -0500 Subject: [PATCH 12/13] Nit changes --- Algorithm/QCAlgorithm.Indicators.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index 54756efb0d38..9197c040f973 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3235,8 +3235,8 @@ private void WarmUpIndicatorImpl(Symbol symbol, TimeSpan period, Action ha } else { - var timezone = MarketHoursDatabase.GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType); - currentTime = this.UtcTime.ConvertFromUtc(timezone); + var exchangeHours = MarketHoursDatabase.GetExchangeHours(symbol.ID.Market, symbol, symbol.SecurityType); + currentTime = UtcTime.ConvertFromUtc(exchangeHours.TimeZone); } consolidator.Scan(currentTime); From 21d32a8bbb654066b002a017154914a4b78c792c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Andr=C3=A9s=20Marino=20Rojas?= <47573394+Marinovsky@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:34:36 -0500 Subject: [PATCH 13/13] Nit change --- Algorithm/QCAlgorithm.Indicators.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Algorithm/QCAlgorithm.Indicators.cs b/Algorithm/QCAlgorithm.Indicators.cs index 9197c040f973..24e0c781f10e 100644 --- a/Algorithm/QCAlgorithm.Indicators.cs +++ b/Algorithm/QCAlgorithm.Indicators.cs @@ -3130,7 +3130,6 @@ public void WarmUpIndicator(Symbol symbol, IndicatorBase indicator, TimeSp private IEnumerable GetIndicatorWarmUpHistory(IEnumerable symbols, IIndicator indicator, TimeSpan timeSpan, out bool identityConsolidator) { identityConsolidator = false; - if (!AssertIndicatorHasWarmupPeriod(indicator)) { return Enumerable.Empty();