Cancel_orders is not working as expected

I have a universe of stocks that are not so liquid, but I am executing trades every 30 mins.
Before I execute each trade, I will make sure I have cancelled all the open orders, using:

open_orders = get_open_orders()
cancel_order(order for order in open_orders)

However, whenever I check the open_orders after the above code is executed, there are still orders that are not cancelled.
Actually I did this:
open_orders = get_open_orders()
N1=len(open_orders)
cancel_order(order for order in open_orders)
open_orders = get_open_orders()
N2=len(open_orders)

Strangely, N1=N2 all the time. It is not supposed to be this way.

*CODE:*
import numpy as np
import pandas as pd

def initialize(context):
#initiate symbols we want to trade.
#should read from master.csv file when available.
#below are only randomly picked stocks from asian ETF markets

context.stocks=symbols('EWT',
'EWY',
'AAXJ',
'VPL',
'EEP',
'EWA',
'GMF',
'EWS',
'IPAC',
'FHK',
#'HAUD',
'DBKO',
'ENZL',
'AXJL',
'FPA')
'''
context.stocks=symbols('APB','APF','CAF','CHN','GCH','GRR','IAE','IF','IFN','IIF','JEQ','JFC','JOF','KEF','KF','SGF','TDF','TTF','TWN')
'''
context.weights=pd.Series([0.33,0.34,0.33])
context.longNum=3
context.shortNum=3
#define the trading time as how many minutes after market open
set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025,price_impact=0.1))
'''
date_rule=date_rules.every_day(),
time_rule=time_rules.market_open(minutes=minute))
'''
def handle_data(context, data):
mins = get_datetime().minute
#print mins
context.yesterdayClosePrices=history(2,'1d','price').iloc[0]
context.currentPrices=history(1,'1m','price').iloc[0]
sortedStocks=sort_returns(context)
nstocks=len(sortedStocks)
if nstocks<(context.longNum+context.shortNum):
longNum=nstocks/2
shortNum=nstocks/2
weight=1.0/longNum
for i in xrange(1,longNum):
weights=pd.Series()
weights.set_value(i,weight)
else:
longNum=context.longNum
shortNum=context.shortNum
weights=context.weights

longStocks=sortedStocks[:longNum]
shortStocks=sortedStocks[-shortNum:]
#Cancel any orders that are still open
open_orders = get_open_orders()
cancel_order(order for order in open_orders)
longCounter=0
shortCounter=0
for stock in context.stocks:
if stock in longStocks:
order_target_percent(stock,weights[longCounter])
longCounter=longCounter+1
elif stock in shortStocks:
order_target_percent(stock,-weights[shortCounter])
shortCounter=shortCounter+1
else:
order_target_percent(stock,0.0)
record(total_position_value=context.account.total_positions_value)
log.info("longs: "+", ".join([long_.symbol for long_ in longStocks]))
log.info("shorts: "  +", ".join([short_.symbol for short_ in shortStocks]))

def sort_returns(context):
#rank stock returns by the ascending order
stockReturns=pd.DataFrame(
context.currentPrices/context.yesterdayClosePrices-1,
index=context.currentPrices.index)
stockReturns.columns=['Returns']
stockReturns=stockReturns.dropna(how='any')
ranks=(stockReturns.sort(['Returns'])).index
#ranks=context.stocks
return ranks

6 responses

Like the order* functions, cancel_order probably just sends aa cancel request to the Quantopian engine and returns, and you will only see a change in your outstanding orders a minute lapass

Another thing is that you are passing a sequence of orders. According to the documentation, you can only oass a single order id or a string. So you should instead do this:

    open_orders = get_open_orders()
for order in open_orders:
cancel_order(order)
log.info("Cancelling order {}".format(order))


André beat me to it, and he's exactly right.

All order commands are asynchronous. When your code executes an order (or cancel order), that information is sent to the brokerage essentially immediately. However, your code is not waiting for that order to be acknowledged - your code continues.

In situations like this you have two options. The safe way is to wait another minute and verify that the orders were closed, then submit new orders. The aggressive way is to fire off the cancels, hope they work, and press on with new orders.

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

With the "aggressive way", I would recommend you make sure you don't order the same assets you have cancelled.

The cancel_order() code above doesn't actually cancel the order, it silently does nothing (a bug in my opinion).

Use this to cancel orders instead, it works:

def cancels(context, data):    # Cancel all open orders
for o_list in get_open_orders().values():   # List of lists of all orders
for order in o_list:                    # Each order in the list
cancel_order(order.id)              # The order id


There's something weird about that, maybe can be improved. This works also and equally odd, it's the use of values() that does that I guess:

def cancels(context, data):    # Cancel all open orders
o_list = get_open_orders().values()   # List of lists of all orders
for order in o_list[0]:               # Each order in the list
cancel_order(order.id)            # The order id


This might be more clear:

def cancels(context, data):  # Cancel all open orders
oo = get_open_orders()             # Dict of security objects with open orders
for sec in oo:                     # Each security object has a list
for order in oo[sec]:          # Each order in the list
cancel_order(order.id)     # The order id


Or:

def cancels(context, data):  # Cancel all open orders
for sec in get_open_orders():
for order in get_open_orders(sec):
cancel_order(order.id)


Those can all be just cancel_order(order), I like the .id for certainty, as it would generate an error if no id present, the erroneous one posted above would have been caught for example.

@garyha - You're right, my code of Aug. 27, 2015 is incorrect. Quantopian help documentation for get_open_orders correctly states that, when called with no argument, it "returns all open orders", which I took to mean "returns a list of all open orders".

Instead, as the documentation clarifies two paragraphs later, it "returns a dictionary keyed by security id", each entry of which "contains a list of orders for each sid". Thus, when used as an iterator, get_open_orders() yields Equity objects representing securities for which there are unfilled orders.

I would recommend your code under "This might be more clear" above, or this, more Pythonic and perhaps slightly faster:

def cancel_open_orders(context, data):  # Cancel all open orders. AP 2016-01-22
for sec, oo_sec in get_open_orders().items():
for order in oo_sec:
log.info("Cancelling order {}: {} {}/{}".format(order.id, sec.symbol, \
order.amount-order.filled, order.amount)) # n shares unfilled / ordered
cancel_order(order)


where oo_sec is a list of open orders for security sec, such as oo[sec] or the result of get_open_orders(sec).

Good to see the pertinent order details in your log line (since order objects can otherwise be really tough to parse with the eye).

My "This might be more clear" surprisingly is a couple hundredths faster than yours on average.

Timing code