I am trying to do some options backtesting. I am finding that the MarketOrder fills for the options is very erratic. Most likely it comes down to the low volume trading that occurs on the options. Anyways, something I ususally do is just assume to lose the spread on every trade execution. For example, when selling an option, you always assume you sell on the bid, and buying you always assume that you buy on the ask. At QuantConnect we have bid/ask data so that seems possible, although I can't quite figure out how I would do the code. From the docs we have this simple example:
# Set the fill models in initialize:
self.Securities["IBM"].SetFillModel(PartialFillModel())
# Custom fill model implementation stub
class PartialFillModel(ImmediateFillModel):
def MarketFill(self, asset, order):
# Override order event handler and return partial order fills
pass
So how would I create a default fill model for all options to say that MarketOrders are filled in the way I described above ( selling on bids and buying on asks ) ? The documentation doesn't really explain what we need to return from this function. Would something like this work?
# Custom fill model implementation stub
class MyCustomFillModel(ImmediateFillModel):
def MarketFill(self, asset, order):
if order.isSell:
order.fillPrice = asset.BidPrice
else:
order.fillPrice = asset.AskPrice
return order
I know that attributes of the order object are wrong but I can't find any documentation explaining the order object and which attributes we are supposed to override in the fill model. Please help.
Thanks.
Serge d'Adesky
Hi Tim
Did you ever get an answer to this? I'm finding that the bid ask spread returned in the data is WAAAY wider than reality. This causes some unusual behavior. In my case I ran a strategy that sells ATM calls/put over 1 year on SPY. . That loses about 5.2%. So you would assume that if you went long the same strikes for the same period, it should be profitable give or take a little due to fees and slippage. Nope. it loses about the same percentage. When looking at a few random data points, I found that the bid ask spreads on SPY averaged about 10%, whereas in reality these average around 2 to 3 percent. Obviously this complicates any trading strategy trying to eke out a profit.Â
I thought a work around would be to use the worst price (ask or bid and add 3pct). So I'm curious how you worked this out.Â
Daniel Chen
Hi Serge,
Thank you for your observations. Regarding the abnormally large spread of SPY data, could you give us an example (code and log) to replicate this issue? We will be very thankful.
Besides, it is easy to create Custom Fill Models in QC. They give you control over order fills and return an OrderEvent object which carries information about order partial fills or errors. To implement your own fill model, we recommend you start with the  FillModel class. Here is an example of how I inherit ImmediateFillModel to build my own fill model on a particular stock LII. All we need to do is to implement our idea into the MarketFill() Method in that custom fill model class. For more information, please visit this page.
Thank you for your support to QC! Feel free to discuss with us in the forum.
Anthony FJ Garner
How do you adapt this to the use of the Course / Fine Filter Universe selction model?
Jared Broad
Hey Anthony -- I recommend you use the SecurityInitializer(). You can see an example of this here. It allows you to run some code on new securities added as a result of the universe selection.Â
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 QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect 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. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Anthony FJ Garner
Many thanks Jared. I'll take a look.
Anthony FJ Garner
I don't think Daniel Chen's code is working as he thinks.
As I understand it, the object is to spread fills over a period of time so that each partial fill is executed at a different price. In other words, if I were to use second data (resolution second) I would expect a partial filll at a price based on the close of the first second and then another fill at a different price based off the close of the second second and so on.
As can be seen from the attached test and the log extract below, this does not happen. Partial fills are all executed at the same price - the close of the first second or hour or whatever resolution is used.Â
Note from the below that both fills were executed at the identical time and hence at the identical price.
Not (I assume) what was intended.
2020-01-01 00:00:00 Launching analysis for 06c2de807579222e30829d598983b292 with LEAN Engine v2.4.0.0.7783 2020-01-03 10:00:00 MarketOrder: 204.99999999999997 2020-01-03 10:00:00 CustomFillModel: Time: 01/03/2020 15:00:00 OrderID: 1 EventID: 0 Symbol: LII Status: PartiallyFilled Quantity 0 FillQuantity: 163 FillPrice: 242.82 USD 2020-01-03 10:00:00 CustomFillModel: Time: 01/03/2020 15:00:00 OrderID: 1 EventID: 0 Symbol: LII Status: Filled Quantity 0 FillQuantity: 42 FillPrice: 242.82 USD
Â
Jared Broad
It might be a result of the short term data used in a second level backtest Anthony (the price might not move every second) - I've simplified Daniel's example and added debugging logs to Daniel's post here to show explicitly the partial fills emitted over the 10 hour period (100 shares, filled 10 per partial fill).Â
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 QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect 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. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Li Cheng
Hi Jared, the backtest that you attached in your latest comment in this thread had a bug where the order for SPY was getting filled 2 times for every bar that the algorithm received. I've attached a screenshot in this comment to illustrate what I mean.
Li Cheng
I've created a support thread for the issue, hopefully someone can help solve it
Tim De Lise
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 QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect 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. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!