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/

    My Orders dont get Closed (wrong implementation of SL/TP?)

    General Code/Help
    4
    17
    1652
    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.
    • Bayne
      Bayne last edited by Bayne

      no stop losses / take profits hit during backtesting, please help what am i doing wrong in this case? (usage for backtesting purposes only,therefore directly executing TP /SL and Market Order at the "same" time)

      class TestStrategy(bt.Strategy):
          params = (("PChan1", Positive_Chan1),("PChan2", Positive_Chan2),("PChan3", Positive_Chan3),("PChan4", Positive_Chan4),
                    ("NChan1", Negative_Chan1),("NChan2", Negative_Chan2),("NChan3", Negative_Chan3),("NChan4", Negative_Chan4),('printlog', True),)
      
          def log(self, txt, dt=None, doprint=True):  #logs
              if self.params.printlog or doprint:
                  dt = dt or f"{self.datas[0].datetime.date(0)} {self.datas[0].datetime.time(0)}"#self.datas[0].datetime.date(0)
                  print('%s, %s' % (dt, txt))
      
          def __init__(self): 
              self.dataclose = self.datas[0].close
              self.order = None
              self.takeprofit= None
              self.stoploss  = None
              self.TP_order =None
              self.SL_order =None
              
              self.unexecuted_Order=False
              self.buyprice = None
              self.buycomm = None
              self.TradeID = 0
              self.sellprice = None
              self.sellcomm = None
              self.long_stop1 = None
              self.long_stop2 = None 
              self.long_stop3 = None
              self.long_stop4 = None
              self.short_stop1 = None
              self.short_stop2 = None
              self.short_stop3 = None 
              self.short_stop4 = None 
              self.long_target1 = None
              self.long_target2 = None  
              self.long_target3 = None  
              self.long_target4 = None 
              self.short_target1 = None 
              self.short_target2 = None
              self.short_target3 = None 
              self.short_target4 = None
              
          
          def notify_order(self, order):
              #self.log(f"{self.datas[0].datetime.date(0)} {self.datas[0].datetime.time(0)}")#self.datas[0]
              if order.status in [order.Submitted, order.Accepted]:
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  '''if order.isbuy() and order.exectype==bt.Order.Market:'''
                      
                      
                  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.exectype==bt.Order.Market: 
                      if order.isbuy():
                      
                          
                          self.log('BUY EXECUTED, Price_%.5f ,ID_%.0f, ' % (order.executed.price,self.TradeID))
                          self.buyprice = order.executed.price
                          self.buycomm = order.executed.comm
                          if  (order.executed.dt - order.created.dt) >0.5: 
                              self.log("DELAY %s  %s" % (order.created.dt,order.executed.dt))
                      elif order.issell():
                                          
                          self.log('SELL EXECUTED, Price_%.5f ,ID_%.0f, ' % (order.executed.price,self.TradeID))
                          self.buyprice = order.executed.price
                          self.buycomm = order.executed.comm
                          if  (order.executed.dt - order.created.dt) >0.5: 
                              self.log("DELAY %s  %s" % (order.created.dt,order.executed.dt))
                  self.bar_executed = len(self)
      
                  
              elif order.status in [ order.Margin]:
                  self.log('Order Margin')
              elif order.status in [order.Rejected]:
                  self.log('Order Rejected')
      
      
          def notify_trade(self, trade):
              
              if not trade.isclosed:
                  return
              self.log('Position (ID %.0f) Closed , GROSS %.2f, NET %.2f' %(trade.tradeid, trade.pnl, trade.pnlcomm))
              self.log("OHLC = %.5f, %.5f, %.5f, %.5f, "% (self.data.open[0],self.data.high[0],self.data.low[0],self.data.close[0],))
          
          def next(self):
              datestring = f"{self.datas[0].datetime.date(0)} {self.datas[0].datetime.time(0)}"
              #prediction = 0
              #prediction = pred_y[X_Dates.index(datestring)]
              TrueTarget = 0
              self.log(X_Dates.index(datestring))
              TrueTarget = Y_Data[X_Dates.index(datestring)]
              self.TrueTarget = TrueTarget
              
              self.long_stop1 = self.data.close[0] - self.params.NChan1 
              self.short_stop1 = self.data.close[0] + self.params.PChan1 
              self.long_target4 = self.data.close[0] + self.params.PChan4
              self.short_target4 = self.data.close[0] - self.params.NChan4 
              
              if TrueTarget != 4 or 8:
                  return
      
              self.log(f"prediction = {TrueTarget}")
                  
              if TrueTarget == 4:# and self.unexecuted_Order==False:
                  self.takeprofit = self.long_target4
                  self.stoploss   = self.dataclose[0]-0.00050
                  self.log("_______")
                  self.log("OHLC = %.5f, %.5f, %.5f, %.5f, "% (self.data.open[0],self.data.high[0],self.data.low[0],self.data.close[0],))
                  self.log('BUY CREATE, %.5f, ID %.0f,' % (self.dataclose[0],self.TradeID ))     self.log("_______")
                  self.order = self.buy(exectype=bt.Order.Market, tradeid=self.TradeID)
                  self.TP_order = self.sell(tradeid = self.TradeID, exectype=bt.Order.Limit,price=self.takeprofit,oco=self.order)
                  self.SL_order = self.sell(tradeid = self.TradeID, exectype=bt.Order.Stop, price=self.stoploss,oco=self.order)
                  self.log("TARGET =,%.5f (ID %.0f)" %(self.takeprofit, self.TradeID))
                  self.log("STOP =,%.5f (ID %.0f)" %(self.stoploss, self.TradeID))
                  self.TradeID +=1
              elif TrueTarget == 8:
                  self.takeprofit = self.long_target4
                  self.stoploss   = self.dataclose[0]+0.00050
                  self.log("_______")
                  self.log("OHLC = %.5f, %.5f, %.5f, %.5f, "% (self.data.open[0],self.data.high[0],self.data.low[0],self.data.close[0],))
                  self.log('Sell CREATE, %.5f, ID %.0f,' % (self.dataclose[0],self.TradeID ))
                  self.log("_______")
                  
                  self.order = self.sell(exectype=bt.Order.Market, tradeid=self.TradeID)
                  
                  self.TP_order = self.buy(tradeid = self.TradeID, exectype=bt.Order.Limit,price=self.takeprofit,oco=self.order)
                  self.SL_order = self.buy(tradeid = self.TradeID, exectype=bt.Order.Stop, price=self.stoploss,oco=self.order)
                  self.log("TARGET =,%.5f (ID %.0f)" %(self.takeprofit, self.TradeID))
                  self.log("STOP =,%.5f (ID %.0f)" %(self.stoploss, self.TradeID))
                  self.TradeID +=1
      
          def stop(self): # am ende
              self.log('Ending Value %.3f' %( self.broker.getvalue()), doprint=True)
      
      
      print("start")
      start_time = time.time()
           
      if __name__ == '__main__':
          cerebro = bt.Cerebro()    # Create a cerebro entity
          data    = btfeed.GenericCSVData(dataname=Backtraderfilename,
                                       fromdate=datetime.datetime(from_year,from_month,from_day,from_hour,from_minute),#(1999,1,13, 10),
                                       todate=datetime.datetime(to_year,to_month,to_day,to_hour,to_minute),#2019,5,1, 20),#(2019,5,1, 20),
                                       nullvalue=0.0,dtformat=('%Y.%m.%d %H:%M:%S'),
                                       timeframe = bt.TimeFrame.Minutes, compression = 60,
                                       datetime=0,high=1,low=2,open=3,close=4,volume=5,openinterest=-1)
          
          # Add the Data Feed to Cerebro
          cerebro.adddata(data)
          
          # Add a strategy
          cerebro.addstrategy(TestStrategy)
      
          # Set our desired cash start
          cerebro.broker.setcash(10000000.0)
          #slippage
          cerebro.broker = bt.brokers.BackBroker(slip_perc=0)  # 0.5%
      
          # Add a FixedSize sizer according to the stake     #was ist ein stake? eine Unit-Y 1000 = 0.01 Lot
          cerebro.addsizer(bt.sizers.FixedSize, stake=1000)
      
          # Set the commission
          cerebro.broker.setcommission(commission=0)
          
          # Print out the starting conditions
          print('Starting Portfolio Value: %.3f' % cerebro.broker.getvalue())
      
          # Run over everything
          cerebro.run()
          cerebro.plot(style='bar')
      
          # Print out the final result
          print('Final Portfolio Value: %.3f' % cerebro.broker.getvalue())
          
          execution_time = time.time() - start_time
          print("--- %s seconds ---" % (execution_time))   
      
      S B 2 Replies Last reply Reply Quote 0
      • S
        scottz1 @Bayne last edited by

        @Bayne I'm not sure you want the sl and tp order to be oco with the market order. Make the tp order oco on the sl order.
        Also, once you complete that test, you'll want revise next() to check if there is a position before issuing new orders.
        Also check if any of your variables can be eliminated in favor of using the fields that populated in the orders. Hope this helps.

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

                      self.order = self.buy(exectype=bt.Order.Market, tradeid=self.TradeID)
                      self.TP_order = self.sell(tradeid = self.TradeID, exectype=bt.Order.Limit,price=self.takeprofit,oco=self.order)
                      self.SL_order = self.sell(tradeid = self.TradeID, exectype=bt.Order.Stop, price=self.stoploss,oco=self.order)
          

          I don't know what your goal is there but those two cannot be OCO of another order, because they will be cancelled when the first order is executed. Hence no hits, because they no longer exist as soon as the other is executed. The manual stop-loss/take-profit can only be set once your market order is executed, and one of them has to be oco of the other.

          My recommendation is that you take MANY steps back, stop thinking about your Deep Learning Space 9 super-duper model and concentrate on the basics of being able to send orders to the market as wished.

          Create a simple script which sends order to the market using a moving average cross over. Once you understand how orders work you can add as many Artificial Intelligence as you wish. But knowing how trading works is a pre-requisite you cannot forego.

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

            Sorry my bad, i thought oco would mean, that if the main order is closed, that the orders with oco would get closed. (or am i understanding it right?)

            So the right implementation would be making Takeprofit oco with the main and the sl order + making the Stoploss oco with the main and the Takeprofit order, right?
            but how is that possible when the second closing order isnt even created?

            What i want is just a Market order with a TakeProfit and a Stoploss. Bracket orders dont work for my purpose because they arent executed as market orders.

            S A 2 Replies Last reply Reply Quote 0
            • S
              scottz1 @Bayne last edited by

              @Bayne Nope, just submit the market order in next() (only if there is no current position). Then when it gets filled (only in notify_order), submit the tp order. Then on the next line of code, submit the sl order with the tp order as the oco. That will bind the sl and tp as a bracket order.

              Note, it's very important to submit the bracket order in notify_order because the original market order could be partial filled, so you need to use the proper size. And the second reason is that the market order might be rejected due to lack of margin. If that happened, but the sl order had sufficient margin because it's at a different price, then you're strategy would have no position and a pending order to enter an opposite position.

              1 Reply Last reply Reply Quote 0
              • S
                scottz1 last edited by

                If you decide to close the original order for some reason other than the sl or tp firing automatically, then you would also want to cancel the sl or tp. Because they are oco, you only have to cancel either one of them.

                Bayne 1 Reply Last reply Reply Quote 0
                • Bayne
                  Bayne last edited by

                  ahhh i think i get it.

                  I only need to make one order oco of the other and they both follow the concept of oco (thats how i understand your explanation)

                  1 Reply Last reply Reply Quote 0
                  • Bayne
                    Bayne @scottz1 last edited by Bayne

                    @scottz1
                    is this right? ( I mean do they work as closing orders for the main order and both by the oco concept now?)

                    def __init__(self):
                        self.Stoploss = None
                        self.Takeprofit = None
                    
                    def notify_order()
                        takeprofit_price = ...
                        stoploss_price = ....
                        if trade.isbuy():
                              self.Takeprofit = self.sell(tradeid = TradeID, exectype=bt.Order.Limit, price=takeprofit_price)
                              self.Stoploss = self.sell(tradeid = TradeID, exectype=bt.Order.Stop, price=stoploss_price,    oco =self.Takeprofit)
                    
                    def next():
                          ...
                         
                         if signal:
                              self.order=self.buy(tradeid=TradeID)
                          ...
                    
                    1 Reply Last reply Reply Quote 0
                    • S
                      scottz1 last edited by

                      Looks ok basically. However,

                      1. remember to add logic for partial fills so the tp/sl orders will have the correct size.
                      2. remember to check existing position so as not to overwrite self.order and end up doubling your position.
                      Bayne B 2 Replies Last reply Reply Quote 0
                      • Bayne
                        Bayne @scottz1 last edited by Bayne

                        @scottz1
                        1)is there another solution for not overwriting self.order ?(because i open a new main order at nearly every bar)

                        2)i think the tp and sl orders again arent executet at the same bar as the main order ( if i get a breakout at the execution bar and there are no TPs/SLs i wont get this win in backtester

                        (i just need to use backtrader for simulation not for live trading)

                        1 Reply Last reply Reply Quote 0
                        • S
                          scottz1 last edited by

                          I can't answer your first question without seeing code of what you're trying to do. It sounds strange to submit an order on every bar, but nothing prevents that. In that case, perhaps you need to keep a list of active orders.

                          For 2nd question, please understand distinction between submit and execute. If you submit the market order on bar #1, it can notify as filled on bar #2.
                          That means you submit the sl/tp on bar #2, and the earliest one of them would be filled is bar #3.

                          Bayne 1 Reply Last reply Reply Quote 0
                          • A
                            ab_trader @Bayne last edited by

                            @Bayne said in My Orders dont get Closed (wrong implementation of SL/TP?):

                            What i want is just a Market order with a TakeProfit and a Stoploss. Bracket orders dont work for my purpose because they arent executed as market orders.

                            I think you can change bracket order to Market changing exectype parameter when you call bracket order method.

                            • If my answer helped, hit reputation up arrow at lower right corner of the post.
                            • Python Debugging With Pdb
                            • New to python and bt - check this out
                            1 Reply Last reply Reply Quote 0
                            • Bayne
                              Bayne @scottz1 last edited by Bayne

                              @scottz1

                              nononono i want direct execution of all 3 together.

                              a shot summary of what i am planning.

                              I got a list of targets for every bar (numbers 0 to 24 ), which i ll use for machine learning purposes. (i am going to train a ML Model on it to give mostly accurate predictions on every bar)
                              Every numver is an identifier for a specific situation ( e.g. "4" means a buy order with a take profit of 700points and a stoploss of 50 points is comming up)

                              For checking if i implementet backtrader as a simulator correct, i need to check if i get only 100% winning trades in my backtrader implementation. i didnt, because of the delay.
                              I expected to be able to create a buy position together with a TP and SL and the Opening Price of the next bar without any delay.
                              And this is what i want exactly

                              1 Reply Last reply Reply Quote 0
                              • Bayne
                                Bayne last edited by Bayne

                                in A Nutshell:

                                Every bar i want to create a different order (or no order depending on the target) each containing its own unique stoploss and takeprofit, and all of the beeing executed on the Openprice of the next bar (or the closeprice of the signalbar would be even better, thought that doesnt seem possible)

                                what do i have todo for that?

                                1 Reply Last reply Reply Quote 0
                                • S
                                  scottz1 last edited by

                                  Again, please distinguish between submit vs. execute. It doesn't make sense to say "all of them executed at the next open" because you cannot control when the market will hit the price point in the sl/tp.
                                  You can submit them all together, but trying to fill at the close price of the current bar is an example of look ahead bias. To avoid intrabar fallacies you would need data at a lower timeframe.

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

                                    @scottz1 said in My Orders dont get Closed (wrong implementation of SL/TP?):

                                    uish between submit vs. execute. It doesn't make sense to say "all of them executed at the next open" because you cannot control when the market will hit the price point in the sl/tp.
                                    You can submit them all together, but trying to fill at the close price of the current bar is an example of look ahead bias.

                                    i just want to submit them all together/ haver them ready to do what what they should be doing (main order should be executed, and tp and sl should be ready to be hit)
                                    ... and that for multiple orders

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

                                      @scottz1 said in My Orders dont get Closed (wrong implementation of SL/TP?):

                                      Looks ok basically. However,

                                      1. remember to add logic for partial fills so the tp/sl orders will have the correct size.
                                      2. remember to check existing position so as not to overwrite self.order and end up doubling your position.

                                      https://www.backtrader.com/docu/order-creation-execution/oco/oco/

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