I recently worked on single asset backtests with daily resolution without any problems. I was working primarily with ETF data.
I have recently begun working on multi asset strategies using 15 forex pairs provided through the Oanda data feed at hourly resolution. These backtests take long periods to acually launch (close to an hour on some occasions) and rarely finish. When I move back to daily resolution and 15 forex pairs my backtests are also timing out at times. The strategies I am testing are not overly complex so I am surprised to experience these issues. I should also note this is occuring on two completely different strategies.
Are there speed differences between data feeds? Eg: ETF data vs Oanda forex data?
Is there a guide with tips to improve backtest speed?
Is anybody else experiencing these long waits and backtests which do not complete?
Do my local specs have any relation to backtest times or are these speeds all based upon server specs?
Jared Broad
Hi Kieran; yesterday we had an issue with the cloud which delayed some launches by about 20minutes. This might have been what you experienced. Generally, 15 hourly resolution datasets will be quite fast; depending on your implementation.
General tips
- Use history calls sparingly.
- Use online formulas vs batch ones.
Your local computer won't impact the backtest speed; however, it may impact your viewing of the backtest results. Some browsers have issues drawing lots of chart data.
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.
Kieran Flynn
Thanks for the tips Jared!
In my OnData function I will call something like this for 15 symbols:
EURUSD = self.History(["EURUSD"], 500, Resolution.Daily)
or,
EURUSD = self.History(["EURUSD"], 500, Resolution.Hourly)
Is this overuse of history calls? Is there an better way to retrieve data for analysis?
Jared Broad
You should ideally only call those once in Initialize and then use a RollingWindow to add the other bars incrementally as they arrive.
You can see an example of this in the RollingWindow documentation.
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.
Kieran Flynn
Thanks Jared I appreciate the help!
Kieran Flynn
# In Initialize, create the rolling windows def Initialize(self): # Create a Rolling Window to keep the 4 decimal self.closeWindow = RollingWindow[decimal](4) # Create a Rolling Window to keep the 2 TradeBar self.tradeBarWindow = RollingWindow[TradeBar](2) # Create a Rolling Window to keep the 2 QuoteBar self.quoteBarWindow = RollingWindow[QuoteBar](2) # In OnData, update the rolling windows def OnData(self, data): # Add SPY bar close in the rolling window self.closeWindow.Add(data["SPY"].Close) # Add SPY TradeBar in rolling window self.tradeBarWindow.Add(data["SPY"]) # Add EURUSD QuoteBar in rolling window self.quoteBarWindow.Add(data["EURUSD"])
This code was on the documentation provided.
What are the '2 Quotebars' and '2 TradeBars' referenced in the comments? I understand what Quote and Trade Bars are, I'm just having trouble understanding what the 2's refer to.
Kieran Flynn
def Initialize(self): self.SetStartDate(2018,1,1) self.SetEndDate(2018,2,2) self.SetCash(100000) self.AddForex("EURUSD", Resolution.Hour, Market.Oanda) def OnData(self, data): EURUSD_Data = self.History(["EURUSD"], 500, Resolution.Hour) a = EURUSD_Data['close'].iloc[0] b = EURUSD_Data['close'].iloc[499]
Above is a simplified reprsentation of how my algorithm begins.
The issue is that each time the OnData function is run, EURUSD_Data will be repopulated with 500 periods of OHLC, Bid-OHLC and Ask-OHLC when I really only need the most recent close (a) and another close from x amount of periods back (b).
I then have to repeat this for 14 other symbols which to get the data that I need.
This repeats over and over for every bar and is likely why I have had slow and failing backtests.
I have been unable to work how to use a RollingWindow implementation to return the values needed for the variables a and b above, could somebody please help me with the code to return these two using a RollingWindow?
Gurumeher Sawhney
The number at the end of the RollingWindow constructor is the size of the RollingWindow. So in the line self.closeWindow = RollingWindow[decimal](4) there is a RollingWindow with a window of 4 decimal values. The elements are indexed, so they can be accessed by self.closeWindow[int]. The link below can provide more information about using RollingWindow.
For the algorithm-specific question, a RollingWindow might not be the answer. A RollingWindow is an array of data that allows for reverse list access semantics, where the object with index [0] refers to the most recent item in the window and index [Length-1] refers to the last item in the window. If the algorithm above needs specific history data at period a and period b then a possible solution could be using the self.History(Symbol,DateTime,Datetime,Resolution). This provides historical data between two fixed times and will give smaller datasets. Are periods a and b fixed dates or are they a fixed amount away from the current date? If they need to be incremented, the following code might help.
date = datetime.datetime(2010,8,1)
date += datetime.timedelta(days=1)
The backtest below shows the self.History(Symbol,DateTime,Datetime,Resolution) call. Hope this provides enough guidance.
Kieran Flynn
I have tested two different algorithms with both FXCM and Oanda FX products and with ETFs and notice the slowness only occurs with the FX products.
Are the historical datasets of these products stored on different servers? I ask because my algorithms are fine with ETF history, but consistently timeout for very basic FX backtests which have time resolution below the daily time timeframe. I have been attempting only hourly timeframes not down to minute or tick.
I know that the FX history includes both bid OHLC and ask OHLC rather than just regular OHLC but I don't think this alone should slow things down so much considering how basic the things I am testing are.
Jared Broad
shouldn't time out because of FX but more likely because of a design choice
in the algorithm.
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.
Kieran Flynn
Are the historical datasets stored on the same servers for both FX and Equities?
Jared Broad
Correct all data is served in the same way.
The algorithm is asking for a history request every single bar which can be quite slow. I'd recommend using a rolling window to maintain a list like this.
def OnData(self, data): EURUSD_Data = self.History(["EURUSD"], 500, Resolution.Hour)
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.
Kieran Flynn
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!