Percent range slippage model -- USE order.amount - order.filled

Thanks to Andre P., and although the docs say to use "amount" on order, the actual remaining is order.amount - order.filled.

This works:

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class PercentRangeSlippageModel(slippage.SlippageModel):
'''
Daily slippage model only
'''
def __init__(this, basisPointsDrift, pctParticipation):
this.basisPointsDrift = basisPointsDrift * .0001
this.pctParticipation = pctParticipation * .01

remainingQty = order.amount - order.filled
# Limit the quantity to 25% of the total volume
orderQuantity = int(min(remainingQty, this.pctParticipation * trade_bar.volume))
# Calculate any price impact of the order
priceImpactSlippage =  min(.25, (float(remainingQty) / float(trade_bar.volume))) **2 * .1
# Calculate a rough mid point of the day's trading range
rangeMid = trade_bar.close_price * .35 \
# Calculate a conservative price drift from the day's mid point price
drift = this.basisPointsDrift + (this.basisPointsDrift * priceImpactSlippage)
executionPrice = rangeMid + (rangeMid * drift * order.direction)
direction = "BUY" if order.direction > 0 else "SELL"
print(" {0:<4} {1:>7} @ {2:>7.2f}  midPrice:{3:>7.2f}  close:{4:>7.2f}  barVol:{5:>10}".format(
direction, orderQuantity, executionPrice, rangeMid, close, trade_bar.volume))


3
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
 Returns 1 Month 3 Month 6 Month 12 Month
 Alpha 1 Month 3 Month 6 Month 12 Month
 Beta 1 Month 3 Month 6 Month 12 Month
 Sharpe 1 Month 3 Month 6 Month 12 Month
 Sortino 1 Month 3 Month 6 Month 12 Month
 Volatility 1 Month 3 Month 6 Month 12 Month
 Max Drawdown 1 Month 3 Month 6 Month 12 Month
def initialize(context):
set_slippage(PercentRangeSlippageModel(25, .1))
context.security = symbol('PCLN')
#context.security = symbol('ZAGG')

def handle_data(context, data):
record(Leverage = context.account.leverage)

if (get_open_orders(context.security)):
return
if (get_datetime().day == 17 and get_datetime().month == 6):
order_target_percent(context.security, 0)
else:
order_target_percent(context.security, 1)

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class PercentRangeSlippageModel(slippage.SlippageModel):
'''
Daily slippage model only
'''
def __init__(this, basisPointsDrift, pctParticipation):
this.basisPointsDrift = basisPointsDrift * .0001
this.pctParticipation = pctParticipation * .01

# Limit the quantity to 25% of the total volume
orderQuantity = int(min(order.amount, this.pctParticipation * trade_bar.volume))

# Calculate any price impact of the order
priceImpactSlippage =  min(.25, (float(order.amount) / float(trade_bar.volume))) **2 * .1

# Calculate a rough mid point of the day's trading range
rangeMid = trade_bar.close_price * .35 \

# Calculate a conservative price drift from the day's mid point price
drift = this.basisPointsDrift + (this.basisPointsDrift * priceImpactSlippage)
executionPrice = rangeMid + (rangeMid * drift * order.direction)

direction = "BUY" if order.direction > 0 else "SELL"
print(" {0:<4} {1:>7} @ {2:>7.2f}  midPrice:{3:>7.2f}  close:{4:>7.2f}  barVol:{5:>10}".format(
direction, orderQuantity, executionPrice, rangeMid, close, trade_bar.volume))


There was a runtime error.
2 responses

It is not order.amount that should change after an order is filled in full or part, but order.filled. See "Order object" at https://www.quantopian.com/help.

Perhaps you should replace order.amount with order.amount-order.filled, the number of shares not filled yet, in lines 30 and 33.

Edit: I know this is what an order object looks like from within handle_data. I don't know what process_order gets, or is supposed to get, after an order is partially filled. You could print order at the beginning to find out.

If your slippage model doesn't place a transaction for the full amount of the order, the order stays open with an updated amount value, and will be passed to process_order on the next bar. Orders that have limits that have not been reached will not be passed to process_order. Finally, if your transaction has 0 shares or more shares than the original order amount, an exception will be thrown.

The doc is wrong. Andre is right. One must use the following when processing a large order.

remainingQty = order.amount - order.filled