Universe Selection

Options Universes

Introduction

An Option Universe Selection model selects contracts for a set of Options.

Options Universe Selection

The OptionUniverseSelectionModel selects all the available contracts for the Equity Options, Index Options, and Future Options you specify. To use this model, provide a refreshIntervalrefresh_interval and a selector function. The refreshIntervalrefresh_interval defines how frequently LEAN calls the selector function. The selector function receives a DateTimedatetime object that represents the current Coordinated Universal Time (UTC) and returns a list of Symbol objects. The Symbol objects you return from the selector function are the Options of the universe.

UniverseSettings.Asynchronous = true;
AddUniverseSelection(
    new OptionUniverseSelectionModel(
        TimeSpan.FromDays(1), 
        _ => new [] { QuantConnect.Symbol.Create("SPY", SecurityType.Option, Market.USA) }
    )
);
from Selection.OptionUniverseSelectionModel import OptionUniverseSelectionModel 

self.universe_settings.asynchronous = True
self.set_universe_selection(
    OptionUniverseSelectionModel(
        timedelta(1), lambda _: [Symbol.create("SPY", SecurityType.OPTION, Market.USA)]
    )
)

The following table describes the arguments the model accepts:

ArgumentData TypeDescriptionDefault Value
refreshIntervalrefresh_intervalTimeSpantimedeltaTime interval between universe refreshes
optionChainSymbolSelectoroption_chain_symbol_selectorFunc<DateTime, IEnumerable<Symbol>>Callable[[datetime], List[Symbol]]A function that selects the Option symbols
universeSettingsuniverse_settingsUniverseSettingsThe universe settings. If you don't provide an argument, the model uses the algorithm.UniverseSettingsalgorithm.universe_settings by default.nullNone

The following example shows how to define the Option chain Symbol selector as an isolated method:

public override void Initialize()
{
    AddUniverseSelection(
        new OptionUniverseSelectionModel(TimeSpan.FromDays(1), SelectOptionChainSymbols)
    );
}

private IEnumerable<Symbol> SelectOptionChainSymbols(DateTime utcTime)
{
    // Equity Options example:
    //var tickers = new[] {"SPY", "QQQ", "TLT"};
    //return tickers.Select(ticker => QuantConnect.Symbol.Create(ticker, SecurityType.Option, Market.USA));

    // Index Options example:
    //var tickers = new[] {"VIX", "SPX"};
    //return tickers.Select(ticker => QuantConnect.Symbol.Create(ticker, SecurityType.IndexOption, Market.USA));

    // Future Options example:
    var futureSymbol = QuantConnect.Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME);
    var futureContractSymbols = FutureChainProvider.GetFutureContractList(futureSymbol, Time);
    foreach (var symbol in futureContractSymbols)
    {
        yield return QuantConnect.Symbol.CreateCanonicalOption(symbol);
    }
}
from Selection.OptionUniverseSelectionModel import OptionUniverseSelectionModel 

def initialize(self) -> None:
    self.add_universe_selection(
        OptionUniverseSelectionModel(timedelta(days=1), self.select_option_chain_symbols)
    )

def select_option_chain_symbols(self, utc_time: datetime) -> List[Symbol]:
    # Equity Options example:
    #tickers = ["SPY", "QQQ", "TLT"]
    #return [Symbol.create(ticker, SecurityType.OPTION, Market.USA) for ticker in tickers]

    # Index Options example:
    #tickers = ["VIX", "SPX"]
    #return [Symbol.create(ticker, SecurityType.INDEX_OPTION, Market.USA) for ticker in tickers]

    # Future Options example:
    future_symbol = Symbol.create(Futures.Indices.SP500E_MINI, SecurityType.FUTURE, Market.CME)
    future_contract_symbols = self.future_chain_provider.get_future_contract_list(future_symbol, self.time)
    return [Symbol.create_canonical_option(symbol) for symbol in future_contract_symbols]

This model uses the default Option filter, which selects all of the available Option contracts at the current time step. To use a different filter for the contracts, subclass the OptionUniverseSelectionModel and define a Filterfilter method. The Filterfilter method accepts and returns an OptionFilterUniverse object to select the Option contracts. The following table describes the methods of the OptionFilterUniverse class:

MethodDescription
Strikes(int minStrike, int maxStrike)strikes(min_strike: int, max_strike: int)Selects contracts that are within minStrikem_strike strikes below the underlying price and maxStrikemax_strike strikes above the underlying price.
CallsOnly()calls_only()Selects call contracts.
PutsOnly()puts_only()Selects put contracts.
StandardsOnly()standards_only()Selects standard contracts.
IncludeWeeklys()include_weeklys()Selects non-standard weeklys contracts.
WeeklysOnly()weeklys_only()Selects weekly contracts.
FrontMonth()front_month()Selects the front month contract.
BackMonths()back_months()Selects the non-front month contracts.
BackMonth()back_month()Selects the back month contracts.
Expiration(TimeSpan minExpiry, TimeSpan maxExpiry)expiration(min_expiry: timedelta, max_expiry: timedelta)Selects contracts that expire within a range of dates relative to the current day.
Expiration(int minExpiryDays, int maxExpiryDays)expiration(min_expiryDays: int, max_expiryDays: int)Selects contracts that expire within a range of dates relative to the current day.
NakedCall(int minDaysTillExpiry, decimal strikeFromAtm)naked_call(min_days_till_expiry: int, strike_from_atm: float)Selects a call contract to form Naked Call, Covered Call, or Protective Call Option strategies.
NakedPut(int minDaysTillExpiry, decimal strikeFromAtm)naked_put(min_days_till_expiry: int, strike_from_atm: float)Selects a put contract to form Naked Put, Covered Put, or Protective Put Option strategies.
CallSpread(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)call_spread(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two call contracts to form Bull Call Spread or Bear Call Spread Option strategies.
PutSpread(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)put_spread(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two put contracts to form Bull Put Spread or Bear Put Spread Option strategies.
CallCalendarSpread(decimal strikeFromAtm, int minNearDaysTillExpiry, int minFarDaysTillExpiry)call_calendar_spread(strike_from_atm: int, min_near_days_till_expiry: int, min_far_days_till_expiry: int)Selects two call contracts to form Long Call Calendar Spread or Short Call Calendar Spread Option strategies.
PutCalendarSpread(decimal strikeFromAtm, int minNearDaysTillExpiry, int minFarDaysTillExpiry)put_calendar_spread(strike_from_atm: int, min_near_days_till_expiry: int, min_far_days_till_expiry: int)Selects two put contracts to form Long Put Calendar Spread or Short Put Calendar Spread Option strategies.
Strangle(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)strangle(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two contracts to form Long Strangle or Short Strangle Option strategies.
Straddle(int minDaysTillExpiry)straddle(min_days_till_expiry: int)Selects two contracts to form Long Straddle or Short Straddle Option strategies.
ProtectiveCollar(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)protective_collar(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two contracts to form Protective Collar Option strategies.
Conversion(int minDaysTillExpiry, decimal strikeFromAtm)conversion(min_days_till_expiry: int, strike_from_atm: float)Selects two contracts to form Conversion or Reverse Conversion Option strategies.
CallButterfly(int minDaysTillExpiry, decimal strikeSpread)call_butterfly(min_days_till_expiry: int, strike_spread: float)Selects three contracts to form Long Call Butterfly or Short Call Butterfly Option strategies.
PutButterfly(int minDaysTillExpiry, decimal strikeSpread)put_butterfly(min_days_till_expiry: int, strike_spread: float)Selects three contracts to form Long Put Butterfly or Short Put Butterfly Option strategies.
IronButterfly(int minDaysTillExpiry, decimal strikeSpread)iron_butterfly(min_days_till_expiry: int, strike_spread: float)Selects four contracts to form Long Iron Butterfly or Short Iron Butterfly Option strategies.
IronCondor(int minDaysTillExpiry, decimal nearStrikeSpread, decimal farStrikeSpread)iron_condor(min_days_till_expiry: int, near_strike_spread: float, far_strike_spread: float)Selects four contracts to form Long Iron Condor or Short Iron Condor Option strategies.
BoxSpread(int minDaysTillExpiry, decimal strikeSpread)box_spread(min_days_till_expiry: int, strike_spread: float)Selects four contracts to form Box Spread or Short Box Spread Option strategies.
JellyRoll(decimal strikeFromAtm, int minNearDaysTillExpiry, int minFarDaysTillExpiry)jelly_roll(strike_from_atm: float, min_near_days_till_expiry: int, min_far_days_till_expiry: int)Selects four contracts to form Jelly Roll or Short Jelly Roll Option strategies.
CallLadder(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal middleStrikeFromAtm, decimal lowerStrikeFromAtm)call_ladder(min_days_till_expiry: int, higher_strike_from_atm: float, middle_strike_from_atm: float, lower_strike_from_atm: float)Selects four contracts to form Bear Call Ladder or Bull Call Ladder Option strategies.
PutLadder(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal middleStrikeFromAtm, decimal lowerStrikeFromAtm)put_ladder(min_days_till_expiry: int, higher_strike_from_atm: float, middle_strike_from_atm: float, lower_strike_from_atm: float)Selects four contracts to form Bear Put Ladder or Bull Put Ladder Option strategies.
Contracts(IEnumerable<Symbol> contracts)contracts(contracts: List[Symbol])Selects a list of contracts.
Contracts(Func<IEnumerable<Symbol>, IEnumerable< Symbol>> contractSelector)contracts(contract_selector: Callable[[List[Symbol]], List[Symbol]])Selects contracts that a selector function selects.

The contract filter runs at the first time step of each day.

To move the Option chain Symbol selector outside of the algorithm class, create a universe selection model that inherits the OptionUniverseSelectionModel class.

// In Initialize
UniverseSettings.Asynchronous = true;
AddUniverseSelection(new EarliestExpiringAtTheMoneyCallOptionUniverseSelectionModel(this));

// Outside of the algorithm class
class EarliestExpiringAtTheMoneyCallOptionUniverseSelectionModel : OptionUniverseSelectionModel
{
    public EarliestExpiringAtTheMoneyCallOptionUniverseSelectionModel(QCAlgorithm algorithm)
            : base(TimeSpan.FromDays(1), utcTime => SelectOptionChainSymbols(algorithm, utcTime)) {}
    
    private static IEnumerable<Symbol> SelectOptionChainSymbols(QCAlgorithm algorithm, DateTime utcTime)
    {
        // Equity Options example:
        //var tickers = new[] {"SPY", "QQQ", "TLT"};
        //return tickers.Select(ticker => QuantConnect.Symbol.Create(ticker, SecurityType.Option, Market.USA));

        // Index Options example:
        //var tickers = new[] {"VIX", "SPX"};
        //return tickers.Select(ticker => QuantConnect.Symbol.Create(ticker, SecurityType.IndexOption, Market.USA));

        // Future Options example:
        var futureSymbol = QuantConnect.Symbol.Create(Futures.Indices.SP500EMini, SecurityType.Future, Market.CME);
        var futureContractSymbols = algorithm.FutureChainProvider.GetFutureContractList(futureSymbol, algorithm.Time);
        foreach (var symbol in futureContractSymbols)
        {
            yield return QuantConnect.Symbol.CreateCanonicalOption(symbol);
        }
    }

    protected override OptionFilterUniverse Filter(OptionFilterUniverse filter)
    {
        return filter.Strikes(-1, -1).Expiration(0, 7).CallsOnly();
    }
}
# In initialize
self.universe_settings.asynchronous = True
self.add_universe_settings(EarliestExpiringAtTheMoneyCallOptionUniverseSelectionModel(self))

# Outside of the algorithm class
class EarliestExpiringAtTheMoneyCallOptionUniverseSelectionModel(OptionUniverseSelectionModel):
    def __init__(self, algorithm):
        self.algo = algorithm
        super().__init__(timedelta(1), self.select_option_chain_symbols)
    
    def select_option_chain_symbols(self, utc_time: datetime) -> List[Symbol]:
        # Equity Options example:
        #tickers = ["SPY", "QQQ", "TLT"]
        #return [Symbol.create(ticker, SecurityType.OPTION, Market.USA) for ticker in tickers]

        # Index Options example:
        #tickers = ["VIX", "SPX"]
        #return [Symbol.create(ticker, SecurityType.INDEX_OPTION, Market.USA) for ticker in tickers]

        # Future Options example:
        future_symbol = Symbol.create(Futures.Indices.SP500E_MINI, SecurityType.FUTURE, Market.CME)
        future_contract_symbols = self.algo.future_chain_provider.get_future_contract_list(future_symbol, self.algo.time)
        return [Symbol.create_canonical_option(symbol) for symbol in future_contract_symbols]

    def Filter(self, option_filter_universe: OptionFilterUniverse) -> OptionFilterUniverse:
        return option_filter_universe.strikes(-1, -1).expiration(0, 7).calls_only()

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.

To override the default pricing model of the Options, set a pricing model in a security initializer.

To override the initial guess of implied volatility, set and warm up the underlying volatility model.

To view the implementation of this model, see the LEAN GitHub repositoryLEAN GitHub repository.

Option Chained Universe Selection

An Option chained universe subscribes to Option contracts on the constituents of a US Equity universe.

UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
UniverseSettings.Asynchronous = true;
AddUniverseSelection(
    new OptionChainedUniverseSelectionModel(
        AddUniverse(Universe.DollarVolume.Top(10)),
        optionFilterUniverse => optionFilterUniverse.Strikes(-2, +2).FrontMonth().CallsOnly()
    )
);
self.universe_settings.data_normalization_mode = DataNormalizationMode.RAW
self.universe_settings.asynchronous = True
self.add_universe_selection(
    OptionChainedUniverseSelectionModel(
        self.add_universe(self.universe.dollar_volume.top(10)),
        lambda option_filter_universe: option_filter_universe.strikes(-2, +2).front_month().calls_only()
    )
)

The following table describes the arguments the model accepts:

ArgumentData TypeDescriptionDefault Value
universeUniverseThe universe to chain onto the Option Universe Selection model
optionFilteroption_filterFunc<OptionFilterUniverse, OptionFilterUniverse>Callable[[OptionFilterUniverse], OptionFilterUniverse]The Option filter universe to use
universeSettingsuniverse_settingsUniverseSettingsThe universe settings. If you don't provide an argument, the model uses the algorithm.UniverseSettingsalgorithm.universe_settings by default.nullNone

The optionFilteroption_filter function receives and returns an OptionFilterUniverse to select the Option contracts. The following table describes the methods of the OptionFilterUniverse class:

MethodDescription
Strikes(int minStrike, int maxStrike)strikes(min_strike: int, max_strike: int)Selects contracts that are within minStrikem_strike strikes below the underlying price and maxStrikemax_strike strikes above the underlying price.
CallsOnly()calls_only()Selects call contracts.
PutsOnly()puts_only()Selects put contracts.
StandardsOnly()standards_only()Selects standard contracts.
IncludeWeeklys()include_weeklys()Selects non-standard weeklys contracts.
WeeklysOnly()weeklys_only()Selects weekly contracts.
FrontMonth()front_month()Selects the front month contract.
BackMonths()back_months()Selects the non-front month contracts.
BackMonth()back_month()Selects the back month contracts.
Expiration(TimeSpan minExpiry, TimeSpan maxExpiry)expiration(min_expiry: timedelta, max_expiry: timedelta)Selects contracts that expire within a range of dates relative to the current day.
Expiration(int minExpiryDays, int maxExpiryDays)expiration(min_expiryDays: int, max_expiryDays: int)Selects contracts that expire within a range of dates relative to the current day.
NakedCall(int minDaysTillExpiry, decimal strikeFromAtm)naked_call(min_days_till_expiry: int, strike_from_atm: float)Selects a call contract to form Naked Call, Covered Call, or Protective Call Option strategies.
NakedPut(int minDaysTillExpiry, decimal strikeFromAtm)naked_put(min_days_till_expiry: int, strike_from_atm: float)Selects a put contract to form Naked Put, Covered Put, or Protective Put Option strategies.
CallSpread(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)call_spread(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two call contracts to form Bull Call Spread or Bear Call Spread Option strategies.
PutSpread(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)put_spread(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two put contracts to form Bull Put Spread or Bear Put Spread Option strategies.
CallCalendarSpread(decimal strikeFromAtm, int minNearDaysTillExpiry, int minFarDaysTillExpiry)call_calendar_spread(strike_from_atm: int, min_near_days_till_expiry: int, min_far_days_till_expiry: int)Selects two call contracts to form Long Call Calendar Spread or Short Call Calendar Spread Option strategies.
PutCalendarSpread(decimal strikeFromAtm, int minNearDaysTillExpiry, int minFarDaysTillExpiry)put_calendar_spread(strike_from_atm: int, min_near_days_till_expiry: int, min_far_days_till_expiry: int)Selects two put contracts to form Long Put Calendar Spread or Short Put Calendar Spread Option strategies.
Strangle(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)strangle(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two contracts to form Long Strangle or Short Strangle Option strategies.
Straddle(int minDaysTillExpiry)straddle(min_days_till_expiry: int)Selects two contracts to form Long Straddle or Short Straddle Option strategies.
ProtectiveCollar(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal lowerStrikeFromAtm)protective_collar(min_days_till_expiry: int, higher_strike_from_atm: float, lower_strike_from_atm: float)Selects two contracts to form Protective Collar Option strategies.
Conversion(int minDaysTillExpiry, decimal strikeFromAtm)conversion(min_days_till_expiry: int, strike_from_atm: float)Selects two contracts to form Conversion or Reverse Conversion Option strategies.
CallButterfly(int minDaysTillExpiry, decimal strikeSpread)call_butterfly(min_days_till_expiry: int, strike_spread: float)Selects three contracts to form Long Call Butterfly or Short Call Butterfly Option strategies.
PutButterfly(int minDaysTillExpiry, decimal strikeSpread)put_butterfly(min_days_till_expiry: int, strike_spread: float)Selects three contracts to form Long Put Butterfly or Short Put Butterfly Option strategies.
IronButterfly(int minDaysTillExpiry, decimal strikeSpread)iron_butterfly(min_days_till_expiry: int, strike_spread: float)Selects four contracts to form Long Iron Butterfly or Short Iron Butterfly Option strategies.
IronCondor(int minDaysTillExpiry, decimal nearStrikeSpread, decimal farStrikeSpread)iron_condor(min_days_till_expiry: int, near_strike_spread: float, far_strike_spread: float)Selects four contracts to form Long Iron Condor or Short Iron Condor Option strategies.
BoxSpread(int minDaysTillExpiry, decimal strikeSpread)box_spread(min_days_till_expiry: int, strike_spread: float)Selects four contracts to form Box Spread or Short Box Spread Option strategies.
JellyRoll(decimal strikeFromAtm, int minNearDaysTillExpiry, int minFarDaysTillExpiry)jelly_roll(strike_from_atm: float, min_near_days_till_expiry: int, min_far_days_till_expiry: int)Selects four contracts to form Jelly Roll or Short Jelly Roll Option strategies.
CallLadder(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal middleStrikeFromAtm, decimal lowerStrikeFromAtm)call_ladder(min_days_till_expiry: int, higher_strike_from_atm: float, middle_strike_from_atm: float, lower_strike_from_atm: float)Selects four contracts to form Bear Call Ladder or Bull Call Ladder Option strategies.
PutLadder(int minDaysTillExpiry, decimal higherStrikeFromAtm, decimal middleStrikeFromAtm, decimal lowerStrikeFromAtm)put_ladder(min_days_till_expiry: int, higher_strike_from_atm: float, middle_strike_from_atm: float, lower_strike_from_atm: float)Selects four contracts to form Bear Put Ladder or Bull Put Ladder Option strategies.
Contracts(IEnumerable<Symbol> contracts)contracts(contracts: List[Symbol])Selects a list of contracts.
Contracts(Func<IEnumerable<Symbol>, IEnumerable< Symbol>> contractSelector)contracts(contract_selector: Callable[[List[Symbol]], List[Symbol]])Selects contracts that a selector function selects.

The following example shows how to define the Option filter as an isolated method:

public override void Initialize()
{
    UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
    UniverseSettings.Asynchronous = true;
    AddUniverseSelection(
        new OptionChainedUniverseSelectionModel(
            AddUniverse(Universe.DollarVolume.Top(10)), OptionFilterFunction
        )
    );
}

private OptionFilterUniverse OptionFilterFunction(OptionFilterUniverse optionFilterUniverse)
{
    return optionFilterUniverse.Strikes(-2, +2).FrontMonth().CallsOnly();
}
def initialize(self) -> None:
    self.universe_settings.data_normalization_mode = DataNormalizationMode.RAW
    self.universe_settings.asynchronous = True
    self.add_universe_selection(
        OptionChainedUniverseSelectionModel(
            self.add_universe(self.universe.dollar_volume.top(10)), self.option_filter_function
        )
    )

def option_filter_function(self, option_filter_universe: OptionFilterUniverse) -> OptionFilterUniverse:
    return option_filter_universe.strikes(-2, +2).front_month().calls_only()

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.

To view the implementation of this model, see the LEAN GitHub repository.

Example

The following example chains a fundamental universe and an Equity Options universe. It first selects 10 stocks with the lowest PE ratio and then selects their front-month call Option contracts. It buys one front-month call Option contract every day.

To override the default pricing model of the Options, set a pricing model in a security initializer.

To override the initial guess of implied volatility, set and warm up the underlying volatility model.

using QuantConnect.Data;
using QuantConnect.Data.Fundamental;
using QuantConnect.Data.UniverseSelection;
using QuantConnect.Securities;
using QuantConnect.Securities.Option;
using QuantConnect.Util;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp
{
    public class ETFUniverseOptions : QCAlgorithm
    {
        private int _day;
        public override void Initialize()
        {
            SetStartDate(2023, 2, 2);
            SetCash(100000);
            UniverseSettings.Asynchronous = true;
            UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw;
            SetSecurityInitializer(new CustomSecurityInitializer(this));

            var universe = AddUniverse(FundamentalFunction);
            AddUniverseOptions(universe, OptionFilterFunction);
        }

        private IEnumerable<Symbol> FundamentalFunction(IEnumerable<Fundamental> fundamental)
        {
            return fundamental
                .Where(f => !double.IsNaN(f.ValuationRatios.PERatio))
                .OrderBy(f => f.ValuationRatios.PERatio)
                .Take(10)
                .Select(x => x.Symbol);
        }

        private OptionFilterUniverse OptionFilterFunction(OptionFilterUniverse optionFilterUniverse)
        {
            return optionFilterUniverse.Strikes(-2, +2).FrontMonth().CallsOnly();
        }

        public override void OnData(Slice data)
        {
            if (IsWarmingUp || _day == Time.Day) return;

            foreach (var (symbol, chain) in data.OptionChains)
            {
                if (Portfolio[chain.Underlying.Symbol].Invested)
                    Liquidate(chain.Underlying.Symbol);

                var spot = chain.Underlying.Price;
                var contract = chain.OrderBy(x => Math.Abs(spot-x.Strike)).FirstOrDefault();
                var tag = $"IV: {contract.ImpliedVolatility:F3} Δ: {contract.Greeks.Delta:F3}";
                MarketOrder(contract.Symbol, 1, true, tag);
                _day = Time.Day;
            }
        }
    }

    internal class CustomSecurityInitializer : BrokerageModelSecurityInitializer
    {
        private QCAlgorithm _algorithm;
        public CustomSecurityInitializer(QCAlgorithm algorithm)
            : base(algorithm.BrokerageModel, new FuncSecuritySeeder(algorithm.GetLastKnownPrices))
        {
            _algorithm = algorithm;
        }    
    
        public override void Initialize(Security security)
        {
            // First, call the superclass definition
            // This method sets the reality models of each security using the default reality models of the brokerage model
            base.Initialize(security);

            // Next, overwrite the price model        
            if (security.Type == SecurityType.Option) // Option type
            {
                (security as Option).PriceModel = OptionPriceModels.CrankNicolsonFD();
            }

            // Overwrite the volatility model and warm it up
            if (security.Type == SecurityType.Equity)
            {
                security.VolatilityModel = new StandardDeviationOfReturnsVolatilityModel(30);
                var tradeBars = _algorithm.History(security.Symbol, 30, Resolution.Daily);
                foreach (var tradeBar in tradeBars)
                    security.VolatilityModel.Update(security, tradeBar);
            }    
        }
    }
}
from AlgorithmImports import *

    class ChainedUniverseAlgorithm(QCAlgorithm):
    def initialize(self):
        self.set_start_date(2023, 2, 2)
        self.set_cash(100000)
        self.universe_settings.asynchronous = True
        self.universe_settings.data_normalization_mode = DataNormalizationMode.RAW
        self.set_security_initializer(CustomSecurityInitializer(self))

        universe = self.add_universe(self.fundamental_function)
        self.add_universe_options(universe, self.option_filter_function)
        self.day = 0

    def fundamental_function(self, fundamental: List[Fundamental]) -> List[Symbol]:
        filtered = (f for f in fundamental if not np.isnan(f.valuation_ratios.pe_ratio))
        sorted_by_pe_ratio = sorted(filtered, key=lambda f: f.valuation_ratios.pe_ratio)
        return [f.symbol for f in sorted_by_pe_ratio[:10]]

    def option_filter_function(self, option_filter_universe: OptionFilterUniverse) -> OptionFilterUniverse:
        return option_filter_universe.strikes(-2, +2).front_month().calls_only()

    def on_data(self, data: Slice) -> None:
        if self.is_warming_up or self.day == self.time.day:
            return
        
        for symbol, chain in data.option_chains.items():
            if self.portfolio[chain.underlying.symbol].invested:
                self.liquidate(chain.underlying.symbol)

            spot = chain.underlying.price
            contract = sorted(chain, key=lambda x: abs(spot-x.strike))[0]
            tag = f"IV: {contract.implied_volatility:.3f} Δ: {contract.greeks.delta:.3f}"
            self.market_order(contract.symbol, 1, True, tag)
            self.day = self.time.day

class CustomSecurityInitializer(BrokerageModelSecurityInitializer):
    def __init__(self, algorithm: QCAlgorithm) -> None:
        super().__init__(algorithm.brokerage_model, FuncSecuritySeeder(algorithm.get_last_known_prices))
        self.algorithm = algorithm

    def initialize(self, security: Security) -> None:
        # First, call the superclass definition
        # This method sets the reality models of each security using the default reality models of the brokerage model
        super().initialize(security)

        # Overwrite the price model        
        if security.type == SecurityType.OPTION: # Option type
            security.price_model = OptionPriceModels.crank_nicolson_fd()

        # Overwrite the volatility model and warm it up
        if security.type == SecurityType.EQUITY:
            security.volatility_model = StandardDeviationOfReturnsVolatilityModel(30)
            trade_bars = self.algorithm.history[TradeBar](security.symbol, 30, Resolution.DAILY)
            for trade_bar in trade_bars:
                security.volatility_model.update(security, trade_bar)

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: