Problem occurring when I change 'cerebro.adddata(data, name = i)' to 'cerebro.resampledata(data , timeframe = bt.TimeFrame.Minutes, compression=15,name = i)' Error: return self.array[self.idx + ago] IndexError: array index out of range
-
I can't thank the developers enough for this platform. But here I am again with another post trying to figure out what I am doing wrong. I know the mistake might be something really basic.
Important portions of the code are mentioned below.
init functiondef __init__(self): ''' Create an dictionary of indicators so that we can dynamically add the indicators to the strategy using a loop. This mean the strategy will work with any numner of data feeds. ''' self.inds = dict() self.order = {} for i, d in enumerate(self.datas): self.order[d._name] = None self.inds[d] = dict() self.inds[d]['atr14'] = bt.indicators.AverageTrueRange(d, period = self.params.atrperiod) self.inds[d]['macd'] = bt.indicators.MACD(d, period_me1=self.p.macd1, period_me2=self.p.macd2, period_signal=self.p.macdsig) self.inds[d]['mcross'] = bt.indicators.CrossUp(self.inds[d]['macd'].macd, self.inds[d]['macd'].signal)
Main logic in next():
def next(self): # self.logdata() for i, d in enumerate(self.datas): dt, dn = self.datetime.date(), d._name pos = self.getposition(d).size self.logdata() print(d._name) #ERROR OCCURSE BELOW THIS LINE if self.inds[d]['atr14'][0] * self.params.atrmultiplier < (d.high[0]-d.low[0]) and d.close[0]<d.close[-1]: # This is where the error occurs # self.buy(data=d, size=1) if self.order[d._name]: self.log('We already have a buy order for %s in place' % d._name) return self.log(' BUYING. ||| symbol: %s , atr14 : %.2f , high-low : %.2f, close[0]: %.2f, close[-1] %.2f ' % (d._name,self.inds[d]['atr14'][0],(d.high[0]-d.low[0]),d.close[0],d.close[-1])) self.order[d._name] = self.order_target_value(data=d, target = 30000)
Code for data insertion for multiple stocks written below. This code gives error.
for i in stocks_5: stock_ohlc = data_csv[data_csv['Symbol'] == i][['open','high','low','close','volume']] data = bt.feeds.PandasData(dataname=stock_ohlc, sessionstart = datetime.time(9,15), sessionend=datetime.time(15,15)) cerebro.resampledata(data , timeframe = bt.TimeFrame.Minutes, compression=15,name = i)
Keeping everything same but using this code works and I get a proper output.
for i in stocks_5: stock_ohlc = data_csv[data_csv['Symbol'] == i][['open','high','low','close','volume']] data = bt.feeds.PandasData(dataname=stock_ohlc, timeframe = bt.TimeFrame.Minutes, compression=15, sessionstart = datetime.time(9,15), sessionend=datetime.time(15,15)) cerebro.adddata(data, name = i)
The only reason I need to use resample data instead of addatla is because as far as I know there is a necessity to use resample data for 15 minute bars when paper trading I interactive brokers.
I can't post output here of the code that is working since it is really long.
Also 1 important thing to consider which I have deduced is the error occurs when there is no data for that stock. For example out of 5 stocks data of 4 stocks are starting on 21st January but the 5th is starting on 24th, this is where the error occurs.Here is the output when I have the error:
1,2018-12-21T09:15:00,O: 43.85,H: 43.85,L: 43.10,C: 43.30,V: 222.00 20MICRONS 1,2018-12-21T09:15:00,O: 43.85,H: 43.85,L: 43.10,C: 43.30,V: 222.00 21STCENMG 1,2018-12-21T09:15:00,O: 43.85,H: 43.85,L: 43.10,C: 43.30,V: 222.00 3IINFOTEC 1,2018-12-21T09:15:00,O: 43.85,H: 43.85,L: 43.10,C: 43.30,V: 222.00 3MINDIA 1,2018-12-21T09:15:00,O: 43.85,H: 43.85,L: 43.10,C: 43.30,V: 222.00 3PLAND --------------------------------------------------------------------------- IndexError Traceback (most recent call last) <ipython-input-43-a3e55db0bf8e> in <module> 291 # Run over everything 292 # cerebro.broker.set_coc(True) --> 293 cerebro.run() 294 295 #Get final portfolio Value /usr/local/Cellar/python35/3.5.7_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/backtrader/cerebro.py in run(self, **kwargs) 1125 # let's skip process "spawning" 1126 for iterstrat in iterstrats: -> 1127 runstrat = self.runstrategies(iterstrat) 1128 self.runstrats.append(runstrat) 1129 if self._dooptimize: /usr/local/Cellar/python35/3.5.7_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/backtrader/cerebro.py in runstrategies(self, iterstrat, predata) 1296 self._runnext_old(runstrats) 1297 else: -> 1298 self._runnext(runstrats) 1299 1300 for strat in runstrats: /usr/local/Cellar/python35/3.5.7_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/backtrader/cerebro.py in _runnext(self, runstrats) 1628 self._check_timers(runstrats, dt0, cheat=False) 1629 for strat in runstrats: -> 1630 strat._next() 1631 if self._event_stop: # stop if requested 1632 return /usr/local/Cellar/python35/3.5.7_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/backtrader/strategy.py in _next(self) 345 346 def _next(self): --> 347 super(Strategy, self)._next() 348 349 minperstatus = self._getminperstatus() /usr/local/Cellar/python35/3.5.7_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/backtrader/lineiterator.py in _next(self) 273 self.nextstart() # only called for the 1st value 274 else: --> 275 self.prenext() 276 else: 277 # assume indicators and others operate on same length datas <ipython-input-43-a3e55db0bf8e> in prenext(self) 115 d.plotinfo.plotmaster = self.datas[0] 116 def prenext(self): --> 117 self.next() 118 119 def next(self): <ipython-input-43-a3e55db0bf8e> in next(self) 126 print(d._name) 127 if not pos and self.p.typeofentry == 1: # no market / no orders --> 128 if self.inds[d]['atr14'][0] * self.params.atrmultiplier < (d.high[0]-d.low[0]) and d.close[0]<d.close[-1]: 129 # self.buy(data=d, size=1) 130 if self.order[d._name]: /usr/local/Cellar/python35/3.5.7_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/backtrader/lineseries.py in __getitem__(self, key) 465 466 def __getitem__(self, key): --> 467 return self.lines[0][key] 468 469 def __setitem__(self, key, value): /usr/local/Cellar/python35/3.5.7_1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/backtrader/linebuffer.py in __getitem__(self, ago) 161 162 def __getitem__(self, ago): --> 163 return self.array[self.idx + ago] 164 165 def get(self, ago=0, size=1): IndexError: array index out of range
Also I really don't mind implementing this exact code with add data but I have some issue when live paper trading it in interactive brokers thus I have to use resample data. I think there is a need I show the prenext() function to get further insight so here it is:
def prenext(self): self.next()
Again I might be wrong in many things I am considering. Please feel free to correct me. Any help would be appreciated. Thanks in advance.
-
As a guess - When you simply add data you define data feed time frame and compression. However, when you use resampling, than your original data feed time frame and compression is not defined. Only data feed and compression of the resultant data feed.
Maybe this causes the error.
-
Thank you for the reply. I tried defining the original data feed time frame and compression and then using resampling on it.
Note: I don't really need to do this for backtesting but I am doing this as I need to resample the data for interactive brokers live paper trading.
But I still got the same error at the same place.for i in stocks_5: stock_ohlc = data_csv[data_csv['Symbol'] == i][['open','high','low','close','volume']] data = bt.feeds.PandasData(dataname=stock_ohlc, timeframe = bt.TimeFrame.Minutes, compression=15, sessionstart = datetime.time(9,15), sessionend=datetime.time(15,15)) cerebro.resampledata(data, timeframe = bt.TimeFrame.Minutes, compression=15, name = i)
-
So here is an update for the same. I had added
def prenext(self): self.next()
so that my backtest runs the entire timeframe i.e. if I have 100 stocks the earliest possible date is taken into consideration since some stocks have IPO's later. When I removed the prenext the code worked with resample and replay data but again I am getting output for a lower timeframe i.e. if the entire timeframe is 100 days but 1 of the stocks is only 30 days I am getting the backtest of only that particular timeframe.
Is there a way to achieve both i.e. get the backtest for the entire timeframe as well as me not getting an error. I am sure I have made some silly mistake in understanding the docs but I am helpless regarding this. -
You are trying to access the prices which don't yet exist during
prenext()
. Thereforebt
returns you an error. You need to put additional check in the script to avoid it.