I'm experimenting with the Alpha Framework and some consolidated (5 day) indicators. I'm building an AlphaModel that should work with weekly PPO to generate insights.
I'm having trouble properly warming up my indicators, even manually in OnSecuritiesChanged. I think this should work, but the indicators are not warming up until the needed amount of time has actually elapsed in the backtest (i.e. they are not warming up ahead of time as I would wish).
Another, unrelated problem, is that I have set:
self.UniverseSettings.Resolution = Resolution.Daily
in my algo, and, farther on.:
symbols = [ Symbol.Create(ticker, SecurityType.Equity, Market.USA) for ticker in tickers ]
# set algorithm framework models
self.SetUniverseSelection(ManualUniverseSelectionModel(symbols))
and despite what I think should result in daily resolution setting for all my data, my alpha model's Update method is called every minute. I can't figure out why, I'd think with daily resolution for the data, I would only have my AlphaModel's Update called once a day. I can work around this but wonder why I need to.
Here is a summary of what I am doing to try to warm up the 5 day indicators within the AlphaModel - 1)subscribing the consolidator with the symbol using the SubscriptionManager, 2) making sure the consolidator DataConsolidated calls the SymbolData OnWeeklyData which updates the weekly PPO and 3) manually Updating the consolidator with history data to warmup the data (and hopefully the PPO by extension):
def OnSecuritiesChanged(self, algorithm, changes):
'''Event fired each time the we add/remove securities from the data feed
Args:
algorithm: The algorithm instance that experienced the change in securities
changes: The security additions and removals from the algorithm'''
for added in changes.AddedSecurities:
symbolData = self.symbolDataBySymbol.get(added.Symbol)
if symbolData is None:
symbolData = SymbolData(added)
symbolData.PPO = PercentagePriceOscillator(self.fastPeriod, self.slowPeriod)
weeklyConsolidator = TradeBarConsolidator(timedelta(days=5))
weeklyConsolidator.DataConsolidated += symbolData.OnWeeklyData
algorithm.SubscriptionManager.AddConsolidator (added.Symbol.Value, weeklyConsolidator)
tradeBarHistory = algorithm.History([added.Symbol.Value], 150, Resolution.Daily)
for index, tradeBar in tradeBarHistory.loc[added.Symbol.Value].iterrows():
typedBar = TradeBar()
typedBar.High = tradeBar.high
typedBar.Low = tradeBar.low
typedBar.Close = tradeBar.close
typedBar.Open = tradeBar.open
typedBar.Volume = tradeBar.volume
typedBar.EndTime = index
algorithm.Debug(str(typedBar.EndTime))
weeklyConsolidator.Update(typedBar)
#TODO: PPO is not initializing
self.symbolDataBySymbol[added.Symbol] = symbolData
...and farther on in SymbolData...
def OnWeeklyData(self, sender, bar):
self.PPO.Update(bar.EndTime, bar.Close)
My assumption is that by: 1)subscribing the consolidator with the symbol using the SubscriptionManager, 2) making sure the consolidator DataConsolidated calls the SymbolData OnWeeklyUpdate to update the PPO and 3) manually Updating the consolidator to warmup the data, that my PPO should be warmed up at the proper period via manual updates to the consolidator. It doesn't work. How should I be manually warming up a consolidated indicator within the Alpha Framework?
Thanks!
Gurumeher Sawhney
Please check the algorithm below as a reference on how to manually warm up a consolidated indicator within the Alpha Framework. In this example, the indicator is saved in SymbolData and has RegisterIndicators and WarmUpIndicators methods, which are both called while the symbol is being added to the Universe. The indicator is registered via the consolidator in order to automatically trigger the update method. Warmup retrieves downloaded historical data as a dataframe and iterates through it. It is conceptually easier than trying to update weeklyConsolidator with historical data. The following code should provide a good template; it uses the ROC indicator with the past 20 days historical data to determine its insights.
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.
Heather Lamb
Thank you for your help! This successfully warmed up the Daily indicator used in your example.
Attached I modified your example to create and warmup a weekly consolidated indicator to show how this can be done. I've attached the updated code for reference. Instead of using a Daily ROC, I've created a 20 week ROC indicator and warmed it up manually. It warms up using modifications to the SymbolData self.Conslidator initialization and changes to the WarmUp method (to update the consolidator vs the indicator directly and requiring more history than before). See attached.
Thanks.
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.
Charles Naccio
An example of warming up a conslidator should really be in the documentation, otherwise I think people will default to making multiple history calls, which is likely super inefficient.
In my case, I needed to attach pricing data (trade bars) from multiple time frames to my SymbolData object, so I could easily reference candles from other time frames. i.e. What's the current 20min bar's high. To accomplish this, I used rolling windows to capture the current day's bars for each time frame. i.e. todays20MinuteBars = new RollingWindow<TradeBar>(20) to store the current day's 20, 20min candles.
Then I used the method shown by Heather Lamb for warming up the consolidators that in turn warmed up the rolling windows. Code is below; hope it helps.
Thanks guys!
/// <summary> /// Alpha Creation /// </summary> private class BigGapAlphaModel : AlphaModel { /// <summary> /// Actively monitored stocks /// </summary> private Dictionary<Symbol, ActiveSymbol> _activeSymbols; /// <summary> /// Algorithm Properties /// </summary> #region /// <summary> /// Minimum price of securities to be traded. /// </summary> [Parameter ("minPrice")] private decimal minPrice = 1.00m; /// <summary> /// Maximum price of securities to be traded. /// </summary> [Parameter ("maxPrice")] private decimal maxPrice = 16.99m; /// <summary> /// Maximum market capitilization of securities /// to be traded. /// </summary> [Parameter ("maxMarketCap")] private decimal maxMarketCap = 1000000000m; /// <summary> /// Minimum percentage change from prior day's /// closing price to current price. /// </summary> [Parameter ("minChangeFromClose")] private decimal minChangeFromClose = 0.40m; /// <summary> /// Maximum percentage change from prior day's /// closing price to current price. /// </summary> [Parameter ("maxChangeFromClose")] private decimal maxChangeFromClose = 10.00m; /// <summary> /// Maximum percentage gap up from prior day's /// closing price to today's opening price. /// </summary> [Parameter ("maxGapUp")] private decimal maxGapUp = 7.00m; /// <summary> /// Maximum percentage change from daily 20 /// period simple moving average. /// </summary> [Parameter ("maxChangeFromDaily20MA")] private decimal maxChangeFromDaily20MA = 6.00m; /// <summary> /// Minimum percentage change from hourly 8 /// period simple moving average. /// </summary> [Parameter ("minChangeFromHourly8MA")] private decimal minChangeFromHourly8MA = 0.01m; /// <summary> /// Maximum position in lifetime range. /// i.e. Show me stocks where the price is no more /// than 100% above the low of this range /// </summary> [Parameter ("maxPositionInLifetimeRange")] private decimal maxPositionInLifetimeRange = 1.00m; /// <summary> /// Minimum float of traded symbols. /// </summary> [Parameter ("minFloat")] private decimal minFloat = 1000000m; /// <summary> /// Minimum volume required today to place a trade. /// </summary> [Parameter ("minVolumeToday")] private decimal minVolumeToday = 150000m; /// <summary> /// Maximum per share loss allowed for any one trade. /// </summary> [Parameter ("maxLossPerShare")] private decimal maxLossPerShare = 5.00m; #endregion /// <summary> /// Instantiate alpha model /// </summary> public BigGapAlphaModel () { // Keep track of currently active symbols in our universe _activeSymbols = new Dictionary<Symbol, ActiveSymbol> (); } /// <summary> /// Process securities being added/removed from the stock universe /// </summary> /// <param name="algo">Reference to current algorithm instance</param> /// <param name="changes">Securities being added or removed from universe</param> public override void OnSecuritiesChanged (QCAlgorithm algo, SecurityChanges changes) { // Clean up after symbols removed from universe foreach (Security security in changes.RemovedSecurities) { _activeSymbols.Remove (security.Symbol); } // Initialize new symbols added to universe var addedSymbols = changes.AddedSecurities.Select (x => x.Symbol); var history = algo.History (addedSymbols, TimeSpan.FromDays (20)); foreach (var symbol in addedSymbols) { if (!_activeSymbols.ContainsKey (symbol)) { _activeSymbols.Add ( symbol, new ActiveSymbol (algo, symbol, history.Get (symbol)) ); } } // How many symbols currently active? algo.Debug ($"Active Symbols: {_activeSymbols.Count}"); } /// <summary> /// Update event is the primary entry point for your alpha. /// Each new data point will be pumped in here. /// </summary> /// <param name="algo">Reference to current algorithm instance</param> /// <param name="data">Slice object keyed by symbol containing the stock data</param> public override IEnumerable<Insight> Update (QCAlgorithm algo, Slice data) { var insights = new List<Insight> (); // Process trade bars foreach (var bar in data.Bars) { // Do something } // Return insights generated by this alpha return insights; } /// <summary> /// Models an active symbol, with details needed /// to power a common charting like view. /// </summary> private class ActiveSymbol { /// <summary> /// Reference to current algorithm instance /// </summary> private QCAlgorithm _algo; /// <summary> /// Reference to given symbol/stock /// </summary> public Symbol symbol; /// <summary> /// Multiple Timeframes /// </summary> #region /// <summary> /// Daily bar consolidator /// </summary> private readonly IDataConsolidator _dailyConsolidator; /// <summary> /// Daily bars /// </summary> public RollingWindow<TradeBar> dailyBars; /// <summary> /// Daily 20 period simple moving average /// </summary> public SimpleMovingAverage daily20MA; #endregion /// <summary> /// Generate a new active symbol, to track required /// details utilized in our trading rules/logic. /// </summary> /// <param name="algo">Reference to current QuantConnect algorithm</param> /// <param name="symbol">Stock symbol reference</param> public ActiveSymbol (QCAlgorithm algo, Symbol symbol, IEnumerable<TradeBar> history) { this._algo = algo; this.symbol = symbol; // Initialize multiple timeframes _dailyConsolidator = algo.Consolidate ( symbol, TimeSpan.FromDays (1), bar => dailyBars.Add (bar) ); // Initialize indicators daily20MA = new SimpleMovingAverage (20); algo.RegisterIndicator (symbol, daily20MA, _dailyConsolidator); // Warm up timeframes and indicators WarmUp (history); } /// <summary> /// Unload an active symbol, and release held resources. /// This utility is primarily used when securities are /// removed from stock selection universe. /// </summary> ~ActiveSymbol () { // Unload consolidators _algo.SubscriptionManager.RemoveConsolidator (symbol, _dailyConsolidator); } /// <summary> /// Warm up multiple timeframe windows, and indicators, /// via corresponding conslidators. /// </summary> private void WarmUp (IEnumerable<TradeBar> history) { foreach (var bar in history) { _dailyConsolidator.Update (bar); } _algo.Debug ( $"New symbol ({symbol.Value}) is ready after warmup \n" + $"is ready: {daily20MA.IsReady} \n" + $"samples: {daily20MA.Samples} \n" + $"value: {daily20MA.Current.Value} \n" + $"warmup period: {daily20MA.WarmUpPeriod} \n" + $"period: {daily20MA.Period}" ); } } }
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!