In order to try to improve options algo backtest performance when using the Options Universe method, as I require the options Greeks for selection, I created a test algo that dynamically adjusts the options universe filter.
I would like to also trade options for multiple underlyings and so this is the first step towards that, as the subscription needs to be managed to keep within the data lines limits.
The following sequence shows an issue that an updated minimised option universe filter is only applied by LEAN after the next monthly options expiration has occurred, instead of being applied immediately from the next Slice event.
Tested the following sequence:
1. Add option universe using underlying symbol
2. Set universe filter to required strike range and expiration
3. Select option from the Slice OptionChain (eg. by Expiration, Delta)
4. Reduce the option universe using SetFilter to the minimum subscribed set
5. Add the selected option to the subscription
6. For next trade:
7. Close the current option position and unsubscribe the selected option
8. Repeat process from step 2
Is this an issue with this test sequence, or is this an issue with LEAN?
Any info or ideas much appreciated.
Test algo added.
Extracts from the log with added comments for clarification:
----------------------
=> option universe SetFilter 'normal' filter is used to filter the required strike range and expiration
2017-06-01 15:45:00 : 6/1/2017 3:45:00 PM: chain.Contracts.Count=7
=> contract is selected
2017-06-01 15:45:00 : 6/1/2017 3:45:00 PM: INFO: Closest to 50 DTE selection found DTE=49.08:15:00 symbol=SPY 170721C00242000
2017-06-01 15:45:00 : 6/1/2017 3:45:00 PM: INFO: Valid Option selection found DTE=49.08:15:00 Symbol=SPY 170721C00242000 Delta=0.58
=> **** SetFilter is called here to minimise the option universe once the contract has been selected BUT why is it not applied by LEAN until after next option expiration?
2017-06-01 15:45:00 : 6/1/2017 3:45:00 PM: MinimiseFilterOptionUniverse
=> selected contract is added to the subscription
2017-06-01 15:46:00 : AddOptionContract:SPY 170721C00242000
=> contract is bought
2017-06-01 15:47:00 : 6/1/2017 3:47:00 PM: Buy: optionContractSymbol=SPY 170721C00242000
=> Q. Why isn't the updated filter being applied by LEAN immediately instead of after next monthly option Expiration day?
2017-06-02 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-05 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-06 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-07 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-08 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-09 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-12 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-13 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-14 15:45:00 : chain.Contracts.Count=7 (no change)
2017-06-15 15:45:00 : chain.Contracts.Count=7 (no change)
=> Option Expiration Day on 2017-06-16
2017-06-16 15:45:00 : chain.Contracts.Count=4
=> **** updated filter is now only applied by LEAN after option expiration day - why?
2017-06-19 15:45:00 : chain.Contracts.Count=1 (filter now applied)
2017-06-20 15:45:00 : chain.Contracts.Count=1 (filter now applied)
2017-06-21 15:45:00 : chain.Contracts.Count=1 (filter now applied)
2017-06-22 15:45:00 : chain.Contracts.Count=1 (filter now applied)
2017-06-23 15:45:00 : chain.Contracts.Count=1 (filter now applied)
.
.
.
=> option roll (sell option, reapply universe filter to be able to select next option to buy)
2017-07-17 09:31:00 : 7/17/2017 9:31:00 AM: OnData: INFO: Sell : rollover as DTE < 5
2017-07-17 09:31:00 : RemoveSecurity:SPY 170721C00242000
2017-07-17 09:32:00 : 7/17/2017 9:32:00 AM: OnData: slice.Count=1
=> reapply universe filter to required strike range and expiration
2017-07-17 09:32:00 : 7/17/2017 9:32:00 AM: AddOptionUniverseForUnderlying: SetFilter
=> **** updated filter is applied correctly immediately to the chain
2017-07-17 09:50:00 : 7/17/2017 9:50:00 AM: OnData: slice.Count=6 (ok)
2017-07-17 15:45:00 : 7/17/2017 3:45:00 PM: chain.Contracts.Count=5 (ok)
=> next option series contract is selected for trade
2017-07-17 15:45:00 : 7/17/2017 3:45:00 PM: INFO: Closest to 50 DTE selection found DTE=31.08:15:00 symbol=SPY 170818C00245000
2017-07-17 15:45:00 : 7/17/2017 3:45:00 PM: INFO: Valid Option selection found DTE=31.08:15:00 Symbol=SPY 170818C00245000 Delta=0.58
=> **** SetFilter is called here to minimise the option universe once the contract has been selected BUT why is it not applied by LEAN until after next option expiration?
2017-07-17 15:45:00 : 7/17/2017 3:45:00 PM: MinimiseFilterOptionUniverse
=> Q. Why isn't the updated filter being applied by LEAN immediately instead of after option Expiration day?
2017-07-18 15:45:00 : chain.Contracts.Count=5 (no change)
2017-07-19 15:45:00 : chain.Contracts.Count=5 (no change)
2017-07-20 15:45:00 : chain.Contracts.Count=5 (no change)
=> Option Expiration Day on 2017-07-21
2017-07-21 15:45:00 : chain.Contracts.Count=5 (no change)
=> **** updated filter is now only applied by LEAN after option expiration day - why?
2017-07-24 15:45:00 : chain.Contracts.Count=1 (filter now applied)
2017-07-25 15:45:00 : chain.Contracts.Count=1 (filter now applied)
----------------------
Thanks,
ES.
Shile Wen
Hi Ernest Shaggleford,
In your algorithm, the filter doesn't change:
_optionUniverse.SetFilter(u => { return u.Expiration(TimeSpan.Zero, TimeSpan.FromDays(50)) .Contracts(c => c.Where(s => s.ID.OptionRight == OptionRight.Call)); });
so, the multiple calls will not change the outcome. I believe that the universe count changes solely because of the expiry range condition.
The algorithm doesn't need to use AddOptionContract and RemoveSecurity to add and remove a contract that has already been added by the Option.ContractFilter. Please note that when we call AddOption, a universe selection is created and it will add/remove the contracts.
Best,
Shile Wen
Ernest Shaggleford
Hi Shile,
I appreciate your response but your understanding is not correct.
The primary purpose of this algo is to try to speed up backtesting when using the option universe method, by minimising the option universe subscription once an option (or set of options) has been selected to trade.
The reason for using the option universe method is to be able to select an option contract using the greeks, such as delta, for example, which is typically how option traders select options to trade. The alternative method of using OptionChainProvider.GetOptionContractList does not support the greeks for contract selection, and so this isn't suitable, even though it's a faster method.
But, by minimising the option universe subscription, once an option has been selected, this will speed up the backtesting.
There's also a bigger picture here that I would like to also trade options on multiple underlyings, and while using the greeks for selection, and so this is the first step towards that, as the subscription needs to be managed to keep within the data lines limits.
(There is another related issue here that I've raised separately that LEAN doesn't use the IV and Greeks from the Live IB feed, which makes it impossible to trade options on multiple underlyings if requiring the Live Greeks and IV for contract selection and to keep within the data lines allowance, but so far I've had no response on this).
Specifically to help with your understanding of this issue:
re: "In your algorithm, the filter doesn't change:"
This is incorrect as the filter is changed to be the 'minimised' universe once the option has been selected and is changed back to the 'normal' filter once the option trade has been closed, so that a new option trade can be selected.
The 'minimised' filter change is applied on line 185:
_optionUniverse.SetFilter(0,0,TimeSpan.Zero, TimeSpan.FromDays(0));
Now because the universe is minimised to improve performance (and to potentially support trading multiple underlyings), the actual selected contract has to be added as a separate subscription using AddOptionContract so that the selected contract continues to be available in the Slice option chain.
The 'normal' filter change is applied on lines 231-236:
_optionUniverse.SetFilter(u => { return u.Expiration(TimeSpan.Zero, TimeSpan.FromDays(50)) .Strikes(-1, +1) .Contracts(c => c.Where(s => s.ID.OptionRight == OptionRight.Call)); });
But, as mentioned in the original post, there is an issue that the updated minimised option universe filter is only applied by LEAN after the next monthly options expiration has occurred, instead of being applied immediately from the next Slice event.
It's as though there is a cache being applied by LEAN that is only reset after the next monthly options expiration has occurred, which prevents an updated filter from being applied immediately from the next Slice event.
I've tried to detail the issue in the log extracts and comments in the original post.
Any help to diagnose would be most appreciated.
Thanks,
ES.
Alexandre Catarino
Hi Ernest Shaggleford ,
The Option chain is a Universe Selection. AddOption creates a universe of options contracts (Option type that derives from Security), and SetFilter sets a selector. Like regular the Universe Selection, the Options universe was not designed for several re-definitions of the selector. Your approach is interesting but is a depart from the design that we do not recommend.
We are aware that options traders often select contracts based on greeks and implied volatility. To address that feature request, we have opened the following GitHub issue:
Select Option Contracts Based on Greeks #1518
Moreover, we don't recommend using Universe Selection with Options (AddOption) because of the multiple universes (one for each underlying) neither. If we want to trade options for a dynamic selection of underlying, we need to use the option chain provider.
Ernest Shaggleford
Hi Alexandre Catarino ,
if I understand what you are saying, the Universe SetFilter method is only intended to be used once in an algo.
I went down the Universe path as currently there is no other way to select by the Greeks, but the back testing performance of this approach is very slow, so I was trying to use a hybrid approach to speed up the back testing. It mostly works, except for the issue I've raised. It actually does improve the backtesting performance significantly, but it would be even better if SetFilter fully supported dynamic adjustment, but all of this would not be necessary if the OptionChainProvider approach provided Greeks for contract selection.
I agree that the ideal method for performance and for trading options on multiple underlyings would be via the OptionChainProvider approach with the Greeks being made available for contract selection.
For the github issue #1518 - this seems only applicable to the Universe approach and not the OptionChainProvider approach. This also looks like an old issue (2018) that seems to have already been resolved as the Greeks are available in the Universe.
Could you please clarify if this issue is intended for adding Greek selection functionality to the OptionChainProvider approach?
Thanks,
ES.
Alexandre Catarino
Hi Ernest Shaggleford ,
In Select Option Contracts Based on Greeks #1518, we will address both SetFilter and OptionChainProvider approaches.
Ernest Shaggleford
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!