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?)



  • 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))   
    


  • @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.


  • administrators

                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.



  • 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.



  • @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.



  • 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.



  • 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)



  • @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)
          ...
    


  • 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.


  • @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)



  • 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 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.



  • @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



  • 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?



  • 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.



  • @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


  • administrators

    @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/


Log in to reply
 

});