Hi, I am new to writing algos here. Here is the area I would like some help.
- Let's say I am using ROC to measure momentum and I want to buy SPY as long as ROC is positive over a lookback.
- The way I want to trade this is that at the end of the day, say 5 mins before market closes, I want to use the 3:55 PM (EST) market data to calculate ROC over the lookback and place trades before market closes.
- So, instead of taking signal at the end of the day and trading in the next open, we take signal 5 mins before the close and trade it.
I have attached a simple backtest. Appreciate your help!
Rahul Chowdhury
Hi Seine,
We can use scheduled events to fire blocks of code at specific times in the trading day. In this instance, let's define a scheduled event which fires everyday 5 minutes before market close.
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 5), self.Rebalance)
Then in the method which is fired by our scheduled event, let's define our rebalancing logic.
def Rebalance(self): if self.IsWarmingUp: return if self.roc.Current.Value > 0: self.SetHoldings("SPY",1) else: self.Liquidate("SPY")
Best
Rahul
Seine Yumnam
Thank you, Rahul. This really helps. Now i have follow up question. I want to use ROC over the past 5 days (for instance), so I need to use the daily resolution to calculate that. So, if I send a trade at 3:55 PM, the ROC signal will use t-1 closing price, not the 3:55 price of the same day to calculate the signal since daily data is only completed after the market closes.
What would be the solution such that I am calculating ROC signal over the past 5 days where the 5th day is today and I am using 3:55 PM data as the last price for the signal?
Rahul Chowdhury
Hi Seine,
We can accomplish this by creating a blank ROC indicator and then manually updating it with data. We will also make the change to minutely data, so that we can access the most recent price at 3:55 PM.Blank ROC indicator of period 5
self.roc = RateOfChange(5)
Let's update the indicator in our Rebalance method. In this instance the price fed into our indicator won't be EOD price but the price at 3:55 PM each day. Since scheduled events do not fire during warmup, we will also have to warm up our indicator with historical data.
def Rebalance(self): if not self.roc.IsReady: history = self.History("SPY", 5, Resolution.Daily) for bar in history: self.roc.Update(bar.EndTime, bar.Close) self.roc.Update(self.Time, self.Securities["SPY"].Close) if self.roc.Current.Value > 0: self.SetHoldings("SPY",1) else: self.Liquidate("SPY")
Seine Yumnam
Thank you, Rahul.
I want to further extend to rolling indicator window. I have tried this below but not successful.
Rahul Chowdhury
Hi Seine,
Please try to refrain from posting pictures of code. Instead, post either a code snippet or a back test because it helps us assist in debugging the code.We can create a rolling window to hold our indicator data points in initialize.
self.rocWindow = RollingWindow[IndicatorDataPoint](2)
The easiest way to update our rolling window is to add new points as our indicator is updated. We can accomplish this with the updated event handler for our rolling window.
self.roc = RateOfChange(5) self.roc.Updated += self.OnROC
Then in our event handler we can update our rolling window.
def OnROC(self, sender, updated): if self.roc.IsReady: self.rocWindow.Add(updated)
Check out the back test to see it in action.
Try experimenting with using EOD prices rather than 5-min before market close prices in the indicators. Using EOD prices is easier to implement and may not make a large difference in the performance of the strategy.
Seine Yumnam
Thanks Rahul. Apologies for the code picture. I have implemented rolling window using EOD data and I was exploring with data before market close. Performance can be significantly affected if my goal is to capture overnight return after i get a signal.
This example helps. Thanks!
Seine Yumnam
Hi Rahul,
I have employed what you recommended. But there are couple of issues I am trying to address.
1. The Volatility Calculation is give me 0 value.
if not self.roc1.IsReady: history = self.History("ZIV", 1, Resolution.Daily) for bar in history: self.roc1.Update(bar.EndTime, bar.Close) self.roc1.Update(self.Time, self.Securities["ZIV"].Close) self.std = IndicatorExtensions.Of(StandardDeviation(30), self.roc1)
2. The Average True Range calculation is failing.
if not self.atr.IsReady: history = self.History("ZIV", 20, Resolution.Daily) for bar in history: self.atr.Update(bar.EndTime, bar.Close) self.atr.Update(self.Time, self.Securities["ZIV"].Close)
Another question i had was that in your code below, why do we need to update for every bar in the history as well as the current? Meaning why do we self.roc.Update(self.Time, self.Securities["SPY"].Close) after the looping through each history bar has also has the current bar at index 0.
if not self.roc.IsReady: history = self.History("SPY", 5, Resolution.Daily) for bar in history: self.roc.Update(bar.EndTime, bar.Close) self.roc.Update(self.Time, self.Securities["SPY"].Close)
thank you!
Rahul Chowdhury
Hi Seine,
1. We need to define the std indicator once in the Initialize method. Right now, std is being defined every day in our scheduled event.
2. ATR is a bar indicator so it needs a bar to be updated.
self.atr.Update(bar)
Let's use the helper method self.ATR to define our ATR indicator. This way we can subscribe it to daily data and we don't have to update it manually with bar data. We can also warm it up with historical data with our other indicators.
history = self.History("ZIV", 20, Resolution.Daily) for bar in history: self.atr.Update(bar) self.rocfiveDay.Update(bar.EndTime, bar.Close) # voltaility calculator. one day return. self.roc1.Update(bar.EndTime, bar.Close)
Another question i had was that in your code below, why do we need to update for every bar in the history as well as the current? Meaning why do we self.roc.Update(self.Time, self.Securities["SPY"].Close) after the looping through each history bar has also has the current bar at index 0.
First reason is we need to update our indicator everyday even after warming it up historical data. Second reason is we need to update the indicator with the latest data; historical data updates the indicator with only the previous days' data. A better approach may be to warm up our indicators with historical data in Initialze.
Best
Rahul
Seine Yumnam
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!