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

Problems with cancelling order



  • Hi, sorry to bother you guys with such a naive question, but I've read through the cancel strategy in the doc and did not fully understand it.

    It seems that, the order self.cancel(self.order) did not work at all, not any orders have been successfully canceled, and I'm a bit confused.

            if self.data.pre[0] == 2:
                if self.position.size == 0:
                #try to cancel the stop order I have created after I buy/sell
                    self.cancel(self.order)
                    self.log('Buy CREATE, %.2f' % self.dataclose[0])
                    self.order = self.buy(size=10)
                    price = self.dataclose[0]
                    self.order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                elif self.position.size < 0:
                    self.cancel(self.order)
                    self.log('Buy CREATE, %.2f' % self.dataclose[0])
                    self.order = self.buy(size=20)
                    price = self.dataclose[0] 
                    self.order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 20)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
            if self.data.pre[0]== 0 :
                if self.position.size == 0:
                    self.cancel(self.order)
                    self.log('Sell CREATE, %.2f' % self.dataclose[0])
                    self.order = self.sell(size=10)
                    price = self.dataclose[0]
                    self.order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                         
                elif self.position.size>0:
                     self.cancel(self.order)
                     self.log('Sell CREATE, %.2f' % self.dataclose[0])
                     self.order = self.sell(size=20)
                     price = self.dataclose[0]
                     self.order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 20)
                     print(self.position)
                     print('Equity, %2f' % cerebro.broker.getvalue())
    


  • It works, and works as expected. Share more details on what you want to achieve, full strategy script etc and we will try to help.



  • Just for testing purpose, I add a column indicating ‘Buy’(2), ‘Sell’(0) and ‘Do Nothing’(1) in the csv file and feed it into the datafeed.
    When the Buy signal showed up, if our position is 0, we cancel all the unexecuted orders (the stop order in this context) and buy 10 sizes at market price. After which we want to give a stop-loss order, the price of this stop order is to sell at (our executed price – 8), and the size is our position after the buys. (10 in which case)
    If our position is 10, we do nothing.
    If our position is -10, we cancel all the unexecuted orders and buy 20 sizes at market price , then give a stop order at 20 size.

    When the Sell signal showed up, if our position is 0, we cancel all the unexecuted orders and sell 10 sizes at market price. After which we want to give a stop-loss order, the price of the stop-loss order is to buy at (our executed price + 8), and the size is our position after the buys. (10 in which case)
    If our position is -10, we do nothing.
    If our position is 10, we cancel all the unexecuted orders and buy 20 sizes at market price , then give a stop order at 20 size.

    And I’m trying to print out the information of the canceled order (time, type, price, size) as well. For your full information, I give you the full code.

    Thank you again for your help and timely reply! Sorry my reply is a bit late coming.

    from __future__ import (absolute_import, division, print_function,
                            unicode_literals)
    
    import datetime
    import pandas as pd
    import backtrader as bt
    import backtrader.feeds as btfeeds
    from backtrader.feeds import GenericCSVData
    
    
    class dataFeed(btfeeds.GenericCSVData):
    
        # Add a 'pe' line to the inherited ones from the base class
        lines = ('pre',)
    
        # openinterest in GenericCSVData has index 7 ... add 1
        # add the parameter to the parameters inherited from the base class
    
        params = (
            ('dtformat', '%Y/%m/%d %H:%M'),
            ('datetime', 0),
            ('open', 1),
            ('high', 2),
            ('low', 3),
            ('close', 4),
            ('pre', 5),
            ('volume',-1),
            ('openinterest',-1)
            )
    
    
    # Create a Stratey
    class TestStrategy(bt.Strategy):
    
        def log(self, txt, dt=None):
            ''' Logging function fot this strategy'''
            dt = dt or self.datas[0].datetime.date(0)
            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
            # To keep track of pending orders
            self.order = None
     
        def notify_order(self, order):
                print('{}: Order ref: {} / Type {} / Status {}'.format(
                    self.data.datetime.date(0),
                    order.ref, 'Buy' * order.isbuy() or 'Sell',
                    order.getstatusname()))
                
                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. ,size:%.2f"
                            % (order.executed.price, order.executed.size) 
                        )
                    elif order.issell():
                        self.log(
                            "Sell EXECUTED, Price: %.2f, size:%.2f"
                            % (order.executed.price, order.executed.size)
                        )
                elif order.status in [order.Canceled]:
                    self.log('Order Canceled')
    
     
            # Write down: no pending order
                self.order = None
     
        def next(self):
            # Check if an order is pending ... if yes, we cannot send a 2nd one
            if self.order:
                return
            # Simply log the closing price of the series from the reference
            self.log('Close, %.2f' % self.dataclose[0])
    
            order = None
    
            if self.data.pre[0] == 2:
                if self.position.size == 0:
                #try to cancel the stop order I have created here
                    self.cancel(self.order)
                    self.log('Buy CREATE, %.2f' % self.dataclose[0])
                    self.order = self.buy(size=10)
                    price = self.dataclose[0]
                    self.order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                elif self.position.size < 0:
                    self.cancel(self.order)
                    self.log('Buy CREATE, %.2f' % self.dataclose[0])
                    self.order = self.buy(size=20)
                    price = self.dataclose[0] 
                    self.order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 20)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
            if self.data.pre[0]== 0 :
                if self.position.size == 0:
                    self.cancel(self.order)
                    self.log('Sell CREATE, %.2f' % self.dataclose[0])
                    self.order = self.sell(size=10)
                    price = self.dataclose[0]
                    self.order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                         
                elif self.position.size>0:
                     self.cancel(self.order)
                     self.log('Sell CREATE, %.2f' % self.dataclose[0])
                     self.order = self.sell(size=20)
                     price = self.dataclose[0]
                     self.order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 20)
                     print(self.position)
                     print('Equity, %2f' % cerebro.broker.getvalue())
                                           
    if __name__ == '__main__' :
        cerebro = bt.Cerebro()
        data = dataFeed(dataname='D:/TEST_SL_ODA.csv', timeframe=bt.TimeFrame.Minutes)
            
             
    
            # Add the Data Feed to Cerebro
        cerebro.adddata(data)
    
        cerebro.addstrategy(TestStrategy)
    
        # Set our desired cash start
        cerebro.broker.setcash(500000.0)
    
    
        # Set the commission
        cerebro.broker.setcommission(commission=0.0)
        
        print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    
        cerebro.run()
    
        cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name = 'SharpeRatio')
        cerebro.addanalyzer(bt.analyzers.DrawDown, _name='DW')
        results = cerebro.run()
        strat = results[0]
        print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
        print('SR:', strat.analyzers.SharpeRatio.get_analysis())
        print('DW:', strat.analyzers.DW.get_analysis())
    
    
        cerebro.plot()
    
    
    

    Really Appreciate your help! :)



  • @ZHUOER-ZHANG said in Problems with cancelling order:

    def notify_order(self, order):

    In order to print out details of your cancelled orders, you do it in def notify_order,

    @ZHUOER-ZHANG said in Problems with cancelling order:

    elif order.status in [order.Canceled]:
    self.log('Order Canceled')

    Just add in more details. like date time, order reference etc.

    @ZHUOER-ZHANG said in Problems with cancelling order:

         self.order = self.buy(size=10)
         price = self.dataclose[0]
         self.order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 10)
    

    In next you are using self.order improperly. self.order is just a variable, and you keep reassigning it. So first you assign it to

    self.order = self.buy(size=10)
    

    for which your self.order will now be referencing a orderbuy object, and then you immediately reassign it as

    self.order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 10)
    

    and now your self.order references a sell object. You will need to use a list or dictionary to keep track of multiple orders that you plan to cancel all at once.
    Example can be found in this blog and in the docs.



  • Also re-write (maybe even remove) self.order = None from the notify_order(self). With this statement you literally do self.cancel(None) in the next().



  • @run-out First of all Thank you for your detailed explanation! Very clear and informative.

    For the order management part, is it because of my constant re-assigning of self.order causing the whole algorithm to behave strangely? ( and my ultimate failure to cancel an order)
    Because it seems to me that the first order is an market order and hence cannot be Cancelled
    Still the Stop Order can be cancelled and the mean goal of this self.cancel(self.order) is to cancel the Stop Order. I will follow your advice and use a list to improve my code!



  • @ab_trader Thank you! Corrected that and Hit the reputation :)
    Sadly I also met a common problem cannot import name 'warnings' from 'matplotlib.dates'
    The algorithm seems to run well on the Jupyter but not on other platforms.
    Do you know why it happened?



  • Also, what is the difference between self.cancel(self.order) and self.broker.cancel(self.order)?



  • @ZHUOER-ZHANG said in Problems with cancelling order:

    Still the Stop Order can be cancelled and the mean goal of this self.cancel(self.order) is to cancel the Stop Order.

    It can't be cancelled because of the following:

    • you issue stop order in the next as `self.order = self.sell(...)
    • than in notification you set self.order = None
    • therefore self.cancel(self.order) doesn't cancel anything




  • @ab_trader I changed the code the variable of the stop order, and it seems that I still can't cancel anything... Would you mind looking at my (messed) code and further point out some mistakes?

    Thank you!

        def __init__(self):
            # Keep a reference to the "close" line in the data[0] dataseries
            self.dataclose = self.datas[0].close
            # To keep track of pending orders
            self.order = None
            self.stop_order = None
     
        def notify_order(self, order):
                print('{}: Order ref: {} / Type {} / Status {}'.format(
                    self.data.datetime.date(0),
                    order.ref, 'Buy' * order.isbuy() or 'Sell',
                    order.getstatusname()))
                
                if order.status in [order.Submitted, order.Accepted]:
                # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                    return
    
    
    
                if order.status in [order.Completed]:
                    if order.isbuy():
                        self.log(
                            "Buy EXECUTED, Price: %.2f. ,size:%.2f"
                            % (order.executed.price, order.executed.size) 
                        )
                    elif order.issell():
                        self.log(
                            "Sell EXECUTED, Price: %.2f, size:%.2f"
                            % (order.executed.price, order.executed.size)
                        )
                elif order.status in [order.Canceled]:
                    self.log('Order Canceled')
    
     
        def next(self):
            # Check if an order is pending ... if yes, we cannot send a 2nd one
            if self.order:
                return
            # Simply log the closing price of the series from the reference
            self.log('Close, %.2f' % self.dataclose[0])
    
            if self.data.pre[0] == 2:
                if self.position.size == 0:
                #try to cancel the stop order I have created here
                    self.cancel(self.stop_order)
                    self.order = self.buy(size=10)
                    self.log('Buy Create! , %.2f' % self.dataclose[0])
                    price = self.dataclose[0]
                    self.stop_order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                elif self.position.size < 0:
                    self.cancel(self.stop_order)
                    self.order = self.buy(size=20)
                    self.log('Buy Create! , %.2f' % self.dataclose[0])
                    price = self.dataclose[0] 
                    self.stop_order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 20)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                    
            if self.data.pre[0] == 0 :
                if self.position.size == 0:
                    self.cancel(self.stop_order)
                    self.order = self.sell(size=10)
                    self.log('Sell Create, %.2f' % self.dataclose[0])
                    price = self.dataclose[0]
                    self.stop_order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())    
                elif self.position.size>0:
                     self.cancel(self.stop_order)
                     self.log('Sell Create!, %.2f' % self.dataclose[0])
                     self.order = self.sell(size=20)
                     price = self.dataclose[0]
                     self.stop_order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 20)
                     print(self.position)
                     print('Equity, %2f' % cerebro.broker.getvalue())
                                           
    


  • Post some outputs. It seems to me that you have only one buy order issued and executed and nothing else, but want to take a look on the script outputs.



  • 2020-07-24 (4).png 2020-07-24 (3).png

    Here are some posts.
    I keep on trying to improve the code and somehow successfully canceled... ( I delete the logic if self.order return and I suspect that is the reason(?)



  • Anyway here is the improved code.
    I received some suggestions about moving the canceling order into the notify_order section.

        def next(self):
            self.log('Close, %.2f' % self.dataclose[0])
    
            if self.data.pre[0] == 2:
            # When the strategy told us to buy
                if self.position.size == 0:
                #try to cancel the stop order I have created here
                    self.cancel(self.stop_order)
                    self.order = self.buy(size=10)
                    self.log('Buy Create! , %.2f' % self.dataclose[0])
                    price = self.data.open[1]
                    self.stop_order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                elif self.position.size < 0:
                    self.cancel(self.stop_order)
                    self.order = self.buy(size=20)
                    self.log('Buy Create! , %.2f' % self.dataclose[0])
                    price = self.data.open[1] 
                    self.stop_order = self.sell(exectype =bt.Order.Stop, price = price - 8,size = 20)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())
                    
            if self.data.pre[0] == 0 :
           # when the strategy told us to sell
                if self.position.size == 0:
                    self.cancel(self.stop_order)
                    self.order = self.sell(size=10)
                    self.log('Sell Create, %.2f' % self.dataclose[0])
                    price = self.data.open[1]
                    self.stop_order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 10)
                    print(self.position)
                    print('Equity, %2f' % cerebro.broker.getvalue())    
                elif self.position.size>0:
                     self.cancel(self.stop_order)
                     self.log('Sell Create!, %.2f' % self.dataclose[0])
                     self.order = self.sell(size=20)
                     price = self.data.open[1]
                     self.stop_order = self.buy(exectype =bt.Order.Stop, price = price + 8,size = 20)
                     print(self.position)
                     print('Equity, %2f' % cerebro.broker.getvalue())
    


  • Please, next time post just text between backticks similar to the script and start from the very beginning of the output. Having orders with ref 40 and than 60 brings not a lot of understanding in what is going on. I would recommend to keep only data required to generate couple trades in both directions and debug script on this data.

    Anyway, you are able to cancel orders now, what is the problem?



  • @ab_trader What if I move the cancel order into the notify order part? Can I successfully cancel it?



  • @ZHUOER-ZHANG try it. For bt it doesn't matter, but may be a big deal for your trading algo.


Log in to reply
 

});