I am using the algorithm framework and on main.py I am trying to find 14 day RSI of SPY to use as one of several indicators of market conditions, others to be added later, which will determine model set used for alpha, universe, etc. but the RSI determination is not working. QC appears to be using LEAN v2.5.0.0.17034. I set a 14-period daily RSI for SPY with TradeBarConsolidator and RegisterIndicator should be IsReady=True with ~36.55 on 2018-12-31 (Yahoo adjusted closes, 4 up/9 down days over 14 periods), but stays IsReady=False at Samples=14, crashing post-warm-up on 2019-01-03. Code uses standard v2 setup—expecting RSI ready after 14 daily bars from consolidator. Is this a v2.5 RSI bug? How do I make RSI work without crashing?
+ Expand
# region imports
from AlgorithmImports import *
from universe import (StrongBullUniverseModel, WeakBullUniverseModel, SidewaysUpUniverseModel,
SidewaysDownUniverseModel, WeakBearUniverseModel, StrongBearUniverseModel)
from alpha import (StrongBullAlphaModel, WeakBullAlphaModel, SidewaysUpAlphaModel,
SidewaysDownAlphaModel, WeakBearAlphaModel, StrongBearAlphaModel)
from portfolio import (StrongBullPortfolioModel, WeakBullPortfolioModel, SidewaysUpPortfolioModel,
SidewaysDownPortfolioModel, WeakBearPortfolioModel, StrongBearPortfolioModel)
from risk import (StrongBullRiskModel, WeakBullRiskModel, SidewaysUpRiskModel,
SidewaysDownRiskModel, WeakBearRiskModel, StrongBearRiskModel)
from execution import (StrongBullExecutionModel, WeakBullExecutionModel, SidewaysUpExecutionModel,
SidewaysDownExecutionModel, WeakBearExecutionModel, StrongBearExecutionModel)
# endregion
class MatrixMarketAlgo(QCAlgorithm):
def initialize(self):
self.set_start_date(2019, 1, 1)
self.set_end_date(2019, 1, 7)
self.set_cash(100000)
self.UniverseSettings.Resolution = Resolution.Daily
self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol
self.rsi = self.RSI(self.spy, 14, Resolution.Daily)
consolidator = TradeBarConsolidator(TimeSpan.FromDays(1))
consolidator.DataConsolidated += self.on_consolidated_data
self.SubscriptionManager.AddConsolidator(self.spy, consolidator)
self.RegisterIndicator(self.spy, self.rsi, consolidator)
self.SetWarmUp(14, Resolution.Daily)
self.market_condition = None
self.prev_condition = None
self.universe_models = {
"strong_bull": StrongBullUniverseModel(), "weak_bull": WeakBullUniverseModel(),
"sideways_up": SidewaysUpUniverseModel(), "sideways_down": SidewaysDownUniverseModel(),
"weak_bear": WeakBearUniverseModel(), "strong_bear": StrongBearUniverseModel()
}
self.alpha_models = {
"strong_bull": StrongBullAlphaModel(), "weak_bull": WeakBullAlphaModel(),
"sideways_up": SidewaysUpAlphaModel(), "sideways_down": SidewaysDownAlphaModel(),
"weak_bear": WeakBearAlphaModel(), "strong_bear": StrongBearAlphaModel()
}
self.portfolio_models = {
"strong_bull": StrongBullPortfolioModel(), "weak_bull": WeakBullPortfolioModel(),
"sideways_up": SidewaysUpPortfolioModel(), "sideways_down": SidewaysDownPortfolioModel(),
"weak_bear": WeakBearPortfolioModel(), "strong_bear": StrongBearPortfolioModel()
}
self.risk_models = {
"strong_bull": StrongBullRiskModel(), "weak_bull": WeakBullRiskModel(),
"sideways_up": SidewaysUpRiskModel(), "sideways_down": SidewaysDownRiskModel(),
"weak_bear": WeakBearRiskModel(), "strong_bear": StrongBearRiskModel()
}
self.execution_models = {
"strong_bull": StrongBullExecutionModel(), "weak_bull": WeakBullExecutionModel(),
"sideways_up": SidewaysUpExecutionModel(), "sideways_down": SidewaysDownExecutionModel(),
"weak_bear": WeakBearExecutionModel(), "strong_bear": StrongBearExecutionModel()
}
self.universe_model = self.universe_models["strong_bull"]
self.alpha_model = self.alpha_models["strong_bull"]
self.portfolio_model = self.portfolio_models["strong_bull"]
self.risk_model = self.risk_models["strong_bull"]
self.execution_model = self.execution_models["strong_bull"]
self.AddUniverseSelection(self.universe_model)
self.AddAlpha(self.alpha_model)
self.SetPortfolioConstruction(self.portfolio_model)
self.SetRiskManagement(self.risk_model)
self.SetExecution(self.execution_model)
self.Schedule.On(self.DateRules.EveryDay(self.spy), self.TimeRules.At(16, 30), self.update_market_and_models)
def on_consolidated_data(self, sender, bar):
self.Debug(f"Consolidator at {bar.EndTime}: SPY Close={bar.Close}, RSI - Samples={self.rsi.Samples}, IsReady={self.rsi.IsReady}, Value={self.rsi.Current.Value if self.rsi.IsReady else 'N/A'}")
def update_market_and_models(self):
if self.IsWarmingUp:
return
self.Debug(f"Update at {self.Time}: RSI - IsReady={self.rsi.IsReady}, Value={self.rsi.Current.Value if self.rsi.IsReady else 'N/A'}")
if self.rsi.IsReady:
rsi_value = self.rsi.Current.Value
if rsi_value >= 90:
self.market_condition = "strong_bull"
elif rsi_value >= 70:
self.market_condition = "weak_bull"
elif rsi_value >= 50:
self.market_condition = "sideways_up"
elif rsi_value >= 30:
self.market_condition = "sideways_down"
elif rsi_value >= 10:
self.market_condition = "weak_bear"
else:
self.market_condition = "strong_bear"
else:
self.market_condition = None
if self.market_condition is None:
self.Log("ERROR: Market condition is None - insufficient data or RSI not ready")
raise Exception("Market condition calculation failed - stopping algo")
if self.prev_condition is not None and self.market_condition != self.prev_condition:
self.Log(f"ALERT: Market condition changed from {self.prev_condition} to {self.market_condition}")
self.universe_model = self.universe_models[self.market_condition]
self.alpha_model = self.alpha_models[self.market_condition]
self.portfolio_model = self.portfolio_models[self.market_condition]
self.risk_model = self.risk_models[self.market_condition]
self.execution_model = self.execution_models[self.market_condition]
self.SetUniverseSelection(self.universe_model)
self.SetAlpha(self.alpha_model)
self.SetPortfolioConstruction(self.portfolio_model)
self.SetRiskManagement(self.risk_model)
self.SetExecution(self.execution_model)
self.Log(f"Market condition set to: {self.market_condition}")
self.prev_condition = self.market_condition
def on_data(self, data):
if self.spy in data and data[self.spy] is not None:
self.Debug(f"on_data at {self.Time}: SPY Close={data[self.spy].Close}, RSI - Samples={self.rsi.Samples}, IsReady={self.rsi.IsReady}, Value={self.rsi.Current.Value if self.rsi.IsReady else 'N/A'}")
self.Log(f"ON_DATA START: Slice at {self.Time}, Market: {self.market_condition}")
for symbol in self.universe_model.symbols:
if data.ContainsKey(symbol):
self.Debug(f"on_data: {symbol.Value} received")
insights = self.alpha_model.Update(self, data)
targets = self.portfolio_model.CreateTargets(self, insights)
adjusted_targets = self.risk_model.ManageRisk(self, targets)
self.execution_model.Execute(self, adjusted_targets)
self.Log(f"ON_DATA END: Slice processed")
Mia Alissi
Key Points:
universe
,alpha
,portfolio
,risk
,execution
) exist and are correctly referenced.DataConsolidated
event is used correctly with a valid operator.Sources: E T F Constituent Universe R S I Alpha Model Algorithm, Accumulative Insight Portfolio Regression Algorithm, Confidence Weighted Framework Algorithm, Leveraged ETFs With Systematic Risk Management, Momentum And State Of Market Filters
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Prefer Not To Say
Thank you, i have a follow up question, something unexpected is happening. Using LEAN v2.5, I set a 14-period daily RSI for SPY with TradeBarConsolidator and RegisterIndicator (code/logs attached). It calculates correctly (~36.55 on 2019-01-02, matches Yahoo adjusted closes), but IsReady=False at Samples=14 (2018-12-31), only flipping True at Samples=15 (2019-01-02). Docs suggest RSI should be ready after 14 bars—why the extra sample in v2.5? Is this a bug, or do I need to adjust warm-up/consolidator to hit IsReady at 14? Works fine post-warm-up, just want to understand the lag."
Logs snippet:
Updated code:
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!