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/

    Multiple datafeed with signal column

    General Code/Help
    2
    3
    115
    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.
    • toinou222
      toinou222 last edited by

      Hello all,

      I would like to backtest on multiple data feeds that already has a 'signal' column. Here is my custom data loader and sizer.

      class CustomDataLoader(btfeeds.PandasData):
          lines = ("signal",)
          params = (("signal", -1),)
          datafields = btfeeds.PandasData.datafields + (["signal",])
          
      df_btc = pd.read_csv('BTC_USDT_4h_with_signal.csv', infer_datetime_format=True,
              parse_dates=['datetime'],
              dtype={
                  "open"  : "float",
                  "high"  : "float",
                  "low"   : "float",
                  "close" : "float",
                  "volume": "float",
                  "signal": "float"
                  },
              index_col=0)
      df_btc.index = pd.to_datetime(df_btc.datetime, format='%Y-%m-%dT%H:%M:%S.%fZ')
      df_btc = df_btc[['open', 'high', 'low', 'close', 'volume', 'signal']]
      
      df_eth = pd.read_csv('ETH_USDT_4h_with_signal.csv', infer_datetime_format=True,
              parse_dates=['datetime'],
              dtype={
                  "open"  : "float",
                  "high"  : "float",
                  "low"   : "float",
                  "close" : "float",
                  "volume": "float",
                  "signal": "float"
                  },
              index_col=0)
      df_eth.index = pd.to_datetime(df_eth.datetime, format='%Y-%m-%dT%H:%M:%S.%fZ')
      df_eth = df_eth[['open', 'high', 'low', 'close', 'volume', 'signal']]
      
      bt_data_btc = CustomDataLoader(dataname=df_btc)
      bt_data_eth = CustomDataLoader(dataname=df_eth)
      
      class ST_sizer(bt.sizers.PercentSizer):
          params = (('percent', 20),)
          def _getsizing(self, comminfo, cash, data, isbuy):
              position = self.broker.getposition(data)
              size = self.p.percent * (1 + (position.size != 0))
              return size
      

      The strategy goal is simple: if signal =1 go long elif signal = -1 go short

      class TestStrategy(bt.SignalStrategy):
          
          def log(self, txt, dt=None):
              ''' Logging function fot this strategy'''
              dt = dt or self.data.datetime[0]
              print('%s, %s' % (bt.num2date(dt), txt))
      
          def __init__(self):
              self.orderid = None
              self.inds = dict()
              for i, d in enumerate(self.datas):
                  self.inds[d] = dict()
                  self.inds[d]['close'] = self.data.close
                  self.inds[d]['signal'] = self.data.signal
              
          def next(self):
              for i, d in enumerate(self.datas):
                  dt, dn = bt.num2date(self.datetime[0]), d._name
                  print(dt, dn, self.inds[d]['signal'][0])    
                  
                  if self.orderid:
                      return  # if an order is active, no new orders are allowed
      
                  if not self.getposition(d).size:  # not yet in market
                      if self.inds[d]['signal'][0] > 0:
                          self.buy(data=d)
                      elif self.inds[d]['signal'][0] < 0:
                          self.sell(data=d)
      
                  else:  # in the market
                      if self.inds[d]['signal'][0] > 0 and self.getposition(d).size < 0:
                          self.close(data=d)
                          self.buy(data=d)
                      elif self.inds[d]['signal'][0] < 0 and self.getposition(d).size > 0:
                          self.close(data=d)
                          self.sell(data=d)
      
          def notify_trade(self, trade):
              if trade.justopened:
                  print('-' * 32, ' TRADE OPENED ', '-' * 32)
                  print('{}, {}, Price: {}, Size {}, Value {}, Commission {}'.format(
                      bt.num2date(trade.dtopen),
                      self.data._name,
                      round(trade.price, 2),
                      round(trade.size, 2),
                      round(trade.value, 2),
                      round(trade.commission), 6))
                  print('-' * 70)
              if trade.isclosed:
                  print('-' * 32, ' TRADE CLOSED ', '-' * 32)
                  print('{}, {}, Duration {} days, Price: {}, Commission {}, PNL {}, PNL net {}'.format(
                      bt.num2date(trade.dtclose),
                      self.data._name,
                      round((trade.barlen)*4/24,2),
                      round(self.data.open[0], 2),
                      round(trade.commission,2),
                      round(trade.pnl,2),
                      round(trade.pnlcomm,2)))
                  print('-' * 70)
      
      
      # Create a cerebro entity
      cerebro = bt.Cerebro()
      
      # Add data
      cerebro.adddata(bt_data_btc, name='btc')
      cerebro.adddata(bt_data_eth, name='eth')
      
      # Add sizer
      cerebro.addsizer(ST_sizer)
      
      # Add a strategy
      cerebro.addstrategy(TestStrategy)
      
      # Add broker fees
      cerebro.broker.setcommission(commission=0.0004)
      
      # Set our desired cash start
      cerebro.broker.setcash(10000.0)
      
      
      # Run over everything
      strat = cerebro.run()
      
      

      When printing logs it seems that the backtest only takes 1st datafeed (btc) signal and applies it to both feed.

      Signals differs slightly from each other.

      2020-07-06 16:00:00 btc -1.0
      2020-07-06 16:00:00 eth -1.0
      2020-07-06 20:00:00 btc -1.0
      2020-07-06 20:00:00 eth -1.0
      2020-07-07 00:00:00 btc -1.0
      2020-07-07 00:00:00 eth -1.0
      2020-07-07 04:00:00 btc -1.0
      2020-07-07 04:00:00 eth -1.0
      2020-07-07 08:00:00 btc -1.0
      2020-07-07 08:00:00 eth -1.0
      2020-07-07 12:00:00 btc -1.0
      2020-07-07 12:00:00 eth -1.0
      2020-07-07 16:00:00 btc -1.0
      2020-07-07 16:00:00 eth -1.0
      2020-07-07 20:00:00 btc -1.0
      2020-07-07 20:00:00 eth -1.0
      2020-07-08 00:00:00 btc -1.0
      2020-07-08 00:00:00 eth -1.0
      2020-07-08 04:00:00 btc -1.0
      2020-07-08 04:00:00 eth -1.0
      2020-07-08 08:00:00 btc -1.0
      2020-07-08 08:00:00 eth -1.0
      2020-07-08 12:00:00 btc -1.0
      2020-07-08 12:00:00 eth -1.0
      2020-07-08 16:00:00 btc -1.0
      2020-07-08 16:00:00 eth -1.0
      2020-07-08 20:00:00 btc -1.0
      2020-07-08 20:00:00 eth -1.0
      2020-07-09 00:00:00 btc -1.0
      2020-07-09 00:00:00 eth -1.0
      2020-07-09 04:00:00 btc -1.0
      2020-07-09 04:00:00 eth -1.0
      2020-07-09 08:00:00 btc -1.0
      2020-07-09 08:00:00 eth -1.0
      2020-07-09 12:00:00 btc -1.0
      2020-07-09 12:00:00 eth -1.0
      2020-07-09 16:00:00 btc -1.0
      2020-07-09 16:00:00 eth -1.0
      2020-07-09 20:00:00 btc -1.0
      2020-07-09 20:00:00 eth -1.0
      2020-07-10 00:00:00 btc -1.0
      2020-07-10 00:00:00 eth -1.0
      2020-07-10 04:00:00 btc -1.0
      2020-07-10 04:00:00 eth -1.0
      2020-07-10 08:00:00 btc -1.0
      2020-07-10 08:00:00 eth -1.0
      2020-07-10 12:00:00 btc -1.0
      2020-07-10 12:00:00 eth -1.0
      2020-07-10 16:00:00 btc -1.0
      2020-07-10 16:00:00 eth -1.0
      2020-07-10 20:00:00 btc -1.0
      2020-07-10 20:00:00 eth -1.0
      2020-07-11 00:00:00 btc -1.0
      2020-07-11 00:00:00 eth -1.0
      2020-07-11 04:00:00 btc -1.0
      2020-07-11 04:00:00 eth -1.0
      2020-07-11 08:00:00 btc -1.0
      2020-07-11 08:00:00 eth -1.0
      2020-07-11 12:00:00 btc -1.0
      2020-07-11 12:00:00 eth -1.0
      2020-07-11 16:00:00 btc -1.0
      2020-07-11 16:00:00 eth -1.0
      2020-07-11 20:00:00 btc -1.0
      2020-07-11 20:00:00 eth -1.0
      2020-07-12 00:00:00 btc -1.0
      2020-07-12 00:00:00 eth -1.0
      2020-07-12 04:00:00 btc -1.0
      2020-07-12 04:00:00 eth -1.0
      2020-07-12 08:00:00 btc -1.0
      2020-07-12 08:00:00 eth -1.0
      2020-07-12 12:00:00 btc -1.0
      2020-07-12 12:00:00 eth -1.0
      2020-07-12 16:00:00 btc -1.0
      2020-07-12 16:00:00 eth -1.0
      2020-07-12 20:00:00 btc -1.0
      2020-07-12 20:00:00 eth -1.0
      2020-07-13 00:00:00 btc -1.0
      2020-07-13 00:00:00 eth -1.0
      2020-07-13 04:00:00 btc -1.0
      2020-07-13 04:00:00 eth -1.0
      2020-07-13 08:00:00 btc -1.0
      2020-07-13 08:00:00 eth -1.0
      2020-07-13 12:00:00 btc -1.0
      2020-07-13 12:00:00 eth -1.0
      2020-07-13 16:00:00 btc -1.0
      2020-07-13 16:00:00 eth -1.0
      2020-07-13 20:00:00 btc -1.0
      2020-07-13 20:00:00 eth -1.0
      2020-07-14 00:00:00 btc -1.0
      2020-07-14 00:00:00 eth -1.0
      2020-07-14 04:00:00 btc -1.0
      2020-07-14 04:00:00 eth -1.0
      2020-07-14 08:00:00 btc -1.0
      2020-07-14 08:00:00 eth -1.0
      2020-07-14 12:00:00 btc -1.0
      2020-07-14 12:00:00 eth -1.0
      2020-07-14 16:00:00 btc -1.0
      2020-07-14 16:00:00 eth -1.0
      2020-07-14 20:00:00 btc -1.0
      2020-07-14 20:00:00 eth -1.0
      2020-07-15 00:00:00 btc -1.0
      2020-07-15 00:00:00 eth -1.0
      2020-07-15 04:00:00 btc -1.0
      2020-07-15 04:00:00 eth -1.0
      2020-07-15 08:00:00 btc -1.0
      2020-07-15 08:00:00 eth -1.0
      2020-07-15 12:00:00 btc -1.0
      2020-07-15 12:00:00 eth -1.0
      2020-07-15 16:00:00 btc -1.0
      2020-07-15 16:00:00 eth -1.0
      2020-07-15 20:00:00 btc -1.0
      2020-07-15 20:00:00 eth -1.0
      2020-07-16 00:00:00 btc -1.0
      2020-07-16 00:00:00 eth -1.0
      2020-07-16 04:00:00 btc -1.0
      2020-07-16 04:00:00 eth -1.0
      2020-07-16 08:00:00 btc -1.0
      2020-07-16 08:00:00 eth -1.0
      2020-07-16 12:00:00 btc -1.0
      2020-07-16 12:00:00 eth -1.0
      2020-07-16 16:00:00 btc -1.0
      2020-07-16 16:00:00 eth -1.0
      2020-07-16 20:00:00 btc -1.0
      2020-07-16 20:00:00 eth -1.0
      2020-07-17 00:00:00 btc -1.0
      2020-07-17 00:00:00 eth -1.0
      2020-07-17 04:00:00 btc -1.0
      2020-07-17 04:00:00 eth -1.0
      2020-07-17 08:00:00 btc -1.0
      2020-07-17 08:00:00 eth -1.0
      2020-07-17 12:00:00 btc -1.0
      2020-07-17 12:00:00 eth -1.0
      2020-07-17 16:00:00 btc -1.0
      2020-07-17 16:00:00 eth -1.0
      2020-07-17 20:00:00 btc -1.0
      2020-07-17 20:00:00 eth -1.0
      2020-07-18 00:00:00 btc -1.0
      2020-07-18 00:00:00 eth -1.0
      2020-07-18 04:00:00 btc -1.0
      2020-07-18 04:00:00 eth -1.0
      2020-07-18 08:00:00 btc -1.0
      2020-07-18 08:00:00 eth -1.0
      2020-07-18 12:00:00 btc -1.0
      2020-07-18 12:00:00 eth -1.0
      2020-07-18 16:00:00 btc -1.0
      2020-07-18 16:00:00 eth -1.0
      2020-07-18 20:00:00 btc -1.0
      2020-07-18 20:00:00 eth -1.0
      2020-07-19 00:00:00 btc -1.0
      2020-07-19 00:00:00 eth -1.0
      2020-07-19 04:00:00 btc -1.0
      2020-07-19 04:00:00 eth -1.0
      2020-07-19 08:00:00 btc -1.0
      2020-07-19 08:00:00 eth -1.0
      2020-07-19 12:00:00 btc -1.0
      2020-07-19 12:00:00 eth -1.0
      2020-07-19 16:00:00 btc -1.0
      2020-07-19 16:00:00 eth -1.0
      2020-07-19 20:00:00 btc -1.0
      2020-07-19 20:00:00 eth -1.0
      2020-07-20 00:00:00 btc -1.0
      2020-07-20 00:00:00 eth -1.0
      2020-07-20 04:00:00 btc -1.0
      2020-07-20 04:00:00 eth -1.0
      2020-07-20 08:00:00 btc -1.0
      2020-07-20 08:00:00 eth -1.0
      2020-07-20 12:00:00 btc -1.0
      2020-07-20 12:00:00 eth -1.0
      2020-07-20 16:00:00 btc -1.0
      2020-07-20 16:00:00 eth -1.0
      2020-07-20 20:00:00 btc -1.0
      2020-07-20 20:00:00 eth -1.0
      2020-07-21 00:00:00 btc -1.0
      2020-07-21 00:00:00 eth -1.0
      2020-07-21 04:00:00 btc -1.0
      2020-07-21 04:00:00 eth -1.0
      2020-07-21 08:00:00 btc -1.0
      2020-07-21 08:00:00 eth -1.0
      2020-07-21 12:00:00 btc -1.0
      2020-07-21 12:00:00 eth -1.0
      2020-07-21 16:00:00 btc -1.0
      2020-07-21 16:00:00 eth -1.0
      2020-07-21 20:00:00 btc -1.0
      2020-07-21 20:00:00 eth -1.0
      2020-07-22 00:00:00 btc -1.0
      2020-07-22 00:00:00 eth -1.0
      2020-07-22 04:00:00 btc -1.0
      2020-07-22 04:00:00 eth -1.0
      2020-07-22 08:00:00 btc -1.0
      2020-07-22 08:00:00 eth -1.0
      2020-07-22 12:00:00 btc -1.0
      2020-07-22 12:00:00 eth -1.0
      2020-07-22 16:00:00 btc -1.0
      2020-07-22 16:00:00 eth -1.0
      2020-07-22 20:00:00 btc -1.0
      2020-07-22 20:00:00 eth -1.0
      2020-07-23 00:00:00 btc 1.0
      2020-07-23 00:00:00 eth 1.0
      --------------------------------  TRADE CLOSED  --------------------------------
      2020-07-23 04:00:00, btc, Duration 25.17 days, Price: 9517.9, Commission 14.01, PNL -975.51, PNL net -989.52
      ----------------------------------------------------------------------
      --------------------------------  TRADE OPENED  --------------------------------
      2020-07-23 04:00:00, btc, Price: 9517.9, Size 1.89, Value 17997.34, Commission 7
      ----------------------------------------------------------------------
      --------------------------------  TRADE CLOSED  --------------------------------
      2020-07-23 04:00:00, btc, Duration 25.17 days, Price: 9517.9, Commission 0.3, PNL -66.94, PNL net -67.24
      ----------------------------------------------------------------------
      --------------------------------  TRADE OPENED  --------------------------------
      2020-07-23 04:00:00, btc, Price: 264.32, Size 1.53, Value 405.0, Commission 0
      ----------------------------------------------------------------------
      2020-07-23 04:00:00 btc 1.0
      2020-07-23 04:00:00 eth 1.0
      2020-07-23 08:00:00 btc 1.0
      2020-07-23 08:00:00 eth 1.0
      

      As you can see here, 'self.data._name,' is always btc... and prices seems wrong as both trades are closed at BTC price.

      Sans titre.png

      For exemple, ETH data switch from short to long on the '2020-07-08 16:00:00' but the switch doesn't happen until BTC switch on the '2020-07-23 04:00:00'

      I would appreciate if anyone sees where my mistake is...
      Let me know if data is needed to reproduce the exemple?

      Thanks for your help!

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

        I notice you don't set self.orderid anywhere. You should set it when creating an order:

        self.orderid = self.buy(.etc)
        

        and then you also need to clear it when an order is complete at the end of self.notify_order.

        Have a look here at this full code.:

        https://www.backtrader.com/docu/order-creation-execution/order-creation-execution/#the-full-code

        RunBacktest.com

        1 Reply Last reply Reply Quote 1
        • toinou222
          toinou222 last edited by

          Found my error...

              def __init__(self):
                  self.order = None
                  self.inds = dict()
                  for i, d in enumerate(self.datas):
                      self.inds[d] = dict()
                      self.inds[d]['close'] = d.close
                      self.inds[d]['signal'] = d.signal
          

          I was using

           self.inds[d]['close'] = self.data.close
          

          I added the orderid as you mentionned and it works like a charm thank you!! :-)

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