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/

    Entering and taking profit on the same bar

    General Code/Help
    3
    9
    902
    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.
    • Jens Halsberghe
      Jens Halsberghe last edited by

      for simple MA crossover strategy, when an order is created, if the next bar triggers the entry but simultaneously hits the target, it will only execute the entry and then exit the bar after that on the open. I can't figure it out. I've been trying different order types but I haven't been able to change the behavior. I've experimented with cheat on open but that didn't get me anywhere

      class Order_testing(bt.Strategy):
      
          params = dict(
              pfast=10,  # period for the fast moving average
              pslow=30   # period for the slow moving average
          )
      
          
          def log(self, txt, dt=None):
              ''' Logging function for this strategy'''
              dt = dt or self.datas[0].datetime.datetime(0)
              print('%s, %s' % (dt.strftime("%Y-%m-%d %H:%M"), txt))
      
          def __init__(self):
              
              sma1 = bt.ind.SMA(period=self.p.pfast)  # fast moving average
              sma2 = bt.ind.SMA(period=self.p.pslow)  # slow moving average
              self.crossover = bt.ind.CrossOver(sma1, sma2)  # crossover signal
      
              # To keep track of pending orders and buy price/commission
              self.order = None
              self.buyprice = None
              self.buycomm = None
      
          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 enough cash
              if order.status in [order.Completed]:
                  if order.isbuy():
                      self.log(
                          'BUY EXECUTED, Price: %.5f, Cost: %.f, Comm %.2f' %
                          (order.executed.price,
                           order.executed.value,
                           order.executed.comm))
      
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                  else:  # Sell
                      self.log('SELL EXECUTED, Price: %.5f, Cost: %.f, Comm %.2f' %
                               (order.executed.price,
                                order.executed.value,
                                order.executed.comm))
      
                  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 %.5f, NET %.5f' %
                       (trade.pnl, trade.pnlcomm))
      
          def next(self):
      
              # Check if an order is pending ... if yes, we cannot send a 2nd one
              if self.order:
                  if self.order.status == 2 and len(self) == self.bar_order_submitted + 1:
                      self.broker.cancel(self.order)
                      self.log("order was cancelled")
      
      
              # Check if we are in the market
              if not self.position:
      
                  # Not yet ... we MIGHT BUY if ...
                  if self.crossover > 0:  # if fast crosses slow to the upside
      
                      self.order = self.buy(exectype=bt.Order.StopLimit, price=self.data.high[0], transmit=False)
                      self.StopLoss = self.sell(price=self.data.low[0],exectype=bt.Order.Stop, 
                                              transmit=False, size=self.order.size,parent=self.order)
                      self.target = self.sell(price=(self.data.high[0]-self.data.low[0])*1.1+self.data.high[0], exectype=bt.Order.Limit, 
                                              transmit=True, size=self.order.size,  parent=self.order)
      
                      self.bar_order_submitted = len(self)
                      
      
                      self.log('BUY CREATE, %.5f' % self.order.price)
      
                      self.log('SL: %.5f, T: %.5f' %(self.StopLoss.price,self.target.price))
                                
      
      if __name__ == '__main__':
      
          cerebro = bt.Cerebro()
      
          # Add a strategy
          cerebro.addstrategy(Order_testing)
          
          # Create a Data Feed
          data = bt.feeds.PandasData(dataname=df2020)
          one_minute = cerebro.resampledata(data, timeframe=bt.TimeFrame.Minutes, compression=1)
            
          
          # Print out the starting conditions
          print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
          
          cerebro.run()
          
          # Print out the final result
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
      

      log for reference. it should both execute the buy and sell order at 06:29

      2020-08-12 06:28, BUY CREATE, 1.17185
      2020-08-12 06:28, SL: 1.17171, T: 1.17200
      2020-08-12 06:29, BUY EXECUTED, Price: 1.17185, Cost: 1, Comm 0.00
      2020-08-12 06:30, SELL EXECUTED, Price: 1.17203, Cost: 1, Comm 0.00
      2020-08-12 06:30, Order Canceled/Margin/Rejected
      2020-08-12 06:30, OPERATION PROFIT, GROSS 0.00018, NET 0.00018
      
      1 Reply Last reply Reply Quote 0
      • ?
        A Former User last edited by

        I am not really sure with this. Maybe the quicknotify param could help you with that problem.

        Jens Halsberghe 1 Reply Last reply Reply Quote 0
        • Jens Halsberghe
          Jens Halsberghe @Guest last edited by

          @dasch much appreciate the quick response. I've tried it but it doesn't work. I haven't found any posts on the forum where it was mentioned either unfortunately.

          1 Reply Last reply Reply Quote 0
          • ?
            A Former User last edited by

            could you post the data file to play with that problem a bit?

            1 Reply Last reply Reply Quote 0
            • Jens Halsberghe
              Jens Halsberghe last edited by

              I would but I can't see how to add an attachment? if not possible, I'll add it to dropbox and then send it that way

              1 Reply Last reply Reply Quote 0
              • ?
                A Former User last edited by

                you can send it directly to my email, which is available in my profile

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

                  @Jens-Halsberghe said in Entering and taking profit on the same bar:

                  if the next bar triggers the entry but simultaneously hits the target, it will only execute the entry and then exit the bar after that on the open.

                  This is default behaviour since it is impossible to know for sure what order the triggers for enter and sale happen when using just one bar of data. Perhaps the enter price happens just before the close but the stop price happens near the open. It's problematic. If you wish to have greater granularity you may wish to consider using a smaller time frame, or perhaps replay.

                  RunBacktest.com

                  1 Reply Last reply Reply Quote 1
                  • ?
                    A Former User last edited by

                    @run-out you are right. we went through this yesterday via email. The result was like you explained. The child order gets activated after the parent order gets executed and will be checked in next cycle.

                    One way to manually allow executing on the same bar is to activate the child order by hand.

                    after the order was created:

                    self.target.activate()
                    

                    Which is not that good idea, since then you don't know, if the parent order was executed, too.

                    1 Reply Last reply Reply Quote 2
                    • Jens Halsberghe
                      Jens Halsberghe last edited by

                      I agree and I understand the logic. I can't replay but also, it's useful to use target.activate() and it can be used to do only in certain scenarios where it looks most likely the target would have been hit. for example if the price never even reached the stoploss but got to the entry and then the target, it's perfectly fine to use it. in case of a big outside bar which would hit all three entry, target and stoploss there would be doubt but it's more an exceptional case.

                      thanks again for your help Dasch

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