The price at which an order fills, and the quantity of shares filled, is determined by the slippage model
(see https://www.quantopian.com/docs/user-guide/tools/algo-api#setting-slippage-and-commissions). The current default is FixedBasisPointsSlippage
which models market orders rather well. These are the types of orders placed when using order_optimal_portfolio
and therefore is appropriate for contest algos. If that default doesn't model the order type or pattern one has in a specific algo, other slippage methods, or even a custom method, can be specified.
The VolumeShareSlippage
model handles limit orders a bit better than the default. This will never fill worse than the limit but, if the market price is better, will fill at that better market price. This can happen in real trading but it's not typical. Therefore, this could be considered an 'optimistic' best fill model. Using this provides the best fill scenario. To use this model, put the following code into the initialize
function
set_slippage(slippage.VolumeShareSlippage(volume_limit=.1, price_impact=0.0))
There isn't a built in slippage model to provide what might be considered a 'pessimistic' worst fill model, but one can write a custom slippage model. Here is a custom slippage class that fills market orders at the bars close price but fills at the limit orders at the limit price.
class VolumeShareSlippage_Pessimistic(slippage.SlippageModel):
"""
This is a simple slippage model which assumes no price impact on market orders.
The filled price will equal the bar's close price.
It fills all limit orders at the limit price to give a worst case fill price.
The max volume is 10% of a bar volume.
_________________________
Note this does not account for multiple orders being placed in a minute.
It also doesn't handle stop orders.
"""
# limit the volume to 10% of a minute bar volume / no price impact
volume_limit = 0.1
price_impact = 0.0
def process_order(self, data, order):
volume = data.current(order.asset, "volume")
price = data.current(order.asset, "close")
# The fill amount will be the min of the
# volume available in the bar or the max_volume.
max_volume = self.volume_limit * volume
max_fill_volume = int(min(max_volume, abs(order.open_amount)))
# The fill price will be the limit price for limit orders and the current price for market orders
if order.limit:
limit_reached = ((order.direction > 0 and price > order.limit) or
(order.direction < 0 and price < order.limit)
)
if limit_reached:
fill_price = order.limit
fill_volume = math.copysign(max_fill_volume, order.direction)
else:
fill_price = None
fill_volume = None
else:
# it's a market order
fill_price = price
fill_volume = math.copysign(max_fill_volume, order.direction)
return (fill_price, fill_volume)
All the basic ordering logic, including the built in slippage models, are open source. I'd encourage everyone to take a look at the code to better understand how orders are filled and backtested. Check out the slippage models here. There are also some other posts on this topic you may want to look at:
https://www.quantopian.com/posts/why-is-the-fill-price-greater-than-the-limit-price-1
https://www.quantopian.com/posts/simulation-of-non-marketable-limit-orders
Attached is an algo to test the various slippage models and shows how to implement a custom slippage model.