Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Order state on partial fills, close, open or crossover

Some code to let you know the state of a partially filled order. cls_opn_crs()

Example:

oos = get_open_orders()  
for s in oos:  
    for o in oos[s]:                             # loop thru open orders  
        if cls_opn_crs(context, o) in [1, 3]:    # if opening, not closing  
            if o.filled < o.amount * .10:        # if partial fill and very small  
                cancel_order(o.id)               # cancel remaining  

The idea is that an order so thinly traded on open (at some threshold you determine) can also have a difficult time closing which can be very bad if the price is moving in the wrong direction when the time comes.

About the return from cls_opn_crs():
1: A straightup opening order, from 0 shares, it is a simple increasing number of shares away from zero, or for example an increase of allocation from 100 shares to 300 shares, or -50 shares to -112 shares.
3: Crossover opening portion. For example where a position was 100 shares and an order was entered for -500 shares (targeting -400), and at least 100 (or -100 depending on how you think of it) of the previous position have been filled, now passing 0 and into negative territory. Was long, is now short and increasing the number of short shares (more negative). This is now an order that is opening (greater magnitude in the number of shares).

0: Closing order, reduction in shares toward 0
2: Closing toward zero however merely the closing portion of a crossover order

A change from -50 shares to -35 shares (or 50 to 35) is considered a "closing" order (0) here even though the target is not 0.

def cls_opn_crs(c, o):      # c = context    o = order object  
    # Whether order is closing, opening or crossover (short to long or reverse)  
    amt = c.portfolio.positions[o.sid].amount  
    if (amt - o.filled) * o.amount < 0:   # close or x  
        if abs(o.amount) > abs(amt - o.filled):  
            if abs(amt) - abs(o.filled) < 0:  
                  return 3           # crossed 0 shares and now opening  
            else: return 2           # x crossover  
        else:     return 0           # close  
    else:         return 1           # open  

.

1 response

I use this function quite a bit for example after a certain number of partial fills to cancel an opening order while letting closing orders finish closing whenever they can. Spotted an uncaught crossover order, presumably fixed now with the edit above, would appreciate someone with more horsepower in their head than myself to go over this with a fine-toothed comb and see if you can find flaws or improved efficiency. This backtest could be a useful start for testing.