Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    indicator on resampled data

    Indicators/Strategies/Analyzers
    3
    4
    486
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • J T
      J T last edited by

      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/25

      class 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

      duni4i 1 Reply Last reply Reply Quote 0
      • duni4i
        duni4i @J T last edited by

        @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.

        run-out 1 Reply Last reply Reply Quote 0
        • run-out
          run-out @duni4i last edited by

          @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

          1. 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 to self.datas[0]

          # cerebro.adddata(data0)   # remove
          

          RunBacktest.com

          duni4i 1 Reply Last reply Reply Quote 0
          • duni4i
            duni4i @run-out last edited by

            @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:
            9b12a815-f578-42f5-a65e-e18776e8fdc4-image.png

            1 Reply Last reply Reply Quote 0
            • 1 / 1
            • First post
              Last post
            Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors