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 toself.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 thenotify_order(self)
. With this statement you literally doself.cancel(None)
in thenext()
. -
@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
-
@ZHUOER-ZHANG said in Problems with cancelling order:
Do you know why it happened?
https://community.backtrader.com/topic/2784/cannot-import-name-warnings-from-matplotlib-dates
-
@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.
-
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.