An update and maybe clarification and direction when using limit orders. First off, there hasn't been any changes to how limit orders are filled since the original 2014 post. Specifically, the steps that zipline follows are:
- Check if an order is triggered. The data bar's close price is compared to the limit price.
- If the order is triggered the order goes into the execution engine.
- The execution engine applies the slippage model to determine the filled shares and price.
- The order is filled using the slippage-adjusted price.
One issue is the current default slippage model used in step 3. (see https://www.quantopian.com/posts/changes-coming-to-the-default-slippage-model). It's FixedBasisPointsSlippage
(see https://www.quantopian.com/help#ide-slippage). This always 'slips' the buy/sell price by a fixed amount which, in the case of limit orders, may be over/under the limit price. This default slippage model is meant to be used in conjunction with the contest which requires the 'order_optimal_portfolio' method for ordering. It isn't so much a 'bug' as much as the wrong application of this slippage model when using limit orders. If one isn't developing for the contest and doesn't want to use the standard 'order_optimal_portfolio' method for ordering then the default slippage may not be a good choice.
That's the update and clarification part of this post. Now for some direction.
The default FixedBasisPointsSlippage
can be used for limit orders but the results will be negatively skewed (since orders may fill worse than the limit price). A better approximation when using limit orders may be to use VolumeShareSlippage
.
set_slippage(slippage.VolumeShareSlippage(volume_limit=.01, price_impact=0.0)
The key is 'price_impact' = 0.0' (volume_limit' can be whatever seems appropriate). By setting this to zero, the fill price will be the close of the previous bar. Because the order was triggered, this will always be equal or better than the limit price but never worse than the limit price. Note however this is optimistic (since one will often get a better price) but at least the limit price will be respected. Getting a better price actually does happen in live trading when a limit order is placed and it's a 'marketable order'. A marketable limit order is a buy order with a price at or above the lowest offer in the market or a sell order with a price at or below the highest bid in the market. Marketable orders are submitted as a 'market order' by the broker and therefore fill at market which may be better than the limit (more on the bid and ask issues later). So, VolumeShareSlippage
can be used for market orders but it will optimistically skew results
Probably a better slippage choice would be to write a custom slippage method
. Return the fill price to be the limit price. This would be slightly negatively skewed (because some orders would fill better than the limit) but not crazy and most of all not overly optimistic. The added benefit of a custom method comes if one uses a combination of limit orders and market orders. It get's passed the order which can be inspected and, based upon the order type, different slippage could be applied to each order type.
That's the direction. Use the default slippage to get a pessimistic model then switch to VolumeShareSlippage
and get a more optimistic version. More than likely reality may be somewhere in between. To reduce that margin maybe write a custom slippage method to replace the default and reduce the pessimistic side of the model. The actual may be something in between the two.
Now a few added thoughts.
Remember that a backtest isn't reality. It's important to look how sensitive performance is to the slippage model. If an algo swings from bad to good based upon a change in slippage would one really want to risk real money?
@Mikko M hope this helps. If there are some specific anomalies you are seeing with orders and have questions please post them. The devil is always in the details. As @Blue mentioned it's helpful to have some specifics when looking for them.