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/

    Getting executed twice on closing orders

    General Discussion
    2
    7
    2731
    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.
    • O
      Osofuego last edited by Osofuego

      I just realized this is probably in the wrong forum, but don't have enough privileges go delete so can an admin move?

      Hello. I am getting executed twice on a time triggered close order. Anyone have any thoughts on why this would occur and how to solve this?

          def next(self):
              dt = self.datas[0].datetime.date(0)
              wkdy = datetime.datetime.weekday(dt)
              tme = self.datas[0].datetime.time(0)
              
            #If not in trade and day is wed and time is 930 and the closing 5m print is up buy 1 lot 
              if not self.position:
                  if wkdy == 2:
                      if tme == datetime.time(9,30,0,0):
                          if (((self.dataclose[0] / self.dataclose[-5])-1)*100) > 0:
                              self.buy(size=1,trailamount=1)
      
      
      
              #Exit positions at 12:01 open if trail stop not triggered
              elif self.position:
                  if tme == datetime.time(12, 00, 0, 0):
                      self.close()
      
      

      and the console output in pycharm

      0_1505745090758_Backtrader Output.png

      Any thoughts? This is by far the most powerful backtesting engine I have used and love it!

      1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators last edited by

        Partial code won't for sure help. The likely culprit: you are printing twice. But cannot be ascertained.

        1 Reply Last reply Reply Quote 0
        • O
          Osofuego last edited by

          Sorry, realize it might be helpful for you to have the logging code for a question about logging.

          My first reaction to printing twice is thats probably true, but I can't seem where to find where it is printed twice. It looks like maybe the close function is doing twice as many contracts as I have open, but when i put self.close(size=1) nothing changes, I still go short 2 contracts when I am trying to close out the 1 long contract I have open. Any other users have this issue?

          class Strat(bt.Strategy):
              def log(self, txt, dt=None):
                  ''' Logging function for this strategy'''
                  dt = self.datas[0].datetime.date(0)
                  dt_time = self.datas[0].datetime.time(0)
                  dt_weekday = datetime.datetime.weekday(dt)
          
          
                  print('%s, %s' % (dt.isoformat(), txt))
          
          
              def __init__(self):
                  # Keep a reference to the "close" line in the data[0] dataseries
                  self.dataclose = self.datas[0].close
                  self.dataopen = self.datas[0].open
                  self.dt = self.datas[0].datetime.date(0)
                  self.dt_time = self.datas[0].datetime.time(0)
                  self.dt_weekday = datetime.datetime.weekday(self.dt)
          
          
          
          
          
              def notify_order(self, order):
                  if order.status in [order.Submitted, order.Accepted]:
                      # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                      return
          
                  # Check if an order has been completed
                  # Attention: broker could reject order if not enougth cash
                  if order.status in [order.Completed]:
                      if order.isbuy():
                          self.log(
                              'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f, Datetime: %s' %
                              (order.executed.price,
                               order.executed.value,
                               order.executed.comm,
                              bt.num2date(order.executed.dt)))
          
                          self.buyprice = order.executed.price
                          self.buycomm = order.executed.comm
                      else:  # Sell
                          self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f, Datetime: %s' %
                                   (order.executed.price,
                                    order.executed.value,
                                    order.executed.comm,
                                    bt.num2date(order.executed.dt)))
          
                      self.bar_executed = len(self)
          
                  elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                      self.log('Order Canceled/Margin/Rejected')
          
                  self.order = None
          
              def notify_trade(self, trade):
                  if not trade.isclosed:
                      return
                  self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                           (trade.pnl, trade.pnlcomm))
          #####CHANGED IN V4
              def next(self):
                  dt = self.datas[0].datetime.date(0)
                  wkdy = datetime.datetime.weekday(dt)
                  tme = self.datas[0].datetime.time(0)
          
          
                  if self.position:
                      if tme == datetime.time(12,00,0,0):
                          self.close()
          
                  elif not self.position:
                      if wkdy == 2:
                          if tme == datetime.time(9,30,0,0):
                              if (((self.dataclose[0] / self.dataclose[-5])-1)*100) > 0:
                                  self.buy(size=1)
          
          
          1 Reply Last reply Reply Quote 0
          • B
            backtrader administrators last edited by

            The problem is still that part of the whole still has holes

            You may not think that the surrounding parts for your strategy play any role in your whereabouts. But they mostly probably do. Things like how the data feed is loaded.

            O 1 Reply Last reply Reply Quote 0
            • O
              Osofuego @backtrader last edited by

              @backtrader Here is the code in its entirety. In the main i feed the data as a pandas dataframe and run don't do much else. I have also included a screenshot of the dataframe that is imported.

              Thanks for all your help!

              class Strat(bt.Strategy):
                  def log(self, txt, dt=None):
                      ''' Logging function for this strategy'''
                      dt = self.datas[0].datetime.date(0)
                      dt_time = self.datas[0].datetime.time(0)
                      dt_weekday = datetime.datetime.weekday(dt)
              
              
                      print('%s, %s' % (dt.isoformat(), txt))
              
              
                  def __init__(self):
                      # Keep a reference to the "close" line in the data[0] dataseries
                      self.dataclose = self.datas[0].close
                      self.dataopen = self.datas[0].open
                      self.dt = self.datas[0].datetime.date(0)
                      self.dt_time = self.datas[0].datetime.time(0)
                      self.dt_weekday = datetime.datetime.weekday(self.dt)
              
              
              
              
              
                  def notify_order(self, order):
                      if order.status in [order.Submitted, order.Accepted]:
                          # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                          return
              
                      # Check if an order has been completed
                      # Attention: broker could reject order if not enougth cash
                      if order.status in [order.Completed]:
                          if order.isbuy():
                              self.log(
                                  'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f, Datetime: %s' %
                                  (order.executed.price,
                                   order.executed.value,
                                   order.executed.comm,
                                  bt.num2date(order.executed.dt)))
              
                              self.buyprice = order.executed.price
                              self.buycomm = order.executed.comm
                          else:  # Sell
                              self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f, Datetime: %s' %
                                       (order.executed.price,
                                        order.executed.value,
                                        order.executed.comm,
                                        bt.num2date(order.executed.dt)))
              
                          self.bar_executed = len(self)
              
                      elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                          self.log('Order Canceled/Margin/Rejected')
              
                      self.order = None
              
                  def notify_trade(self, trade):
                      if not trade.isclosed:
                          return
                      self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                               (trade.pnl, trade.pnlcomm))
              #####CHANGED IN V4
                  def next(self):
                      dt = self.datas[0].datetime.date(0)
                      wkdy = datetime.datetime.weekday(dt)
                      tme = self.datas[0].datetime.time(0)
              
              
                      if self.position:
                          if tme == datetime.time(12,00,0,0):
                              self.close()
              
                      elif not self.position:
                          if wkdy == 2:
                              if tme == datetime.time(9,30,0,0):
                                  if (((self.dataclose[0] / self.dataclose[-5])-1)*100) > 0:
                                      self.buy(size=1)
              
              if __name__ == '__main__':
                  #Start the brain
                  cerebro = bt.Cerebro()
                  # Load Strat
                  cerebro.addstrategy(Strat)
                  
              
                  #Start cash level
                  cerebro.broker.setcash(10000.0)
              
                  #Set multiplier and commish level
                  cerebro.broker.setcommission(commission=0.79, margin=3000.0, mult=1000.0)
              
                  #Get dataframe
                  df = pd.DataFrame()
                  df = bck.df()
              
              
                  #Add Dataframe from other module
                  data = bt.feeds.PandasData(dataname=df)
              
                  #Load data to brain
                  cerebro.adddata(data)
              
              
              
                  print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
              
              
                  results = cerebro.run()
              
              
              
              
              
              
                  print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
              
              
              
              
                  cerebro.plot(style='bar')
              

              0_1505822746990_dataframe.png

              B 1 Reply Last reply Reply Quote 0
              • B
                backtrader administrators @Osofuego last edited by backtrader

                @Osofuego said in Getting executed twice on closing orders:

                #Add Dataframe from other module
                data = bt.feeds.PandasData(dataname=df)
                

                Your data is clearly 1-minute based, but you are not telling that to the platform. You are letting the defaults kick-in, i.e.: 1-day.

                Hence the multiple execution which happens only when the day changes, because the timeframe is daily based. Your self.position check happens more than once during the day.

                See for example

                • Community - FAQ
                • Community -Intraday time issue/Orders waiting until T+1 (which was due to typo, but it's exactly the same)
                1 Reply Last reply Reply Quote 0
                • O
                  Osofuego last edited by Osofuego

                  Re: Getting executed twice on closing orders

                  Ah, I am an idiot. Thanks for your help I had a datafeed issue. Thx!
                  Working code below.

                  if __name__ == '__main__':
                      #Start the brain
                      cerebro = bt.Cerebro()
                      # Load Strat
                      cerebro.addstrategy(Strat)
                  
                  
                      #Start cash level
                      cerebro.broker.setcash(10000.0)
                  
                      #Set multiplier and commish level
                      cerebro.broker.setcommission(commission=0.79, margin=3000.0, mult=1000.0)
                  
                      #Get dataframe
                      df = pd.DataFrame()
                      df = bck.df()
                  
                  
                      #Add Dataframe from other module
                      data = bt.feeds.PandasData(dataname=df,timeframe=bt.TimeFrame.Minutes,compression=1)
                  
                  
                  
                  
                     #Load data to brain
                      cerebro.adddata(data)
                  
                  
                  
                      print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
                  
                  
                      results = cerebro.run()
                  
                    
                      print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
                  
                  

                  0_1505839717527_Backtest_Close results.png

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