Universes
Equity Options
Create Universes
To add a universe of Equity Option contracts, in the Initialize
method, call the AddOption
method. This method returns an Option
object, which contains the canonical Symbol
. You can't trade with the canonical Option Symbol
, but save a reference to it so you can easily access the Option contracts in the OptionChain that LEAN passes to the OnData
method.
var option = AddOption("SPY"); _symbol = option.Symbol;
option = self.AddOption("SPY") self.symbol = option.Symbol
The following table describes the AddOption
method arguments:
Argument | Data Type | Description | Default Value |
---|---|---|---|
ticker | string str | The underlying Equity ticker. To view the supported underlying Equity tickers, see Supported Assets. | |
resolution | Resolution? Resolution/NoneType | The resolution of the market data. To view the supported resolutions, see Resolutions. The Equity resolution must be less than or equal to the Equity Option resolution. For example, if you set the Equity resolution to minute, then you must set the Equity Option resolution to minute, hour, or daily. | None null |
market | string str | The underlying Equity market. | None null |
fillForward | bool | If true, the current slice contains the last available data even if there is no data at the current time. | True true |
leverage | decimal float | The leverage for this Equity. | Security.NullLeverage |
extendedMarketHours | bool | A flag that signals if LEAN should send data during pre- and post-market trading hours. | False false |
If you add an Equity Option universe but don't have a subscription to the underlying Equity, LEAN automatically subscribes to the underlying Equity with the following settings:
Setting | Value |
---|---|
Fill forward | Same as the Option universe |
Leverage | 0 |
Extended Market Hours | Same as the Option universe |
Data Normalization | DataNormalizationMode.Raw |
If you already have a subscription to the underlying Equity but it's not Raw
data normalization, LEAN automatically changes it to Raw
.
To override the default pricing model of the Option, set a pricing model.
option.PriceModel = OptionPriceModels.CrankNicolsonFD();
option.PriceModel = OptionPriceModels.CrankNicolsonFD()
To override the initial guess of implied volatility, set and warm up the underlying volatility model.
Filter Contracts
By default, LEAN subscribes to the Option contracts that have the following characteristics:
- Standard type (exclude weeklys)
- Within 1 strike price of the underlying asset price
- Expire within 31 days
To adjust the universe of contracts, set a filter. The filter usually runs at every time step in your algorithm. When the filter selects a contract that isn't currently in your universe, LEAN adds the new contract data to the next Slice
that it passes to the OnData
method.
To set a contract filter, in the Initialize
method, call the SetFilter
method of the Option
object. The following table describes the available filter techniques:
Method | Description |
---|---|
SetFilter(int minStrike, int maxStrike) SetFilter(minStrike: int, maxStrike: int) | Selects the contracts that have a strike price within a minimum and maximum strike level relative to the underlying price. For example, say the underlying price is $302 and there are strikes at every $5. If you set minStrike to -1 and maxStrike to 1, LEAN selects the contracts that have a strike of $300 or $305. |
SetFilter(TimeSpan minExpiry, TimeSpan maxExpiry) SetFilter(minExpiry: timedelta, maxExpiry: timedelta) | Selects the contracts that expire within the range you set. |
SetFilter(int minStrike, int maxStrike, TimeSpan minExpiry, TimeSpan maxExpiry) SetFilter(minStrike: int, maxStrike: int, minExpiry: timedelta, maxExpiry: timedelta) | Selects the contracts that expire and have a strike within the range you set. |
SetFilter(Func<OptionFilterUniverse, OptionFilterUniverse> universeFunc) SetFilter(universeFunc: Callable[[OptionFilterUniverse], OptionFilterUniverse]) | Selects the contracts that a function selects. |
// Select contracts that have a strike price within 1 strike level above and below the underlying price option.SetFilter(minStrike: -1, maxStrike: 1); // Select contracts that expire within 30 days option.SetFilter(minExpiry: TimeSpan.FromDays(0), maxExpiry: TimeSpan.FromDays(30)); // Select contracts that have a strike price within 1 strike level and expire within 30 days option.SetFilter(minStrike: -1, maxStrike: 1, minExpiry: TimeSpan.FromDays(0), maxExpiry: TimeSpan.FromDays(30)); // Select call contracts option.SetFilter(optionFilterUniverse => optionFilterUniverse.CallsOnly());
# Select contracts that have a strike price within 1 strike level above and below the underlying price option.SetFilter(minStrike=-1, maxStrike=1) # Select contracts that expire within 30 days option.SetFilter(minExpiry=timedelta(days=0), maxExpiry=timedelta(days=30)) # Select contracts that have a strike price within 1 strike level and expire within 30 days option.SetFilter(minStrike=-1, maxStrike=1, minExpiry=timedelta(days=0), maxExpiry=timedelta(days=30)) # Select call contracts option.SetFilter(lambda option_filter_universe: option_filter_universe.CallsOnly())
The following table describes the filter methods of the OptionFilterUniverse
class:
Method | Description |
---|---|
Strikes(int minStrike, int maxStrike) Strikes(minStrike: int, maxStrike: int) | Selects contracts that are within minStrike strikes below the underlying price and maxStrike strikes above the underlying price |
CallsOnly() | Selects call contracts |
PutsOnly() | Selects put contracts |
StandardsOnly() | Selects standard contracts |
IncludeWeeklys() | Selects non-standard weeklys contracts |
WeeklysOnly() | Selects weekly contracts |
FrontMonth() | Selects the front month contract |
BackMonths() | Selects the non-front month contracts |
BackMonth() | Selects the back month contracts |
Expiration(TimeSpan minExpiry, TimeSpan maxExpiry) Expiration(minExpiry: timedelta, maxExpiry: timedelta) | Selects contracts that expire within a range of dates relative to the current day |
Expiration(int minExpiryDays, int maxExpiryDays) Expiration(minExpiryDays: int, maxExpiryDays: int) | Selects contracts that expire within a range of dates relative to the current day |
Contracts(IEnumerable<Symbol> contracts) Contracts(contracts: List[Symbol]) | Selects a list of contracts |
Contracts(Func<IEnumerable<Symbol>, IEnumerable< Symbol>> contractSelector) Contracts(contractSelector: Callable[[List[Symbol]], List[Symbol]]) | Selects contracts that a selector function selects |
OnlyApplyFilterAtMarketOpen() | Instructs the engine to only filter contracts on the first time step of each market day |
The preceding methods return an OptionFilterUniverse
, so you can chain the methods together.
// Example 1: Select the front month call contracts option.SetFilter(optionFilterUniverse => optionFilterUniverse.CallsOnly().FrontMonth()); // Example 2: Select the contracts (including weeklys) that expire in the next 90 days option.SetFilter(optionFilterUniverse => optionFilterUniverse.IncludeWeeklys().Strikes(-20, 20).Expiration(0, 90));
# Example 1: Select the front month call contracts option.SetFilter(lambda option_filter_universe: option_filter_universe.CallsOnly().FrontMonth()) # Example 2: Select the contracts (including weeklys) that expire in the next 90 days option.SetFilter(lambda option_filter_universe: option_filter_universe.IncludeWeeklys().Strikes(-20, 20).Expiration(0, 90))
To perform thorough filtering on the OptionFilterUniverse
, define an isolated filter method.
// In Initialize option.SetFilter(Selector); private OptionFilterUniverse Selector(OptionFilterUniverse optionFilterUniverse) { var symbols = optionFilterUniverse.PutsOnly(); var strike = symbols.Select(symbol => symbol.ID.StrikePrice).Min(); symbols = symbols.Where(symbol => symbol.ID.StrikePrice == strike); return optionFilterUniverse.Contracts(symbols); }
# In Initialize option.SetFilter(self.contract_selector) def contract_selector(self, option_filter_universe: OptionFilterUniverse) -> OptionFilterUniverse: symbols = option_filter_universe.PutsOnly() strike = min([symbol.ID.StrikePrice for symbol in symbols]) symbols = [symbol for symbol in symbols if symbol.ID.StrikePrice == strike] return option_filter_universe.Contracts(symbols)
Some of the preceding filter methods only set an internal enumeration in the OptionFilterUniverse
that it uses later on in the filter process. This subset of filter methods don't immediately reduce the number of contract Symbol
objects in the OptionFilterUniverse
.
Navigate Option Chains
OptionChain
objects represent an entire chain of Option contracts for a single underlying security. They have the following properties:
To get the OptionChain
, index the OptionChains
property of the Slice
with the canonical Symbol
. After you get the OptionChain
, you can sort and filter the Option contracts in the chain.
public override void OnData(Slice slice) { if (slice.OptionChains.TryGetValue(_symbol, out var chain)) { // Example: Find 5 put contracts that are closest to at-the-money (ATM) and have the farthest expiration var contracts = chain .Where(x => x.Right == OptionRight.Put) .OrderByDescending(x => x.Expiry) .ThenBy(x => Math.Abs(chain.Underlying.Price - x.Strike)) .Take(5); // Select the contract with the delta closest to -0.5 var contract = contracts.OrderBy(x => Math.Abs(-0.5m - x.Greeks.Delta)).FirstOrDefault(); } } public void OnData(OptionChains optionChains) { if (optionChains.TryGetValue(_symbol, out var chain)) { var contracts = chain.Contracts; } }
def OnData(self, slice: Slice) -> None: chain = slice.OptionChains.get(self.symbol) if chain: # Example: Find 5 put contracts that are closest to at-the-money (ATM) and have the farthest expiration contracts = [x for x in chain if x.Right == OptionRight.Put] contracts = sorted(sorted(contracts, \ key = lambda x: abs(chain.Underlying.Price - x.Strike)), \ key = lambda x: x.Expiry, reverse=True)[:5] # Select the contract with the delta closest to -0.5 contract = sorted(contracts, key=lambda x: abs(-0.5 - x.Greeks.Delta))[0]
You can also loop through the OptionChains
property to get each OptionChain
.
public override void OnData(Slice slice) { foreach (var kvp in slice.OptionChains) { var canoncialSymbol = kvp.Key; var chain = kvp.Value; var contracts = chain.Contracts; } } public void OnData(OptionChains optionChains) { foreach (var kvp in optionChains) { var canoncialSymbol = kvp.Key; var chain = kvp.Value; var contracts = chain.Contracts; } }
def OnData(self, slice: Slice) -> None: for canonical_symbol, chain in slice.OptionChains.items(): contracts = chain.Contracts
Live Trading Considerations
By default, LEAN adds contracts to the OptionChain
that pass the filter criteria at every time step in your algorithm. If a contract has been in the universe for a duration that matches the MinimumTimeInUniverse
setting and it no longer passes the filter criteria, LEAN removes it from the chain.
This default behavior can lead to a large number of open data subscriptions, which can be inconvenient in live trading since some data feed providers impose data subscription limits. To reduce the number of data subscriptions, change the value of the MinimumTimeInUniverse
universe setting.
UniverseSettings.MinimumTimeInUniverse = TimeSpan.FromMinutes(15); UniverseSettings.MinimumTimeInUniverse = TimeSpan.Zero;
self.UniverseSettings.MinimumTimeInUniverse = timedelta(minutes=15) self.UniverseSettings.MinimumTimeInUniverse = timedelta(0)
If you set the value to TimeSpan.Zero
timedelta(0)
, LEAN removes all of the contract subscriptions at every time step and your data provider stops sending the data. If your filter re-selects some of the same contracts when it runs next, LEAN requests new data subscriptions from your data provider. To avoid unsubscribing and resubscribing to the same contracts at every time step, use a timedelta
TimeSpan
greater than 0.