For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Cancel buy_bracket order after it's closed



  • I'm trying to implement a stop loss in my strategy by using buy_bracket, but I'm getting multiple closes, as you can see on the log. What I think is happening is that the stop order issued by the buy_bracket is not being canceled after the buy_bracket is closed. This is the code:

    import backtrader as bt
    from datetime import datetime
    
    
    class RSI(bt.Strategy):
        params = dict(
            stopLoss=0.2,
            upperband=75,
            lowerband=25,
            period=9
        )
    
        def __init__(self):
            self.rsi = bt.indicators.RelativeStrengthIndex(period=self.p.period, upperband=self.p.upperband, lowerband=self.p.lowerband, safediv=True)
    
        def log(self, txt, dt=None):
            dt = dt or self.data.datetime[0]
            if isinstance(dt, float):
                dt = bt.num2date(dt)
            print('%s, %s' % (dt.isoformat(), txt))
    
        def notify_order(self, order):
            price = round(order.executed.price, 2)
            if order.status in [order.Completed]:
                if order.isbuy():
                    self.log(f'BUY EXECUTED, Price: {price}')
                else:
                    self.log(f'CLOSE EXECUTED, Price: {price}')
    
            self.order = None
    
        def next(self):
            price = round(self.data.close[0], 2)
            if not self.position and self.rsi <= self.p.lowerband:
                self.buy_bracket(limitexec=None, stopprice=(self.data.close * (1 - self.p.stopLoss)), exectype=bt.Order.Market)
                self.log(f'BUY CREATE, price:{price}')
            if self.position and self.rsi >= self.p.upperband:
                self.close()
                self.log(f'CLOSE CREATE, price:{price}')
    
    
    start_cash = 100
    
    cerebro = bt.Cerebro()
    
    cerebro.addstrategy(RSI)
    
    data = bt.feeds.GenericCSVData(
        dataname='NEOUSDT-15m-data.csv',
        fromdate=datetime(2020, 2, 1, 0, 0),
        todate=datetime(2020, 6, 1, 0, 0),
        timeframe=bt.TimeFrame.Minutes,
        compression=15,
        dtformat='%Y-%m-%d %H:%M:%S',
        openinterest=None
    )
    
    cerebro.adddata(data)
    
    cerebro.broker.setcash(start_cash)
    
    cerebro.addsizer(bt.sizers.PercentSizer, percents=90)  # Set the order size
    
    cerebro.addanalyzer(bt.analyzers.DrawDown, _name='Drawdown')
    
    cerebro.broker.setcommission(commission=0.0001, margin=False)
    
    cerebro.run()
    
    portvalue = round(cerebro.broker.getvalue(), 2)
    pnl = round(portvalue - start_cash, 2)
    
    print('Final Portfolio Value: ${}'.format(portvalue))
    print('P/L: ${}'.format(pnl))
    cerebro.plot(style='candlestick')
    
    

    Is there a way to cancel that order or am I doing something wrong?



  • You might wish to consider using stop loss instead of bracket orders, since you aren't using the limit side.



  • @run-out said in Cancel buy_bracket order after it's closed:

    You might wish to consider using stop loss instead of bracket orders, since you aren't using the limit side.

    I've tried to implement it with this:

        def next(self):
                price = round(self.data.close[0], 2)
                stop_price = price * (1 - self.p.stopLoss)
                if not self.position and self.rsi <= self.p.lowerband:
                    buy = self.buy()
                    stop = self.close(price=stop_price)
                    self.log(f'BUY CREATE, price:{price}')
                if self.position and self.rsi >= self.p.upperband:
                    self.close()
                    self.log(f'CLOSE CREATE, price:{price}')
                    if self.stop:
                        self.cancel(stop)
    

    However, it doesn't work. I get an UnboundLocalError.



  • Try implementing the stop/close/cancel order something like this:

            price = round(self.data.close[0], 2)
            stop_price = price * (1 - self.p.stopLoss)
            if not self.position and self.rsi[0] <= self.p.lowerband:
                self.buy_order = self.buy(transmit=False)
                self.stop_order = self.sell(exectype=bt.Order.Stop, price=stop_price,
                          parent=self.buy_order, transmit=True)
                self.log(f'BUY CREATE, price: {price}')
    
            if self.position and self.rsi >= self.p.upperband:
                self.close()
                self.cancel(self.stop_order)
                self.log(f'CLOSE CREATE, price {price}')
    
    
    

    @Eduardo-Menges-Mattje said in Cancel buy_bracket order after it's closed:

    stop_price = price * (1 - self.p.stopLoss)

    A comment on the stop_price. Your parameter is 0.2, which means your stop price is:

    price * (1-.2) 
    # or
    price * (0.8)
    

    This will rarely trigger while the other sell condition is in place. I lowered this to .02 using 15 minute data and there seemed to be a good balance between stops and close orders.



  • OCO orders were developed to treat situations when orders depends on each other. Use of theses type of the orders might help.



  • @run-out said in Cancel buy_bracket order after it's closed:

    Try implementing the stop/close/cancel order something like this:

            price = round(self.data.close[0], 2)
            stop_price = price * (1 - self.p.stopLoss)
            if not self.position and self.rsi[0] <= self.p.lowerband:
                self.buy_order = self.buy(transmit=False)
                self.stop_order = self.sell(exectype=bt.Order.Stop, price=stop_price,
                          parent=self.buy_order, transmit=True)
                self.log(f'BUY CREATE, price: {price}')
    
            if self.position and self.rsi >= self.p.upperband:
                self.close()
                self.cancel(self.stop_order)
                self.log(f'CLOSE CREATE, price {price}')
    
    
    

    Now I have a question. If I use self.buy(), the self.sell() from the stop loss will open a short order or will it simply close the buy order?

    @Eduardo-Menges-Mattje said in Cancel buy_bracket order after it's closed:

    stop_price = price * (1 - self.p.stopLoss)

    A comment on the stop_price. Your parameter is 0.2, which means your stop price is:

    price * (1-.2) 
    # or
    price * (0.8)
    

    This will rarely trigger while the other sell condition is in place. I lowered this to .02 using 15 minute data and there seemed to be a good balance between stops and close orders.

    Yes, this high number I've used only for testing, to see if it's working at all.



  • BUMP....



  • @Eduardo-Menges-Mattje said in Cancel buy_bracket order after it's closed:

    Is there a way to cancel that order or am I doing something wrong?

    OCO orders were developed to treat situations when orders depends on each other. Use of theses type of the orders might help.

    @Eduardo-Menges-Mattje said in Cancel buy_bracket order after it's closed:

    Now I have a question. If I use self.buy(), the self.sell() from the stop loss will open a short order or will it simply close the buy order?

    self.sell just sells shares. If it uses the same size as it was used in the self.buy, than the long position will be closed. If the self.sell size is less, than part of the long position will be still open. If the self.sell size is more, than long position will be closed, and short position will be open.



  • @ab_trader @run-out Thank you for your everything!


Log in to reply
 

});