Universes

Equity Options

Introduction

An Equity Options universe lets you select a basket of contracts for a single Option. LEAN models Option subscriptions as a universe of Option contracts.

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:

ArgumentData TypeDescriptionDefault Value
tickerstringstrThe underlying Equity ticker.
resolutionResolution?Resolution/NoneTypeThe resolution of the market data.Nonenull
marketstringstrThe underlying Equity market.Nonenull
fillDataForwardboolIf true, the current slice contains the last available data even if there is no data at the current time.Truetrue
leveragedecimalfloatThe leverage for this Equity.Security.NullLeverage
extendedMarketHoursboolA flag that signals if LEAN should send data during pre- and post-market trading hours.Falsefalse

If you add an Option universe for an underlying Equity that you don't have a subscription for, LEAN automatically subscribes to the underlying Equity with a data normalization mode of Raw. If you already have a subscription to the underlying Equity but it's not Raw, it automatically changes to Raw.

To set the price model of the Option, set its PriceModel property.

option.PriceModel =  OptionPriceModels.CrankNicolsonFD();
option.PriceModel = OptionPriceModels.CrankNicolsonFD()

Filter Contracts

By default, LEAN adds all of the available Option contracts to the Slice it passes to the OnData method. To narrow down the universe of Option contracts, 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:

MethodDescription
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.

// Select the front month call contracts
option.SetFilter(optionFilterUniverse => optionFilterUniverse.CallsOnly().FrontMonth());
# Select the front month call contracts
option.SetFilter(lambda option_filter_universe: option_filter_universe.CallsOnly().FrontMonth())

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)

By default, LEAN adds contracts to the OptionChain that pass the filter criteria at every time step in your algorithm. In backtests, if a contract in the chain doesn't pass the filter criteria, LEAN removes it from the chain at the start of the next day. In live trading, LEAN removes these contracts from the chain every 15 minutes.

Navigate Option Chains

OptionChain objects represent and 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 an at-the-money (ATM) put contract with the farthest expiration
        var contract = chain
            .OrderByDescending(x => x.Expiry)
            .ThenBy(x => Math.Abs(chain.Underlying.Price - x.Strike))
            .ThenByDescending(x => x.Right)
            .FirstOrDefault();
    }
}

public void OnData(OptionChains optionChains)
{
    if (optionChains.TryGetValue(_symbol, out var chain))
    {
        //
    }
}
def OnData(self, slice: Slice) -> None:
    chain = slice.OptionChains.get(self.symbol)
    if chain:
        # Example: Find an at-the-money (ATM) put contract with the farthest expiration
        contract = sorted(sorted(sorted(chain, \
            key = lambda x: abs(chain.Underlying.Price - x.Strike)), \
            key = lambda x: x.Expiry, reverse=True), \
            key = lambda x: x.Right, reverse=True)[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;
    }
}

public void OnData(OptionChains optionChains)
{
    foreach (var kvp in optionChains)
    {
        var canoncialSymbol = kvp.Key;
        var chain = kvp.Value;
    }
}
def OnData(self, slice: Slice) -> None:
    for canonical_symbol, chain in slice.OptionChains.items():
        pass

You can also see our Videos. You can also get in touch with us via Discord.

Did you find this page helpful?

Contribute to the documentation: