Backtrader Community

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

    help with indicator based on multiple data feeds not synchronised

    General Code/Help
    2
    4
    607
    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.
    • M
      momentum last edited by

      Hi,

      I would like to implement an indicator that first calculates the bid-ask midpoint on two separate minute-bar data feeds, one for bid and the other for ask. These data feeds are not synchronised i.e. there are minutes when one has value and the other does not. Although the value of the indicator is correct, its length is not. When the second feed does not have a minute bar of the first feed, it just overwrites the indicator value.

      Many thanks for the help.

      import backtrader as bt
      import sys
      import os
      
      
      class StrategyBidAsk(bt.Strategy):
      
          def next(self):
              output_str = ""
              for i in range(len(self.datas)):
                  output_str += "{}: {}, {}|".format(self.datas[i]._name, self.datas[i].datetime.datetime(0), self.datas[i].lines.close[0])
              output_str = output_str[:-1]
              print(output_str)
              for ind in self.getindicators_lines():
                  line_names = ind.getlinealiases()
                  for idx in range(len(line_names)):
                      print("{} {} {} {} {}".format(ind.plotinfo.plotname or ind.__class__.__name__,
                                              line_names[idx], ind.lines[idx][0], ind.lines[idx][-1], len(ind)))
      
      
      class MidPriceIndicator(bt.Indicator):
          lines = ('toy_mid',)
      
          def __init__(self):
              self.lines.toy_mid = (self.datas[0]+self.datas[1])/2
      
      
      def main(argv):
      
          folder = "data"
          files = [['Toy_Ask.csv', 'Toy_Bid.csv']]
          cash = 100000.0
      
          cerebro = bt.Cerebro()
          cerebro.broker.setcash(cash)
          cerebro.broker.set_shortcash(False)
          cerebro.broker.setcommission(commission=0)
          cerebro.broker.set_coc(False)
      
          for file in files:
              if not isinstance(file, list):
                  file = [file]
              data_list = []
              for i, f in enumerate(file):
                  data = bt.feeds.GenericCSVData(
                          dataname=os.path.join(folder, f),
                          dtformat='%Y-%m-%d %H:%M:%S', # default
                          datetime=0,         # default
                          time=-1,            # default
                          close=1,
                          high=-1,
                          low=-1,
                          open=-1,
                          volume=-1,           # default
                          openinterest=-1,    # default for not present
                          timeframe=bt.TimeFrame.Minutes,
                          compression=1)      # default
                  if i != 0 and len(file) == 2:
                      data.compensate(data_list[0])
                  data_list.append(data)
                  cerebro.adddata(data, name=os.path.splitext(f)[0])
      
          idx = cerebro.addstrategy(StrategyBidAsk)
          cerebro.addsizer_byidx(idx, bt.sizers.SizerFix, stake=100)
          cerebro.addindicator(MidPriceIndicator, cerebro.datasbyname["Toy_Bid"]._getline("close"), cerebro.datasbyname["Toy_Ask"]._getline("close"))
          cerebro.run(runonce=False, preload=True)
          cerebro.plot(volume=False, numfigs=1)
      
      
      if __name__ == "__main__":
          main(sys.argv)
      
      # # Output
      # Toy_Ask: 2018-08-08 00:00:01, 3.0|Toy_Bid: 2018-08-08 00:00:01, 5.0
      # MidPriceIndicator toy_mid 4.0 4.0 1
      # Toy_Ask: 2018-08-08 00:02:01, 3.0|Toy_Bid: 2018-08-08 00:02:01, 6.0
      # MidPriceIndicator toy_mid 4.5 4.0 2
      # Toy_Ask: 2018-08-08 00:02:01, 3.0|Toy_Bid: 2018-08-08 00:03:01, 7.0
      # MidPriceIndicator toy_mid 5.0 4.5 3
      # Toy_Ask: 2018-08-08 00:04:01, 0.0|Toy_Bid: 2018-08-08 00:03:01, 7.0
      # MidPriceIndicator toy_mid 3.5 4.5 3
      # Toy_Ask: 2018-08-08 00:08:01, 1.0|Toy_Bid: 2018-08-08 00:08:01, 2.0
      # MidPriceIndicator toy_mid 1.5 3.5 4
      
      
      1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators last edited by

        @momentum said in help with indicator based on multiple data feeds not synchronised:

        Although the value of the indicator is correct, its length is not. When the second feed does not have a minute bar of the first feed, it just overwrites the indicator value.

        The indicator has the right length and the right value. If the data feeds have different paces, the 1st data feed is the clock for the indicator and marks the tempo. The indicator cannot add the length of both data feeds because it would then have a greater length than the system itself.

        1 Reply Last reply Reply Quote 0
        • M
          momentum last edited by

          Thanks for your reply and help. By system you mean the strategy? Because in this case, strategy will have length 5 while indicator length 4.

          # Toy_Ask: 2018-08-08 00:00:01, 3.0|Toy_Bid: 2018-08-08 00:00:01, 5.0
          # MidPriceIndicator toy_mid 4.0 4.0 1 1
          # Toy_Ask: 2018-08-08 00:02:01, 3.0|Toy_Bid: 2018-08-08 00:02:01, 6.0
          # MidPriceIndicator toy_mid 4.5 4.0 2 2
          # Toy_Ask: 2018-08-08 00:02:01, 3.0|Toy_Bid: 2018-08-08 00:03:01, 7.0
          # MidPriceIndicator toy_mid 5.0 4.5 3 3
          # Toy_Ask: 2018-08-08 00:04:01, 0.0|Toy_Bid: 2018-08-08 00:03:01, 7.0
          # MidPriceIndicator toy_mid 3.5 4.5 3 4
          # Toy_Ask: 2018-08-08 00:08:01, 1.0|Toy_Bid: 2018-08-08 00:08:01, 2.0
          # MidPriceIndicator toy_mid 1.5 3.5 4 5
          
          import backtrader as bt
          import sys
          import os
          
          
          class StrategyBidAsk(bt.Strategy):
          
              def next(self):
                  output_str = ""
                  for i in range(len(self.datas)):
                      output_str += "{}: {}, {}|".format(self.datas[i]._name, self.datas[i].datetime.datetime(0), self.datas[i].lines.close[0])
                  output_str = output_str[:-1]
                  print(output_str)
                  for ind in self.getindicators_lines():
                      line_names = ind.getlinealiases()
                      for idx in range(len(line_names)):
                          print("{} {} {} {} {} {}".format(ind.plotinfo.plotname or ind.__class__.__name__,
                                                  line_names[idx], ind.lines[idx][0], ind.lines[idx][-1], len(ind), len(self)))
          
          
          class MidPriceIndicator(bt.Indicator):
              lines = ('toy_mid',)
          
              def __init__(self):
                  self.lines.toy_mid = (self.datas[0]+self.datas[1])/2
          
          
          def main(argv):
          
              folder = "data"
              files = [['Toy_Ask.csv', 'Toy_Bid.csv']]
              cash = 100000.0
          
              cerebro = bt.Cerebro()
              cerebro.broker.setcash(cash)
              cerebro.broker.set_shortcash(False)
              cerebro.broker.setcommission(commission=0)
              cerebro.broker.set_coc(False)
          
              for file in files:
                  if not isinstance(file, list):
                      file = [file]
                  data_list = []
                  for i, f in enumerate(file):
                      data = bt.feeds.GenericCSVData(
                              dataname=os.path.join(folder, f),
                              dtformat='%Y-%m-%d %H:%M:%S', # default
                              datetime=0,         # default
                              time=-1,            # default
                              close=1,
                              high=-1,
                              low=-1,
                              open=-1,
                              volume=-1,           # default
                              openinterest=-1,    # default for not present
                              timeframe=bt.TimeFrame.Minutes,
                              compression=1)      # default
                      if i != 0 and len(file) == 2:
                          data.compensate(data_list[0])
                      data_list.append(data)
                      cerebro.adddata(data, name=os.path.splitext(f)[0])
          
              idx = cerebro.addstrategy(StrategyBidAsk)
              cerebro.addsizer_byidx(idx, bt.sizers.SizerFix, stake=100)
              cerebro.addindicator(MidPriceIndicator, cerebro.datasbyname["Toy_Bid"]._getline("close"), cerebro.datasbyname["Toy_Ask"]._getline("close"))
              cerebro.run(runonce=False, preload=True)
              cerebro.plot(volume=False, numfigs=1)
          
          
          if __name__ == "__main__":
              main(sys.argv)
          
          
          1 Reply Last reply Reply Quote 0
          • B
            backtrader administrators last edited by

            The system can be longer than the underlying elements. If not, it would impossible to operate with different timeframes simultaneously.

            But it cannot be shorter.

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