Index Options

Individual Contracts

Introduction

This page explains how to request historical data for individual Index Option contracts. The history requests on this page only return the prices and open interest of the Option contracts, not their implied volatility or Greeks. For information about history requests that return the daily implied volatility and Greeks, see Universes.

Create Subscriptions

Follow these steps to subscribe to individual Index Option contracts:

  1. Load the assembly files and data types in their own cell.
  2. #load "../Initialize.csx"
  3. Import the data types.
  4. #load "../QuantConnect.csx"
    #r "../Microsoft.Data.Analysis.dll"
    
    using QuantConnect;
    using QuantConnect.Data;
    using QuantConnect.Algorithm;
    using QuantConnect.Research;
    using QuantConnect.Indicators;
    using QuantConnect.Data.Market;
    using QuantConnect.Securities.Index;
    using QuantConnect.Securities.IndexOption;
    using Microsoft.Data.Analysis;
  5. Create a QuantBook.
  6. var qb = new QuantBook();
    qb = QuantBook()
  7. Add the underlying Index.
  8. var underlyingSymbol = qb.AddIndex("SPX", Resolution.Minute).Symbol;
    underlying_symbol = qb.add_index("SPX", Resolution.MINUTE).symbol

    To view the available Indices, see Supported Assets.

    If you do not pass a resolution argument, Resolution.MinuteResolution.MINUTE is used by default.

  9. Set the start date to a date in the past that you want to use as the analysis date.
  10. qb.SetStartDate(2024, 1, 1);
    qb.set_start_date(2024, 1, 1)

    The method that you call in the next step returns data on all the contracts that were tradable on this date.

  11. Call the OptionChainoption_chain method with the underlying Index Symbol.
  12. // Get the Option contracts that were tradable on January 1st, 2024.
    //   Option A: Standard contracts.
    var chain = qb.OptionChain(
        QuantConnect.Symbol.CreateCanonicalOption(underlyingSymbol, Market.USA, "?SPX")
    );
    
    //   Option B: Weekly contracts.
    //var chain = qb.OptionChain(
    //    QuantConnect.Symbol.CreateCanonicalOption(underlyingSymbol, "SPXW", Market.USA, "?SPXW")
    //);
    # Get the Option contracts that were tradable on January 1st, 2024.
    #   Option A: Standard contracts.
    chain = qb.option_chain(
        Symbol.create_canonical_option(underlying_symbol, Market.USA, "?SPX"), flatten=True
    ).data_frame
    
    #  Option B: Weekly contracts.
    #chain = qb.option_chain(
    #    Symbol.create_canonical_option(underlying_symbol, "SPXW", Market.USA, "?SPXW"), flatten=True
    #).data_frame

    This method returns an OptionChain object, which represent an entire chain of Option contracts for a single underlying security. You can even format the chain data into a DataFrame where each row in the DataFrame represents a single contract.

  13. Sort and filter the data to select the specific contract(s) you want to analyze.
  14. // Select a contract.
    var expiry = chain.Select(contract => contract.Expiry).Min();
    var contractSymbol = chain
        .Where(contract => 
            // Select call contracts with the closest expiry.
            contract.Expiry == expiry && 
            contract.Right == OptionRight.Call &&
            // Select contracts with a 0.3-0.7 delta.
            contract.Greeks.Delta > 0.3m && 
            contract.Greeks.Delta < 0.7m
        )
        // Select the contract with the largest open interest.
        .OrderByDescending(contract => contract.OpenInterest)
        .First()
        // Get the Symbol of the target contract.
        .Symbol;
    # Select a contract.
    expiry = chain.expiry.min()
    contract_symbol = chain[
        # Select call contracts with the closest expiry.
        (chain.expiry == expiry) & 
        (chain.right == OptionRight.CALL) &
        # Select contracts with a 0.3-0.7 delta.
        (chain.delta > 0.3) &
        (chain.delta < 0.7)
        # Select the contract with the largest open interest.
    ].sort_values('openinterest').index[-1]
  15. Call the AddIndexOptionContractadd_index_option_contract method with an OptionContract Symbol and disable fill-forward.
  16. var optionContract = qb.AddIndexOptionContract(contractSymbol, fillForward: false);
    option_contract = qb.add_index_option_contract(contract_symbol, fill_forward=False)

    Disable fill-forward because there are only a few OpenInterest data points per day.

Trade History

TradeBar objects are price bars that consolidate individual trades from the exchanges. They contain the open, high, low, close, and volume of trading activity over a period of time.

Tradebar decomposition

To get trade data, call the history or history[TradeBar]History<TradeBar> method with the contract Symbol object(s).

var history = qb.History<TradeBar>(contractSymbol, TimeSpan.FromDays(3));
foreach (var tradeBar in history)
{
    Console.WriteLine(tradeBar);
}
# DataFrame format
history_df = qb.history(TradeBar, contract_symbol, timedelta(3))
display(history_df)

# TradeBar objects
history = qb.history[TradeBar](contract_symbol, timedelta(3))
for trade_bar in history:
    print(trade_bar)

TradeBar objects have the following properties:

Quote History

QuoteBar objects are bars that consolidate NBBO quotes from the exchanges. They contain the open, high, low, and close prices of the bid and ask. The Openopen, Highhigh, Lowlow, and Closeclose properties of the QuoteBar object are the mean of the respective bid and ask prices. If the bid or ask portion of the QuoteBar has no data, the Openopen, Highhigh, Lowlow, and Closeclose properties of the QuoteBar copy the values of either the Bidbid or Askask instead of taking their mean.

Quotebar decomposition

To get quote data, call the history or history[QuoteBar]History<QuoteBar> method with the contract Symbol object(s).

var history = qb.History<QuoteBar>(contractSymbol, TimeSpan.FromDays(3));
foreach (var quoteBar in history)
{
    Console.WriteLine(quoteBar);
}
# DataFrame format
history_df = qb.history(QuoteBar, contract_symbol, timedelta(3))
display(history_df)

# QuoteBar objects
history = qb.history[QuoteBar](contract_symbol, timedelta(3))
for quote_bar in history:
    print(quote_bar)

QuoteBar objects have the following properties:

Open Interest History

Open interest is the number of outstanding contracts that haven't been settled. It provides a measure of investor interest and the market liquidity, so it's a popular metric to use for contract selection. Open interest is calculated once per day.

To get open interest data, call the history or history[OpenInterest]History<OpenInterest> method with the contract Symbol object(s).

var history = qb.History<OpenInterest>(contractSymbol, TimeSpan.FromDays(3));
foreach (var openInterest in history)
{
    Console.WriteLine(openInterest);
}
# DataFrame format
history_df = qb.history(OpenInterest, contract_symbol, timedelta(3))
display(history_df)

# OpenInterest objects
history = qb.history[OpenInterest](contract_symbol, timedelta(3))
for open_interest in history:
    print(open_interest)

OpenInterest objects have the following properties:

Greeks and IV History

The Greeks are measures that describe the sensitivity of an Option's price to various factors like underlying price changes (Delta), time decay (Theta), volatility (Vega), and interest rates (Rho), while Implied Volatility (IV) represents the market's expectation of the underlying asset's volatility over the life of the Option.

Follow these steps to get the Greeks and IV data:

  1. Create the mirror contract Symbol.
  2. var mirrorContractSymbol = Symbol.CreateOption(
        optionContract.Underlying.Symbol, 
        contractSymbol.ID.Market, 
        optionContract.Style, 
        optionContract.Right == OptionRight.Put ? OptionRight.Call : OptionRight.Put,
        optionContract.StrikePrice, 
        optionContract.Expiry
    );
    mirror_contract_symbol = Symbol.create_option(
        option_contract.underlying.symbol, contract_symbol.id.market, option_contract.style, 
        OptionRight.Call if option_contract.right == OptionRight.PUT else OptionRight.PUT,
        option_contract.strike_price, option_contract.expiry
    )
  3. Set up the risk free interest rate, dividend yield, and Option pricing models.
  4. In our research, we found the Forward Tree model to be the best pricing model for indicators.

    risk_free_rate_model = qb.risk_free_interest_rate_model
    dividend_yield_model = DividendYieldProvider(underlying_symbol)
    option_model = OptionPricingModelType.FORWARD_TREE
    var riskFreeRateModel = qb.RiskFreeInterestRateModel;
    var dividendYieldModel = new DividendYieldProvider(underlyingSymbol);
    var optionModel = OptionPricingModelType.ForwardTree;
  5. Define a method to return the IV & Greeks indicator values for each contract.
  6. def greeks_and_iv(contracts, period, risk_free_rate_model, dividend_yield_model, option_model):
        # Get the call and put contract.
        call, put = sorted(contracts, key=lambda s: s.id.option_right)
        
        def get_values(indicator_class, contract, mirror_contract):
            return qb.indicator_history(
                indicator_class(contract, risk_free_rate_model, dividend_yield_model, mirror_contract, option_model), 
                [contract, mirror_contract, contract.underlying], 
                period
            ).data_frame.current
    
        return pd.DataFrame({
            'iv_call': get_values(ImpliedVolatility, call, put),
            'iv_put': get_values(ImpliedVolatility, put, call),
            'delta_call': get_values(Delta, call, put),
            'delta_put': get_values(Delta, put, call),
            'gamma_call': get_values(Gamma, call, put),
            'gamma_put': get_values(Gamma, put, call),
            'rho_call': get_values(Rho, call, put),
            'rho_put': get_values(Rho, put, call),
            'vega_call': get_values(Vega, call, put),
            'vega_put': get_values(Vega, put, call),
            'theta_call': get_values(Theta, call, put),
            'theta_put': get_values(Theta, put, call),
        })
    Dictionary<string, IndicatorHistory> GreeksAndIV(List<Symbol> contracts, int period)
    {
        // Get the call and put contract.
        var sortedSymbols = contracts.OrderBy(s => s.ID.OptionRight).ToArray();
        var call = sortedSymbols[0];
        var put = sortedSymbols[1];
        
        IndicatorHistory GetValues(OptionIndicatorBase indicator)
        {
            // Use both contracts and the underlying to update the indicator and get its value.
            return qb.IndicatorHistory(indicator, new[] { call, put, call.Underlying }, period);
        }
    
        // Get the values of all the IV and Greek indicators.
        return new Dictionary<string, IndicatorHistory>
        {
            {"IVCall", GetValues(new ImpliedVolatility(call, riskFreeRateModel, dividendYieldModel, put, optionModel))},
            {"IVPut", GetValues(new ImpliedVolatility(put, riskFreeRateModel, dividendYieldModel, call, optionModel))},
            {"DeltaCall", GetValues(new Delta(call, riskFreeRateModel, dividendYieldModel, put, optionModel))},
            {"DeltaPut", GetValues(new Delta(put, riskFreeRateModel, dividendYieldModel, call, optionModel))},
            {"GammaCall", GetValues(new Gamma(call, riskFreeRateModel, dividendYieldModel, put, optionModel))},
            {"GammaPut", GetValues(new Gamma(put, riskFreeRateModel, dividendYieldModel, call, optionModel))},
            {"VegaCall", GetValues(new Vega(call, riskFreeRateModel, dividendYieldModel, put, optionModel))},
            {"VegaPut", GetValues(new Vega(put, riskFreeRateModel, dividendYieldModel, call, optionModel))},
            {"ThetaCall", GetValues(new Theta(call, riskFreeRateModel, dividendYieldModel, put, optionModel))},
            {"ThetaPut", GetValues(new Theta(put, riskFreeRateModel, dividendYieldModel, call, optionModel))},
            {"RhoCall", GetValues(new Rho(call, riskFreeRateModel, dividendYieldModel, put, optionModel))},
            {"RhoPut", GetValues(new Rho(put, riskFreeRateModel, dividendYieldModel, call, optionModel))}
        };
    }
  7. Call the preceding method and display the results.
  8. greeks_and_iv([contract_symbol, mirror_contract_symbol], 15, risk_free_rate_model, dividend_yield_model, option_model)
    foreach (var (key, indicatorHistory) in GreeksAndIV(new List<Symbol> {contractSymbol, mirrorContractSymbol}, 15))
    {
        foreach (var dataPoint in indicatorHistory)
        {
            Console.WriteLine($"{dataPoint.EndTime} - {key}: {dataPoint.Current.Value}");
        }
    }
DataFrame result of the preceding code snippets, containing the greeks and IV history.

The DataFrame can have NaN entries if there is no data for the contracts or the underlying asset at a moment in time.

Examples

The following examples demonstrate some common practices for analyzing individual Index Option contracts in the Research Environment.

Example 1: Contract Trade History

The following notebook plots the historical prices of an SPX Index Option contract using PlotlyPlotly.NET:

#load "../Initialize.csx"
import plotly.graph_objects as go

# Get the SPX Option chain for January 1, 2024.
qb = QuantBook()
underlying_symbol = qb.add_index("SPX").symbol
qb.set_start_date(2024, 1, 1)
chain = qb.option_chain(
    Symbol.create_canonical_option(underlying_symbol, Market.USA, "?SPX"), flatten=True
).data_frame

# Select a contract from the chain.
expiry = chain.expiry.min()
contract_symbol = chain[
    (chain.expiry == expiry) & 
    (chain.right == OptionRight.CALL) &
    (chain.delta > 0.3) &
    (chain.delta < 0.7)
].sort_values('openinterest').index[-1]

# Add the target contract.
qb.add_index_option_contract(contract_symbol)

# Get the contract history.
history = qb.history(contract_symbol, timedelta(3))

# Plot the price history.
go.Figure(
    data=go.Candlestick(
        x=history.index.levels[4],
        open=history['open'],
        high=history['high'],
        low=history['low'],
        close=history['close']
    ), 
    layout=go.Layout(
        title=go.layout.Title(text=f'{contract_symbol.value} OHLC'),
        xaxis_title='Date',
        yaxis_title='Price',
        xaxis_rangeslider_visible=False
    )
).show()
#load "../QuantConnect.csx"
#r "../Plotly.NET.dll"

using QuantConnect;
using QuantConnect.Data;
using QuantConnect.Algorithm;
using QuantConnect.Research;
using QuantConnect.Indicators;
using QuantConnect.Data.Market;
using QuantConnect.Securities.Option;
using Plotly.NET;
using Plotly.NET.LayoutObjects;

// Get the SPX Option chain for January 1, 2024.
var qb = new QuantBook();
var underlyingSymbol = qb.AddIndex("SPX").Symbol;
qb.SetStartDate(2024, 1, 1);
var chain = qb.OptionChain(
    QuantConnect.Symbol.CreateCanonicalOption(underlyingSymbol, Market.USA, "?SPX")
);

// Select a contract from the chain.
var expiry = chain.Select(contract => contract.Expiry).Min();
var contractSymbol = chain
    .Where(contract => 
        contract.Expiry == expiry && 
        contract.Right == OptionRight.Call &&
        contract.Greeks.Delta > 0.3m && 
        contract.Greeks.Delta < 0.7m
    )
    .OrderByDescending(contract => contract.OpenInterest)
    .First()
    .Symbol;

// Add the target contract.
qb.AddIndexOptionContract(contractSymbol);

// Get the contract history.
var history = qb.History<TradeBar>(contractSymbol, TimeSpan.FromDays(3));

// Plot the price history.
var chart = Chart2D.Chart.Candlestick<decimal, decimal, decimal, decimal, DateTime, string>(
    history.Select(x => x.Open),
    history.Select(x => x.High),
    history.Select(x => x.Low),
    history.Select(x => x.Close),
    history.Select(x => x.EndTime)
);
LinearAxis xAxis = new LinearAxis();
xAxis.SetValue("title", "Time");
LinearAxis yAxis = new LinearAxis();
yAxis.SetValue("title", "Price ($)");
Title title = Title.init($"{contractSymbol} Price");
Layout layout = new Layout();
layout.SetValue("xaxis", xAxis);
layout.SetValue("yaxis", yAxis);
layout.SetValue("title", title);
chart.WithLayout(layout);
HTML(GenericChart.toChartHTML(chart))
Candlestick plot of the prices for an SPX Index Option contract Candlestick plot of the prices for an SPX Index Option contract

Example 2: Contract Open Interest History

The following notebook plots the historical open interest of a VIXW Index Option contract using MatplotlibPlotly.NET:

#load "../Initialize.csx"
# Get the VIX weekly Option chain for January 1, 2024.
qb = QuantBook()
underlying_symbol = qb.add_index("VIX").symbol
qb.set_start_date(2024, 1, 1)
chain = qb.option_chain(
    Symbol.create_canonical_option(underlying_symbol, "VIXW", Market.USA, "?VIXW"), flatten=True 
).data_frame

# Select a contract from the chain.
strike_distance = (chain.strike - chain.underlyinglastprice).abs()
target_strike_distance = strike_distance.min()
chain = chain.loc[strike_distance[strike_distance == target_strike_distance].index]
contract_symbol = chain.sort_values('openinterest').index[-1]

# Add the target contract.
qb.add_index_option_contract(contract_symbol, fill_forward=False)

# Get the contract's open interest history.
history = qb.history(OpenInterest, contract_symbol, timedelta(90))
history.index = history.index.droplevel([0, 1, 2])
history = history['openinterest'].unstack(0)[contract_symbol]

# Plot the open interest history.
history.plot(title=f'{contract_symbol.value} Open Interest')
plt.show()
#load "../QuantConnect.csx"
#r "../Plotly.NET.dll"

using QuantConnect;
using QuantConnect.Data;
using QuantConnect.Algorithm;
using QuantConnect.Research;
using QuantConnect.Indicators;
using QuantConnect.Data.Market;
using QuantConnect.Securities.Option;
using Plotly.NET;
using Plotly.NET.LayoutObjects;

// Get the VIX weekly Option chain for January 1, 2024.
var qb = new QuantBook();
var underlyingSymbol = qb.AddIndex("VIX").Symbol;
qb.SetStartDate(2024, 1, 1);
var chain = qb.OptionChain(
    QuantConnect.Symbol.CreateCanonicalOption(underlyingSymbol, "VIXW", Market.USA, "?VIXW")
);

// Select a contract from the chain.
var targetStrikeDistance = chain
    .Select(contract => Math.Abs(contract.Strike - contract.UnderlyingLastPrice))
    .Min();
var contractSymbol = chain
    .Where(contract => Math.Abs(contract.Strike - contract.UnderlyingLastPrice) == targetStrikeDistance)
    .OrderBy(contract => contract.OpenInterest)
    .Last()
    .Symbol;

// Add the target contract.
qb.AddIndexOptionContract(contractSymbol, fillForward: false);

// Get the contract's open interest history.
var history = qb.History<OpenInterest>(contractSymbol, TimeSpan.FromDays(90));

// Plot the open interest history.
var chart = Chart2D.Chart.Line<DateTime, decimal, string>(
    history.Select(x => x.EndTime),
    history.Select(x => x.Value)
);
LinearAxis xAxis = new LinearAxis();
xAxis.SetValue("title", "Time");
LinearAxis yAxis = new LinearAxis();
yAxis.SetValue("title", "Open Interest");
Title title = Title.init($"{contractSymbol.Value} Open Interest");
Layout layout = new Layout();
layout.SetValue("xaxis", xAxis);
layout.SetValue("yaxis", yAxis);
layout.SetValue("title", title);
chart.WithLayout(layout);
HTML(GenericChart.toChartHTML(chart))
Line plot of the open interest for a VIWX Index Option contract Line plot of the open interest for a VIXW Index Option contract

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: