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/

    Volume Filler – Execution Bits added repeatedly?

    General Code/Help
    1
    1
    41
    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.
    • B
      Batman last edited by

      When adding a Volume Filler to a strategy, the strategy started executing a very small number of Trades, despite executing thousands of Orders. Without the Volume Filler, the strategy executes the number of Trades normally.

      I created a test strategy to try to understand this behavior, using a data feed file from the github repository (file: 2006-01-02-volume-min-001.txt in datas directory).

      The Volume Filler used to test always returns a constant maximum volume.

      # A simple filler: max returned size is constant
      class TestFiller(with_metaclass(MetaParams, object)):
          def __call__(self, order, price, ago):
              maxsize = FILLER_VOLUME
              return min(maxsize, abs(order.executed.remsize))
      

      And the strategy always tries to buy a constant maximum volume, but sends sell orders before reaching the maximum volume.

      class TestStrategy(backtrader.Strategy):
              
          def next(self):
              
              # Computes volume of orders already opened
              buy_orders_volume = 0
              sell_orders_volume = 0
              for order in self.broker.get_orders_open():
                  remsize = order.executed.remsize
                  if order.isbuy():
                      buy_orders_volume += remsize
                  else:
                      sell_orders_volume += abs(remsize)
      
              # Target volumes based on constant value and current position        
              target_sell_volume = self.getposition().size;
              target_buy_volume = STRATEGY_VOLUME - self.getposition().size
              
              # Computes how much volume is needed to achieve target
              required_sell_volume = target_sell_volume - sell_orders_volume
              required_buy_volume = target_buy_volume - buy_orders_volume
              
              # Send orders immediately
              if required_sell_volume > 0:
                  self.close(size=required_sell_volume)
              
              if required_buy_volume > 0:
                  self.buy(size=required_buy_volume)
      

      I added a notify_order() method to show the Execution Bits of the partial Buy Orders and also the associated Trade.

      def notify_order(self, order):
              
              # Log only partial buy orders
              if order.isbuy():
                  if order.status in [backtrader.Order.Partial]:
                      # Trade associated with the order
                      # (code snippet from method _addnotification() of backtrader.Strategy class) 
                      datatrades = self._trades[order.data][order.tradeid]
                      trade = datatrades[-1]
                      print("TRADE - ref: {}, size: {} ".format(trade.ref, trade.size))
                      
                      # Execution bits
                      for exbit in order.executed.exbits:
                          print('EXBIT - dt: {}, size:{}, price:{}, closed:{}, opened:{}'.format(
                              order.data.num2date(exbit.dt), 
                              exbit.size, 
                              exbit.price, 
                              exbit.closed, 
                              exbit.opened))
      
                      print('---')
      

      Complete code:

      import backtrader 
      import datetime 
      from backtrader.utils.py3 import with_metaclass
      from backtrader.metabase import MetaParams
      
      # Test params
      STRATEGY_VOLUME = 100
      FILLER_VOLUME = 5
      USE_FILLER = True 
      CASH = 1000000
      FROM_DATE =  datetime.datetime(2006, 1, 5) 
      TO_DATE = datetime.datetime(2006, 1, 6) 
      
      # A simple filler: max returned size is constant
      class TestFiller(with_metaclass(MetaParams, object)):
          def __call__(self, order, price, ago):
              maxsize = FILLER_VOLUME
              return min(maxsize, abs(order.executed.remsize))
      
      
      class TestStrategy(backtrader.Strategy):
              
          def next(self):
              
              # Computes volume of orders already opened
              buy_orders_volume = 0
              sell_orders_volume = 0
              for order in self.broker.get_orders_open():
                  remsize = order.executed.remsize
                  if order.isbuy():
                      buy_orders_volume += remsize
                  else:
                      sell_orders_volume += abs(remsize)
      
              # Target volumes based on constant value and current position        
              target_sell_volume = self.getposition().size;
              target_buy_volume = STRATEGY_VOLUME - self.getposition().size
              
              # Computes how much volume is needed to achieve target
              required_sell_volume = target_sell_volume - sell_orders_volume
              required_buy_volume = target_buy_volume - buy_orders_volume
              
              # Send orders immediately
              if required_sell_volume > 0:
                  self.close(size=required_sell_volume)
              
              if required_buy_volume > 0:
                  self.buy(size=required_buy_volume)
              
      
          def notify_order(self, order):
              
              # Log only partial buy orders
              if order.isbuy():
                  if order.status in [backtrader.Order.Partial]:
                      # Trade associated with the order
                      # (code snippet from method _addnotification() of backtrader.Strategy class) 
                      datatrades = self._trades[order.data][order.tradeid]
                      trade = datatrades[-1]
                      print("TRADE - ref: {}, size: {} ".format(trade.ref, trade.size))
                      
                      # Execution bits
                      for exbit in order.executed.exbits:
                          print('EXBIT - dt: {}, size:{}, price:{}, closed:{}, opened:{}'.format(
                              order.data.num2date(exbit.dt), 
                              exbit.size, 
                              exbit.price, 
                              exbit.closed, 
                              exbit.opened))
      
                      print('---')
      
      
      def run():
          cerebro = backtrader.Cerebro()
          cerebro.broker.setcash(CASH)
      
          if USE_FILLER:
              cerebro.broker.set_filler(TestFiller())
         
          data = backtrader.feeds.BacktraderCSVData(dataname='../../datas/2006-01-02-volume-min-001.txt', 
                                                  fromdate = FROM_DATE, 
                                                  todate = TO_DATE,
                                                  timeframe = backtrader.TimeFrame.Minutes,
                                             )
          cerebro.adddata(data)
          #cerebro.replaydata(data, timeframe=bt.TimeFrame.Days)
      
          cerebro.addstrategy(TestStrategy)
          cerebro.addanalyzer(backtrader.analyzers.TradeAnalyzer, _name="myTradeAnalysis")
          st = cerebro.run()[0]
          trade_analyzer = st.analyzers.myTradeAnalysis.get_analysis()
          
          print("Total trades: " + str(trade_analyzer.total.total))
          cerebro.plot()
      
      
      if __name__ == '__main__':
          run()
      
      

      Log output (truncated):

      TRADE - ref: 1, size: 5 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 10 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 25 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 45 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:05:00, size:5, price:3660.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 60 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:05:00, size:5, price:3660.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:06:00, size:5, price:3661.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 80 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:05:00, size:5, price:3660.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:06:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:07:00, size:5, price:3661.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 80 
      EXBIT - dt: 2006-01-05 09:07:00, size:5, price:3661.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 115 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:05:00, size:5, price:3660.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:06:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:07:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:08:00, size:5, price:3662.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 115 
      EXBIT - dt: 2006-01-05 09:08:00, size:5, price:3662.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 155 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:05:00, size:5, price:3660.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:06:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:07:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:08:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:09:00, size:5, price:3662.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 155 
      EXBIT - dt: 2006-01-05 09:09:00, size:5, price:3662.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 200 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:05:00, size:5, price:3660.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:06:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:07:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:08:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:09:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:10:00, size:5, price:3659.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 200 
      EXBIT - dt: 2006-01-05 09:10:00, size:5, price:3659.0, closed:0, opened:5
      ---
      TRADE - ref: 1, size: 235 
      EXBIT - dt: 2006-01-05 09:02:00, size:5, price:3666.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:03:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:04:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:05:00, size:5, price:3660.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:06:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:07:00, size:5, price:3661.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:08:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:09:00, size:5, price:3662.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:10:00, size:5, price:3659.0, closed:0, opened:5
      EXBIT - dt: 2006-01-05 09:11:00, size:5, price:3659.0, closed:0, opened:5
      ---
      ...
      

      Analyzing the log:

      1. Only one Trade is created during the entire test
      2. The size of the executed Trade (235 in the truncated log) is much larger than the maximum that the strategy tries to limit when sending orders (100 in this test)
      3. The cause of this seems to be that the Execution Bits of the partial Order are added up repeatedly

      In the log, see the increasing size of the trade (5, 10, 25, 45, 60 ...) and how the exbits with the same minute seem to be being added up even if they had already been added in the previous call (+5, +10, + 15, + 20, + 25...) . I think that with each call it should add an execution bit (ie +5, +5, + 5 ...)

      This log is to try to explain, but first I tried to debug the Backtrader source code, putting breakpoints in the strategy class for example, but my Python skills are not great (I actually learned this language to try to use Backtrader) ...

      So: is there an error in the code that deals with Execution Bits? Or am I missing something?

      1 Reply Last reply Reply Quote 0
      • 1 / 1
      • First post
        Last post
      Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
      $(document).ready(function () { app.coldLoad(); }); }