indicator on resampled data
-
Hi
I am having some trouble on resampled data and custom indicator.class BaseStrategy(bt.Strategy): def __init__(self): self.zz = ZigZag(self.data0, period=2, retrace=0.05, minbars=2) def next(self): print('{},{:.5f},{:.5f},{:.5f}'.format(self.data0.datetime.datetime(0), self.zz.l.zigzag[0], self.zz.l.last_high[0], self.zz.l.last_low[0])) def main(): cerebro = bt.Cerebro(oldtrades=True) cerebro.addstrategy(BaseStrategy) df = pd.read_csv('datas\\EURUSD.csv', sep=',', header=0, index_col=0, parse_dates=True) data0 = bt.feeds.PandasData(dataname=df, timeframe=bt.TimeFrame.Minutes) cerebro.adddata(data0) cerebro.resampledata(data0, timeframe=bt.TimeFrame.Minutes, compression=240) cerebro.run(maxcpus=3, stdstats=False, runonce=True) if __name__ == '__main__': main()
Simple enough code that passes in 2 datas. Run an indicator on init and run it on data0 and print out the line values in the next() method. However, the above code does not work. The zz.l.zigzag[0] are always nan. If I remove resampleddata() line, it works and it works with only this single change.
Code of the indicator is below, courtesy of Nikolai. https://community.backtrader.com/topic/1771/zigzag-indicator-for-live-trading/25class ZigZag(bt.ind.PeriodN): # periodN controls number lines to skip i think, so period is 2 so curr_idx start at 2 lines = ('trend', 'last_high', 'last_low', 'zigzag',) plotinfo = dict( subplot=False, plotlinelabels=True, plotlinevalues=True, plotvaluetags=True, ) plotlines = dict( trend=dict(_plotskip=True), last_high=dict(color='green', ls='-', _plotskip=True), last_low=dict(color='black', ls='-', _plotskip=True), zigzag=dict(_name='zz', color='lightblue', ls='-', _skipnan=True), # linewidth=2.0, ls='-', ) params = (dict(period=2, retrace=0.25, minbars=2, _autoplot=True)) def __init__(self): super(ZigZag, self).__init__() assert self.p.retrace > 0, 'Retracement should be above zero.' assert self.p.minbars >= 0, 'Minimal bars should be >= zero.' self.ret = self.data.close * self.p.retrace / 100 self.minbars = self.p.minbars self.count_bars = 0 self.last_pivot_t = 0 self.last_pivot_ago = 0 def prenext(self): # prenext called before the minimum period required for the indicator, this case 2. So called just once. self.l.trend[0] = 0 self.l.last_high[0] = self.data.high[0] self.l.last_low[0] = self.data.low[0] self.l.zigzag[0] = (self.data.high[0] + self.data.low[0]) / 2 # print('prenext: ', self.l.trend[0], self.l.last_high[0], self.l.last_low[0], self.l.zigzag[0] ) def next(self): # this starts at 2nd line of data curr_idx = len(self.data) self.ret = self.data.close[0] * self.p.retrace / 100 self.last_pivot_ago = curr_idx - self.last_pivot_t self.l.trend[0] = self.l.trend[-1] self.l.last_high[0] = self.l.last_high[-1] self.l.last_low[0] = self.l.last_low[-1] self.l.zigzag[0] = float('nan') # print('next1:',curr_idx,self.data.close[0], self.ret, self.last_pivot_t,self.last_pivot_ago,self.l.trend[0],self.l.last_high[0],self.l.last_low[0]) # Search for trend if self.l.trend[-1] == 0: if self.l.last_low[0] < self.data.low[0] and self.l.last_high[0] < self.data.high[0]: # if current bar is higher than last high and last low self.l.trend[0] = 1 self.l.last_high[0] = self.data.high[0] self.last_pivot_t = curr_idx elif self.l.last_low[0] > self.data.low[0] and self.l.last_high[0] > self.data.high[0]: # if current bar is higher than last high and last low self.l.trend[0] = -1 self.l.last_low[0] = self.data.low[0] self.last_pivot_t = curr_idx # Up trend elif self.l.trend[-1] == 1: if self.data.high[0] > self.l.last_high[-1]: self.l.last_high[0] = self.data.high[0] self.count_bars = self.minbars self.last_pivot_t = curr_idx elif self.count_bars <= 0 and self.l.last_high[0] - self.data.low[0] > self.ret and self.data.high[0] < self.l.last_high[0]: self.l.trend[0] = -1 self.count_bars = self.minbars self.l.last_low[0] = self.data.low[0] self.l.zigzag[-self.last_pivot_ago] = self.l.last_high[0] self.last_pivot_t = curr_idx elif self.count_bars < self.minbars and self.data.close[0] < self.l.last_low[0]: self.l.trend[0] = -1 self.count_bars = self.minbars self.l.last_low[0] = self.data.low[0] self.l.zigzag[-self.last_pivot_ago] = self.l.last_high[0] self.last_pivot_t = curr_idx # Down trend elif self.l.trend[-1] == -1: if self.data.low[0] < self.l.last_low[-1]: self.l.last_low[0] = self.data.low[0] self.count_bars = self.minbars self.last_pivot_t = curr_idx elif self.count_bars <= 0 and self.data.high[0] - self.l.last_low[0] > self.ret and self.data.low[0] > self.l.last_low[0]: self.l.trend[0] = 1 self.count_bars = self.minbars self.l.last_high[0] = self.data.high[0] self.l.zigzag[-self.last_pivot_ago] = self.l.last_low[0] self.last_pivot_t = curr_idx elif self.count_bars < self.minbars and self.data.close[0] > self.l.last_high[-1]: self.l.trend[0] = 1 self.count_bars = self.minbars self.l.last_high[0] = self.data.high[0] self.l.zigzag[-self.last_pivot_ago] = self.l.last_low[0] self.last_pivot_t = curr_idx # Decrease minbars counter self.count_bars -= 1
Need some advice why this is happening, even though I have specified that the indicator run on data0. And how can I change the indicator code so that it can run even if resampled data is passed (no need to run on resampled data, but even just running on lower timeframe data would be great!) ?
Thanks
-
@j-t Hi! I have some issue, have you found a decision? As I've seen in Nikolai's post this indicator is for one timeframe. I try to change it but nothing works.
-
@duni4i It appears you are always adding the indicator to self.datas[0].
def __init__(self): self.zz = ZigZag(self.data0, period=2, retrace=0.05, minbars=2)
Try either
- Change this to the second dataline
def __init__(self): self.zz = ZigZag(self.datas[1], period=2, retrace=0.05, minbars=2)
or
2. remove the lower time frame if you don't need it. This will move the resampled data toself.datas[0]
# cerebro.adddata(data0) # remove
-
@run-out said in indicator on resampled data:
self.zz = ZigZag(self.datas[1], period=2, retrace=0.05, minbars=2)
Hi! I've done everything as you had adviced and i have data for datas[1], but nothing is calculated for datas[0]. COuld you advice something to solve it?
def __init__(self): # Keep a reference to the "close" line in the data[0] dataseries self.dataclose1 = self.datas[0].close self.dataclose30 = self.datas[1].close # To keep track of pending orders self.order = None self.zigzag1 = ZigzagNiko.ZigZag(self.datas[0], period=2, retrace=0.05, minbars=2) self.zigzag30 = ZigzagNiko.ZigZag(self.datas[1], period=2, retrace=0.05, minbars=2) self.ZZLevels1 = pd.DataFrame(columns = ['ZZ1']) self.ZZLevels30 = pd.DataFrame(columns = ['ZZ30'])
and second part when i check data is:
def next(self): # Simply log the closing price of the series from the reference self.log('Close1, %.2f' % self.dataclose1[0]) self.log('Close30, %.2f' % self.dataclose30[0]) if self.zigzag30.lines.zigzag[0]>0 or self.zigzag1.lines.zigzag[0]>0: self.log('ZZ30, %.2f' % self.zigzag30.lines.zigzag[0]) self.log('ZZ10, %.2f' % self.zigzag1.lines.zigzag[0]) # Check if an order is pending ... if yes, we cannot send a 2nd one if self.order: return df1 = pd.DataFrame({'ZZ1': [self.zigzag1.lines.zigzag[0]]}) df30 = pd.DataFrame({'ZZ30': [self.zigzag30.lines.zigzag[0]]}) self.ZZLevels30=self.ZZLevels30.append(df30, ignore_index=True) self.ZZLevels30=self.ZZLevels30.dropna() self.ZZLevels1=self.ZZLevels1.append(df1, ignore_index=True) self.ZZLevels1=self.ZZLevels1.dropna() print(self.ZZLevels30) print(self.ZZLevels1)
and finally i add data this way:
data = exporter.download(asset_id, market=Market.FUTURES, timeframe=Timeframe.MINUTES1, start_date=fromdate1) data['<DATE>'] = data['<DATE>'].apply(lambda x: str(x)) data['<TIME>'] = data['<TIME>'].apply(lambda x: str(x)) data['<DATE>'] =data['<DATE>']+' '+ data['<TIME>'] data['<DATE>'] = data['<DATE>'].apply(lambda x: pd.to_datetime(str(x), format='%Y-%m-%d %H:%M:%S.%f')) rts = pd.DataFrame(data) rts = rts.set_index('<DATE>') rts= rts.loc[:,['<OPEN>','<HIGH>', '<LOW>', '<CLOSE>','<VOL>']] rts.index.names = ['Date'] rts.columns=['Open','High','Low','Close','Volume'] #print(rts) data1 = bt.feeds.PandasData(dataname=rts) cerebro.adddata(data1,name = '1M') # Add the Data Feed to Cerebro data30 = cerebro.resampledata(data1, name='data30', timeframe=bt.TimeFrame.Minutes, compression = 30) # Add the Data Feed to Cerebro cerebro.adddata(data30,name = '30M')
and finally i have data for ZZ30 and nothing for ZZ1: