Datasets

Equity Options

Introduction

This page explains how to request, manipulate, and visualize historical Equity Options data.

Create Subscriptions

Follow these steps to subscribe to an Equity Option security:

  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.Securities.Option;
    using Microsoft.Data.Analysis;
  5. Create a QuantBook.
  6. var qb = new QuantBook();
    qb = QuantBook()
  7. Subscribe to the underlying Equity with raw data normalization and save a reference to the Equity Symbol.
  8. var equitySymbol = qb.AddEquity("SPY", dataNormalizationMode: DataNormalizationMode.Raw).Symbol;
    equity_symbol = qb.add_equity("SPY", data_normalization_mode=DataNormalizationMode.RAW).symbol

    To view the supported underlying assets in the US Equity Options dataset, see the Data Explorer.

  9. Call the AddOption method with the underlying Equity Symbol.
  10. var option = qb.AddOption(equitySymbol);
    option = qb.add_option(equity_symbol)
  11. (Optional) Set a contract filter.
  12. option.set_filter(-1, 1, 0, 90);
    option.set_filter(-1, 1, 0, 90)

    The filter determines which contracts the OptionHistory method returns. If you don't set a filter, the default filter selects the contracts that have the following characteristics:

    • Standard type (exclude weeklys)
    • Within 1 strike price of the underlying asset price
    • Expire within 31 days
  13. (Optional) Set the price model.
  14. option.price_model = OptionPriceModels.binomial_cox_ross_rubinstein();
    option.price_model = OptionPriceModels.binomial_cox_ross_rubinstein()

If you want historical data on individual contracts and their OpenInterest, follow these steps to subscribe to the individual Equity Option contracts:

  1. Call the GetOptionsContractList method with the underlying Equity Symbol and a datetimeDateTime.
  2. var startDate = new DateTime(2021, 12, 31);
    var contractSymbols = qb.OptionChainProvider.GetOptionContractList(equitySymbol, startDate);
    start_date = datetime(2021, 12, 31)
    contract_symbols = qb.option_chain_provider.get_option_contract_list(equity_symbol, start_date)

    This method returns a list of Symbol objects that reference the Option contracts that were trading at the given time. If you set a contract filter with SetFilter, it doesn't affect the results of GetOptionsContractList.

  3. Select the Symbol of the OptionContract object(s) for which you want to get historical data.
  4. To filter and select contracts, you can use the following properties of each Symbol object:

    PropertyDescription
    ID.DateThe expiration date of the contract.
    ID.StrikePriceThe strike price of the contract.
    ID.OptionRight The contract type. The OptionRight enumeration has the following members:
    ID.OptionStyle The contract style. The OptionStyle enumeration has the following members:
    var contractSymbol = contractSymbols.Where(s => 
        s.ID.OptionRight == OptionRight.Call &&
        s.ID.StrikePrice == 477 &&
        s.ID.Date == new DateTime(2022, 1, 21)).First();
    contract_symbol = [s for s in contract_symbols 
        if s.id.option_right == OptionRight.CALL 
            and s.id.strike_price == 477 
            and s.id.date == datetime(2022, 1, 21)][0]
  5. Call the AddOptionContract method with an OptionContract Symbol and disable fill-forward.
  6. var optionContract = qb.AddOptionContract(contractSymbol, fillForward: false);
    option_contract = qb.add_option_contract(contract_symbol, fill_forward = False)

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

  7. (Optional) Set the price model.
  8. optionContract.PriceModel = OptionPriceModels.BinomialCoxRossRubinstein();
    option_contract.price_model = OptionPriceModels.binomial_cox_ross_rubinstein()

Get Historical Data

You need a subscription before you can request historical data for Equity Option contracts. On the time dimension, you can request an amount of historical data based on a trailing number of bars, a trailing period of time, or a defined period of time. On the contract dimension, you can request historical data for a single contract, a subset of the contracts you created subscriptions for in your notebook, or all of the contracts in your notebook.

Before you request historical data, call the SetStartDate method with a datetimeDateTime to reduce the risk of look-ahead bias.

qb.SetStartDate(startDate);
qb.set_start_date(start_date)

If you call the SetStartDate method, the date that you pass to the method is the latest date for which your history requests will return data.

Trailing Number of Bars

To get historical data for a number of trailing bars, call the History method with the contract Symbol object(s) and an integer.

// Slice objects
var singleHistorySlice = qb.History(contractSymbol, 10);
var subsetHistorySlice = qb.History(new[] {contractSymbol}, 10);
var allHistorySlice = qb.History(10);

// TradeBar objects
var singleHistoryTradeBars = qb.History<TradeBar>(contractSymbol, 10);
var subsetHistoryTradeBars = qb.History<TradeBar>(new[] {contractSymbol}, 10);
var allHistoryTradeBars = qb.History<TradeBar>(qb.Securities.Keys, 10);

// QuoteBar objects
var singleHistoryQuoteBars = qb.History<QuoteBar>(contractSymbol, 10);
var subsetHistoryQuoteBars = qb.History<QuoteBar>(new[] {contractSymbol}, 10);
var allHistoryQuoteBars = qb.History<QuoteBar>(qb.Securities.Keys, 10);

// OpenInterest objects
var singleHistoryOpenInterest = qb.History<OpenInterest>(contractSymbol, 400);
var subsetHistoryOpenInterest = qb.History<OpenInterest>(new[] {contractSymbol}, 400);
var allHistoryOpenInterest = qb.History<OpenInterest>(qb.Securities.Keys, 400);
# DataFrame of trade and quote data
single_history_df = qb.history(contract_symbol, 10)
subset_history_df = qb.history([contract_symbol], 10)
all_history_df = qb.history(qb.securities.keys, 10)

# DataFrame of trade data
single_history_trade_bar_df = qb.history(TradeBar, contract_symbol, 10)
subset_history_trade_bar_df = qb.history(TradeBar, [contract_symbol], 10)
all_history_trade_bar_df = qb.history(TradeBar, qb.securities.keys, 10)

# DataFrame of quote data
single_history_quote_bar_df = qb.history(QuoteBar, contract_symbol, 10)
subset_history_quote_bar_df = qb.history(QuoteBar, [contract_symbol], 10)
all_history_quote_bar_df = qb.history(QuoteBar, qb.securities.keys, 10)

# DataFrame of open interest data
single_history_open_interest_df = qb.history(OpenInterest, contract_symbol, 400)
subset_history_open_interest_df = qb.history(OpenInterest, [contract_symbol], 400)
all_history_open_interest_df = qb.history(OpenInterest, qb.securities.keys, 400)

# Slice objects
all_history_slice = qb.history(10)

# TradeBar objects
single_history_trade_bars = qb.history[TradeBar](contract_symbol, 10)
subset_history_trade_bars = qb.history[TradeBar]([contract_symbol], 10)
all_history_trade_bars = qb.history[TradeBar](qb.securities.keys, 10)

# QuoteBar objects
single_history_quote_bars = qb.history[QuoteBar](contract_symbol, 10)
subset_history_quote_bars = qb.history[QuoteBar]([contract_symbol], 10)
all_history_quote_bars = qb.history[QuoteBar](qb.securities.keys, 10)

# OpenInterest objects
single_history_open_interest = qb.history[OpenInterest](contract_symbol, 400)
subset_history_open_interest = qb.history[OpenInterest]([contract_symbol], 400)
all_history_open_interest = qb.history[OpenInterest](qb.securities.keys, 400)

The preceding calls return the most recent bars, excluding periods of time when the exchange was closed.

Trailing Period of Time

To get historical data for a trailing period of time, call the History method with the contract Symbol object(s) and a TimeSpantimedelta.

// Slice objects
var singleHistorySlice = qb.History(contractSymbol, TimeSpan.FromDays(3));
var subsetHistorySlice = qb.History(new[] {contractSymbol}, TimeSpan.FromDays(3));
var allHistorySlice = qb.History(10);

// TradeBar objects
var singleHistoryTradeBars = qb.History<TradeBar>(contractSymbol, TimeSpan.FromDays(3));
var subsetHistoryTradeBars = qb.History<TradeBar>(new[] {contractSymbol}, TimeSpan.FromDays(3));
var allHistoryTradeBars = qb.History<TradeBar>(TimeSpan.FromDays(3));

// QuoteBar objects
var singleHistoryQuoteBars = qb.History<QuoteBar>(contractSymbol, TimeSpan.FromDays(3), Resolution.Minute);
var subsetHistoryQuoteBars = qb.History<QuoteBar>(new[] {contractSymbol}, TimeSpan.FromDays(3), Resolution.Minute);
var allHistoryQuoteBars = qb.History<QuoteBar>(qb.Securities.Keys, TimeSpan.FromDays(3), Resolution.Minute);


// OpenInterest objects
var singleHistoryOpenInterest = qb.History<OpenInterest>(contractSymbol, TimeSpan.FromDays(2));
var subsetHistoryOpenInterest = qb.History<OpenInterest>(new[] {contractSymbol}, TimeSpan.FromDays(2));
var allHistoryOpenInterest = qb.History<OpenInterest>(qb.Securities.Keys, TimeSpan.FromDays(2));
# DataFrame of trade and quote data
single_history_df = qb.history(contract_symbol, timedelta(days=3))
subset_history_df = qb.history([contract_symbol], timedelta(days=3))
all_history_df = qb.history(qb.securities.keys, timedelta(days=3))

# DataFrame of trade data
single_history_trade_bar_df = qb.history(TradeBar, contract_symbol, timedelta(days=3))
subset_history_trade_bar_df = qb.history(TradeBar, [contract_symbol], timedelta(days=3))
all_history_trade_bar_df = qb.history(TradeBar, qb.securities.keys, timedelta(days=3))

# DataFrame of quote data
single_history_quote_bar_df = qb.history(QuoteBar, contract_symbol, timedelta(days=3))
subset_history_quote_bar_df = qb.history(QuoteBar, [contract_symbol], timedelta(days=3))
all_history_quote_bar_df = qb.history(QuoteBar, qb.securities.keys, timedelta(days=3))

# DataFrame of open interest data
single_history_open_interest_df = qb.history(OpenInterest, contract_symbol, timedelta(days=3))
subset_history_open_interest_df = qb.history(OpenInterest, [contract_symbol], timedelta(days=3))
all_history_open_interest_df = qb.history(OpenInterest, qb.securities.keys, timedelta(days=3))

# Slice objects
all_history_slice = qb.history(timedelta(days=3))

# TradeBar objects
single_history_trade_bars = qb.history[TradeBar](contract_symbol, timedelta(days=3))
subset_history_trade_bars = qb.history[TradeBar]([contract_symbol], timedelta(days=3))
all_history_trade_bars = qb.history[TradeBar](qb.securities.keys, timedelta(days=3))

# QuoteBar objects
single_history_quote_bars = qb.history[QuoteBar](contract_symbol, timedelta(days=3), Resolution.MINUTE)
subset_history_quote_bars = qb.history[QuoteBar]([contract_symbol], timedelta(days=3), Resolution.MINUTE)
all_history_quote_bars = qb.history[QuoteBar](qb.securities.keys, timedelta(days=3), Resolution.MINUTE) 


# OpenInterest objects
single_history_open_interest = qb.history[OpenInterest](contract_symbol, timedelta(days=2))
subset_history_open_interest = qb.history[OpenInterest]([contract_symbol], timedelta(days=2))
all_history_open_interest = qb.history[OpenInterest](qb.securities.keys, timedelta(days=2))

The preceding calls return the most recent bars, excluding periods of time when the exchange was closed.

Defined Period of Time

To get historical data for individual Equity Option contracts during a specific period of time, call the History method with the Equity Option contract Symbol object(s), a start DateTimedatetime, and an end DateTimedatetime. The start and end times you provide are based in the notebook time zone.

var startTime = new DateTime(2021, 12, 1);
var endTime = new DateTime(2021, 12, 31);

// Slice objects
var singleHistorySlice = qb.History(contractSymbol, startTime, endTime);
var subsetHistorySlice = qb.History(new[] {contractSymbol}, startTime, endTime);
var allHistorySlice = qb.History(startTime, endTime);

// TradeBar objects
var singleHistoryTradeBars = qb.History<TradeBar>(contractSymbol, startTime, endTime);
var subsetHistoryTradeBars = qb.History<TradeBar>(new[] {contractSymbol}, startTime, endTime);
var allHistoryTradeBars = qb.History<TradeBar>(qb.Securities.Keys, startTime, endTime);

// QuoteBar objects
var singleHistoryQuoteBars = qb.History<QuoteBar>(contractSymbol, startTime, endTime, Resolution.Minute);
var subsetHistoryQuoteBars = qb.History<QuoteBar>(new[] {contractSymbol}, startTime, endTime, Resolution.Minute);
var allHistoryQuoteBars = qb.History<QuoteBar>(qb.Securities.Keys, startTime, endTime, Resolution.Minute);


// OpenInterest objects
var singleHistoryOpenInterest = qb.History<OpenInterest>(contractSymbol, startTime, endTime);
var subsetHistoryOpenInterest = qb.History<OpenInterest>(new[] {contractSymbol}, startTime, endTime);
var allHistoryOpenInterest = qb.History<OpenInterest>(qb.Securities.Keys, startTime, endTime);
start_time = datetime(2021, 12, 1)
end_time = datetime(2021, 12, 31)

# DataFrame of trade and quote data
single_history_df = qb.history(contract_symbol, start_time, end_time)
subset_history_df = qb.history([contract_symbol], start_time, end_time)
all_history_df = qb.history(qb.securities.keys, start_time, end_time)

# DataFrame of trade data
single_history_trade_bar_df = qb.history(TradeBar, contract_symbol, start_time, end_time)
subset_history_trade_bar_df = qb.history(TradeBar, [contract_symbol], start_time, end_time)
all_history_trade_bar_df = qb.history(TradeBar, qb.securities.keys, start_time, end_time)

# DataFrame of quote data
single_history_quote_bar_df = qb.history(QuoteBar, contract_symbol, start_time, end_time)
subset_history_quote_bar_df = qb.history(QuoteBar, [contract_symbol], start_time, end_time)
all_history_quote_bar_df = qb.history(QuoteBar, qb.securities.keys, start_time, end_time)

# DataFrame of open interest data
single_history_open_interest_df = qb.history(OpenInterest, contract_symbol, start_time, end_time)
subset_history_open_interest_df = qb.history(OpenInterest, [contract_symbol], start_time, end_time)
all_history_trade_open_interest_df = qb.history(OpenInterest, qb.securities.keys, start_time, end_time)

# TradeBar objects
single_history_trade_bars = qb.history[TradeBar](contract_symbol, start_time, end_time)
subset_history_trade_bars = qb.history[TradeBar]([contract_symbol], start_time, end_time)
all_history_trade_bars = qb.history[TradeBar](qb.securities.keys, start_time, end_time)

# QuoteBar objects
single_history_quote_bars = qb.history[QuoteBar](contract_symbol, start_time, end_time, Resolution.MINUTE)
subset_history_quote_bars = qb.history[QuoteBar]([contract_symbol], start_time, end_time, Resolution.MINUTE)
all_history_quote_bars = qb.history[QuoteBar](qb.securities.keys, start_time, end_time, Resolution.MINUTE)


# OpenInterest objects
single_history_open_interest = qb.history[OpenInterest](contract_symbol, start_time, end_time)
subset_history_open_interest = qb.history[OpenInterest]([contract_symbol], start_time, end_time)
all_history_open_interest = qb.history[OpenInterest](qb.securities.keys, start_time, end_time)

To get historical data for all of the Equity Option contracts that pass your filter during a specific period of time, call the OptionHistory method with the underlying Equity Symbol object, a start DateTimedatetime, and an end DateTimedatetime.

option_history = qb.option_history(equity_symbol, end_time-timedelta(days=2), end_time, Resolution.MINUTE, fillForward=False, extendedMarketHours=False)
var optionHistory = qb.OptionHistory(equitySymbol, endTime-TimeSpan.FromDays(2), endTime, Resolution.Minute, fillForward: False, extendedMarketHours: False);

The preceding calls return data that have a timestamp within the defined period of time.

Resolutions

The following table shows the available resolutions and data formats for Equity Option contract subscriptions:

ResolutionTradeBarQuoteBarTrade TickQuote Tick
Tick

Second

Minutegreen checkgreen check
Hourgreen checkgreen check
Dailygreen checkgreen check

Markets

LEAN groups all of the US Equity Option exchanges under Market.USA, so you don't need to pass a Market to the AddOption or AddOptionContract methods.

Data Normalization

The data normalization mode doesn't affect data from history request. By default, LEAN doesn't adjust Equity Options data for splits and dividends of their underlying. If you change the data normalization mode, it won't change the outcome.

Wrangle Data

You need some historical data to perform wrangling operations. The process to manipulate the historical data depends on its data type. To display pandas objects, run a cell in a notebook with the pandas object as the last line. To display other data formats, call the print method.

You need some historical data to perform wrangling operations. Use LINQ to wrangle the data and then call the Console.WriteLine method in a Jupyter Notebook to display the data. The process to manipulate the historical data depends on its data type.

DataFrame Objects

If your history request returns a DataFrame, the DataFrame has the following index levels:

  1. Contract expiry
  2. Contract strike price
  3. Contract type (call or put)
  4. Encoded contract Symbol
  5. The EndTime of the data sample

The columns of the DataFrame are the data properties. Depending on how you request data, the DataFrame may contain data for the underlying security, which causes some of the index levels to be an empty string for the corresponding rows.

Historical data dataframe

To select the rows of the contract(s) that expire at a specific time, index the loc property of the DataFrame with the expiry time.

all_history_df.loc[datetime(2022, 1, 21)]
Historical data dataframe of selected date

If you remove the first three index levels, you can index the DataFrame with just the contract Symbol, similiar to how you would with non-derivative asset classes. To remove the first three index levels, call the droplevel method.

all_history_df.index = all_history_df.index.droplevel([0,1,2])
Historical data dataframe of dropped first column

To select the historical data of a single Equity Options contract, index the loc property of the DataFrame with the contract Symbol.

all_history_df.loc[contract_symbol]
DataFrame of one Equity Options

To select a column of the DataFrame, index it with the column name.

all_history_df.loc[contract_symbol]['close']
Series of close values

If you request historical data for multiple Equity Option contracts, you can transform the DataFrame so that it's a time series of close values for all of the Equity Option contracts. To transform the DataFrame, select the column you want to display for each Equity Option contract and then call the unstack method.

all_history_df['close'].unstack(level=0)

The DataFrame is transformed so that the column indices are the Symbol of each security and each row contains the close value.

Historical data dataframe with column indexed by symbols

The historical data methods don't return DataFrame objects, but you can create one for efficient vectorized data wrangling.

using Microsoft.Data.Analysis; 

var columns = new DataFrameColumn[] {
    new PrimitiveDataFrameColumn("Time", history.Select(x => x[contractSymbol].EndTime)),
    new DecimalDataFrameColumn(" Open", history.Select(x => x[contractSymbol].Open)),
    new DecimalDataFrameColumn(" High", history.Select(x => x[contractSymbol].High)),
    new DecimalDataFrameColumn(" Low", history.Select(x => x[contractSymbol].Low)),
    new DecimalDataFrameColumn(" Close", history.Select(x => x[contractSymbol].Close))
};
var df = new DataFrame(columns);
df
Historical C# dataframe

To select a particular column of the DataFrame, index it with the column name.

df[" close"]
Historical C# dataframe column

Slice Objects

If the History method returns Slice objects, iterate through the Slice objects to get each one. The Slice objects may not have data for all of your Equity Options subscriptions. To avoid issues, check if the Slice contains data for your Equity Option contract before you index it with the Equity Options Symbol.

foreach (var slice in allHistorySlice) {
    if (slice.Bars.ContainsKey(contractSymbol))
    {
        var tradeBar = slice.Bars[contractSymbol];
    }
    if (slice.QuoteBars.ContainsKey(contractSymbol))
    {
        var quoteBar = slice.QuoteBars[contractSymbol];
    }
}
for slice in all_history_slice:
        if slice.bars.contains_key(contract_symbol):
        trade_bar = slice.bars[contract_symbol]
    if slice.quote_bars.contains_key(contract_symbol):
        quote_bar = slice.quote_bars[contract_symbol]

You can also iterate through each TradeBar and QuoteBar in the Slice.

foreach (var slice in allHistorySlice)
{
    foreach (var kvp in slice.Bars)
    {
        var symbol = kvp.Key;
        var tradeBar = kvp.Value;
    }
    foreach (var kvp in slice.QuoteBars)
    {
        var symbol = kvp.Key;
        var quoteBar = kvp.Value;
    }
}
for slice in all_history_slice:
    for kvp in slice.bars:
        symbol = kvp.key
        trade_bar = kvp.value
    for kvp in slice.quote_bars:
        symbol = kvp.key
        quote_bar = kvp.value

You can also use LINQ to select each TradeBar in the Slice for a given Symbol.

var tradeBars = allHistorySlice.Where(slice => slice.Bars.ContainsKey(contractSymbol)).Select(slice => slice.Bars[contractSymbol]);

TradeBar Objects

If the History method returns TradeBar objects, iterate through the TradeBar objects to get each one.

foreach (var tradeBar in singleHistoryTradeBars)
{
    Console.WriteLine(tradeBar);
}
for trade_bar in single_history_trade_bars:
    print(trade_bar)

If the History method returns TradeBars, iterate through the TradeBars to get the TradeBar of each Equity Option contract. The TradeBars may not have data for all of your Equity Options subscriptions. To avoid issues, check if the TradeBars object contains data for your security before you index it with the Equity Options Symbol.

foreach (var tradeBars in allHistoryTradeBars)
{
    if (tradeBars.ContainsKey(contractSymbol))
    {
        var tradeBar = tradeBars[contractSymbol];
    }
}
for trade_bars in all_history_trade_bars:
    if trade_bars.contains_key(contract_symbol):
        trade_bar = trade_bars[contract_symbol]

You can also iterate through each of the TradeBars.

foreach (var tradeBars in allHistoryTradeBars)
{
    foreach (var kvp in tradeBars)
    {
        var symbol = kvp.Key;
        var tradeBar = kvp.Value;
    }
}
for trade_bars in all_history_trade_bars:
    for kvp in trade_bars:
        symbol = kvp.Key
        trade_bar = kvp.Value

QuoteBar Objects

If the History method returns QuoteBar objects, iterate through the QuoteBar objects to get each one.

foreach (var quoteBar in singleHistoryQuoteBars)
{
    Console.WriteLine(quoteBar);
}
for quote_bar in single_history_quote_bars:
    print(quote_bar)

If the History method returns QuoteBars, iterate through the QuoteBars to get the QuoteBar of each Equity Option contract. The QuoteBars may not have data for all of your Equity Options subscriptions. To avoid issues, check if the QuoteBars object contains data for your security before you index it with the Equity Options Symbol.

foreach (var quoteBars in allHistoryQuoteBars)
{
    if (quoteBars.ContainsKey(contractSymbol))
    {
        var quoteBar = quoteBars[contractSymbol];
    }
}
for quote_bars in all_history_quote_bars:
    if quote_bars.contains_key(contract_symbol):
        quote_bar = quote_bars[contract_symbol]

You can also iterate through each of the QuoteBars.

foreach (var quoteBars in allHistoryQuoteBars)
{
    foreach (var kvp in quoteBars)
    {
        var symbol = kvp.Key;
        var quoteBar = kvp.Value;
    }
}
for quote_bars in all_history_quote_bars:
    for kvp in quote_bars:
        symbol = kvp.key
        quote_bar = kvp.value

OpenInterest Objects

If the History method returns OpenInterest objects, iterate through the OpenInterest objects to get each one.

foreach (var openInterest in singleHistoryOpenInterest)
{
    Console.WriteLine(openInterest);
}
for open_interest in single_history_open_interest:
    print(open_interest)

If the History method returns a dictionary of OpenInterest objects, iterate through the dictionary to get the OpenInterest of each Equity Option contract. The dictionary of OpenInterest objects may not have data for all of your Equity Options contract subscriptions. To avoid issues, check if the dictionary contains data for your contract before you index it with the Equity Options contract Symbol.

foreach (var openInterestDict in allHistoryOpenInterest)
{
    if (openInterestDict.ContainsKey(contractSymbol))
    {
        var openInterest = openInterestDict[contractSymbol];
    }
}
for open_interest_dict in all_history_open_interest:
    if open_interest_dict.contains_key(contract_symbol):
        open_interest = open_interest_dict[contract_symbol]

You can also iterate through each of the OpenInterest dictionaries.

foreach (var openInterestDict in allHistoryOpenInterest)
{
    foreach (var kvp in openInterestDict)
    {
        var symbol = kvp.Key;
        var openInterest = kvp.Value;
    }
}
for open_interest_dict in all_history_open_interest:
    for kvp in open_interest_dict:
        symbol = kvp.key
        open_interest = kvp.value

OptionHistory Objects

The OptionHistory method returns an OptionHistory object. To get each slice in the OptionHistory object, iterate through it.

foreach (var slice in optionHistory)
{
    foreach (var kvp in slice.OptionChains)
    {
        var canonicalSymbol = kvp.Key;
        var chain = kvp.Value;
        foreach (var contract in chain)
        {
            
        }
    }
}
for slice in option_history:
    for canonical_symbol, chain in slice.option_chains.items(): 
        for contract in chain:
            pass

To convert the OptionHistory object to a DataFrame that contains the trade and quote information of each contract and the underlying, call the GetAllData method.

option_history.get_all_data()

To get the expiration dates of all the contracts in an OptionHistory object, call the GetExpiryDates method.

option_history.get_expiry_dates()

To get the strike prices of all the contracts in an OptionHistory object, call the GetStrikes method.

option_history.get_strikes()

Plot Data

You need some historical Equity Options data to produce plots. You can use many of the supported plotting librariesPlot.NET package to visualize data in various formats. For example, you can plot candlestick and line charts.

Candlestick Chart

Follow these steps to plot candlestick charts:

  1. Get some historical data.
  2. history = qb.history(contract_symbol, datetime(2021, 12, 30), datetime(2021, 12, 31))
    var history = qb.History<TradeBar>(contractSymbol, new DateTime(2021, 12, 30), new DateTime(2021, 12, 31));
  3. Drop the first four index levels of the DataFrame that returns.
  4. history.index = history.index.droplevel([0,1,2,3])
  5. Import the plotlyPlot.NET library.
  6. import plotly.graph_objects as go
    #r "../Plotly.NET.dll"
    using Plotly.NET;
    using Plotly.NET.LayoutObjects;
  7. Create a Candlestick.
  8. candlestick = go.Candlestick(x=history.index,
                                 open=history['open'],
                                 high=history['high'],
                                 low=history['low'],
                                 close=history['close'])
    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)
    );
  9. Create a Layout.
  10. layout = go.Layout(title=go.layout.Title(text=f'{symbol.value} OHLC'),
                       xaxis_title='Date',
                       yaxis_title='Price',
                       xaxis_rangeslider_visible=False)
    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);
  11. Create the Figure.
  12. fig = go.Figure(data=[candlestick], layout=layout)
  13. Assign the Layout to the chart.
  14. chart.WithLayout(layout);
  15. Show the plot.
  16. fig.show()
    HTML(GenericChart.toChartHTML(chart))

    The Jupyter Notebook displays a candlestick chart of the Option contract's price.

Candlestick shart of a contract's price Candlestick shart of a contract's price

Line Chart

Follow these steps to plot line charts using built-in methodsPlotly.NET package:

  1. Get some historical data.
  2. history = qb.history(OpenInterest, contract_symbol, datetime(2021, 12, 1), datetime(2021, 12, 31))
    var history = qb.History<OpenInterest>(contract_symbol, new DateTime(2021, 12, 1), new DateTime(2021, 12, 31));
  3. Drop the first three index levels of the DataFrame that returns.
  4. history.index = history.index.droplevel([0, 1, 2])
  5. Select the open interest data.
  6. history = history['openinterest'].unstack(level=0)
  7. Rename the column to the Symbol of the contract.
  8. history.columns = [
        Symbol.get_alias(SecurityIdentifier.parse(x), equity_symbol)
            for x in history.columns]
  9. Call the plot method with a title.
  10. history.plot(title="Open Interest")
  11. Create a Line chart.
  12. var chart = Chart2D.Chart.Line<DateTime, decimal, string>(
        history.Select(x => x.EndTime),
        history.Select(x => x.Value)
    );
  13. Create a Layout.
  14. LinearAxis xAxis = new LinearAxis();
    xAxis.SetValue("title", "Time");
    LinearAxis yAxis = new LinearAxis();
    yAxis.SetValue("title", "Open Interest");
    Title title = Title.init("SPY Open Interest");
    
    Layout layout = new Layout();
    layout.SetValue("xaxis", xAxis);
    layout.SetValue("yaxis", yAxis);
    layout.SetValue("title", title);
  15. Assign the Layout to the chart.
  16. chart.WithLayout(layout);
  17. Show the plot.
  18. plt.show()
    HTML(GenericChart.toChartHTML(chart))

    The Jupyter Notebook displays a line chart of open interest data.

Line chart of open interest Line chart of open interest

Get Price Model Data

Follow these steps to get the values of implied volatility, and Greeks:

  1. Create subscriptions.
  2. equity_symbol = qb.AddEquity("SPY", dataNormalizationMode=DataNormalizationMode.Raw).Symbol
    
    start_date = datetime(2021, 12, 31)
    contract_list = qb.OptionChainProvider.GetOptionContractList(equity_symbol, start_date)
    
    contract_symbols = [s for s in contract_list 
        if s.ID.OptionRight == OptionRight.Call
            and s.ID.Date == datetime(2022, 1, 21)
            and 450 <= s.ID.StrikePrice <= 500]
    mirror_symbols = [s for s in contract_list 
        if s.ID.OptionRight == OptionRight.Put
            and s.ID.Date == datetime(2022, 1, 21)
            and 450 <= s.ID.StrikePrice <= 500]
    
    # make sure the contracts are aligned by strike prices
    option_contracts = sorted([qb.AddOptionContract(contract_symbol, fillForward = False).Symbol for contract_symbol in contract_symbols], key=lambda x: x.ID.StrikePrice)
    mirror_contracts = sorted([qb.AddOptionContract(mirror_symbol, fillForward = False).Symbol for mirror_symbol in mirror_symbols], key=lambda x: x.ID.StrikePrice)
    var equitySymbol = qb.AddEquity("SPY", dataNormalizationMode: DataNormalizationMode.Raw).Symbol;
    
    var startDate = new DateTime(2021, 12, 31);
    var contractList = qb.OptionChainProvider.GetOptionContractList(equitySymbol, startDate);
    
    var contractSymbols = contractList.Where(s => 
        s.ID.OptionRight == OptionRight.Call &&
        s.ID.StrikePrice <= 500 &&
        s.ID.StrikePrice >= 450 &&
        s.ID.Date == new DateTime(2022, 1, 21));
    var mirrorSymbols = contractList.Where(s => 
        s.ID.OptionRight == OptionRight.Put &&
        s.ID.StrikePrice <= 500 &&
        s.ID.StrikePrice >= 450 &&
        s.ID.Date == new DateTime(2022, 1, 21));
    
    // make sure the contracts are aligned by strike prices
    var optionContracts = contractSymbols.OrderBy(x => x.ID.StrikePrice).Select(x => qb.AddOptionContract(x, fillForward: false).Symbol).ToList();
    var mirrorContracts = mirrorSymbols.OrderBy(x => x.ID.StrikePrice).Select(x => qb.AddOptionContract(x, fillForward: false).Symbol).ToList();
  3. Get historical data for the underlying Equity and the Option contract(s).
  4. qb.set_start_date(start_date)
    history = qb.history[QuoteBar]([equity_symbol] + option_contracts + mirror_contracts, 20, Resolution.MINUTE)
    qb.SetStartDate(startDate);
    var symbols = new List<Symbol> { equitySymbol };
    var history = qb.History<QuoteBar>(symbols.Concat(optionContracts).Concat(mirrorContracts), 20, Resolution.Minute);
  5. Set up Option Indicators, with the chosen option pricing model.
  6. iv = {}
    delta = {}
    gamma = {}
    vega = {}
    theta = {}
    rho = {}
    
    for option_contract, mirror_contract in zip(option_contracts, mirror_contracts):
        strike = option_contract.id.strike_price
    
        iv[strike] = ImpliedVolatility(option_contract, mirror_option=mirror_contract, option_model=OptionPricingModelType.FORWARD_TREE)
        delta[strike] = Delta(option_contract, mirror_option=mirror_contract, option_model=OptionPricingModelType.FORWARD_TREE)
        gamma[strike] = Gamma(option_contract, mirror_option=mirror_contract, option_model=OptionPricingModelType.FORWARD_TREE)
        vega[strike] = Vega(option_contract, mirror_option=mirror_contract, option_model=OptionPricingModelType.FORWARD_TREE)
        theta[strike] = Theta(option_contract, mirror_option=mirror_contract, option_model=OptionPricingModelType.FORWARD_TREE)
        rho[strike] = Rho(option_contract, mirror_option=mirror_contract, option_model=OptionPricingModelType.FORWARD_TREE)
    var iv = new Dictionary<decimal, ImpliedVolatility>();
    var delta = new Dictionary<decimal, Delta>();
    var gamma = new Dictionary<decimal, Gamma>();
    var vega = new Dictionary<decimal, Vega>();
    var theta = new Dictionary<decimal, Theta>();
    var rho = new Dictionary<decimal, Rho>();
    
    foreach (var pair in optionContracts.Zip(mirrorContracts, (x, y) => new {OptionContract = x, MirrorContract = y}))
    {
        var strike = pair.OptionContract.ID.StrikePrice;
        var optionContract = pair.OptionContract;
        var mirrorContract = pair.MirrorContract;
    
        iv[strike] = new ImpliedVolatility(optionContract, mirrorOption: mirrorContract, optionModel: OptionPricingModelType.ForwardTree);
        delta[strike] = new Delta(optionContract, mirrorOption: mirrorContract, optionModel: OptionPricingModelType.ForwardTree);
        gamma[strike] = new Gamma(optionContract, mirrorOption: mirrorContract, optionModel: OptionPricingModelType.ForwardTree);
        vega[strike] = new Vega(optionContract, mirrorOption: mirrorContract, optionModel: OptionPricingModelType.ForwardTree);
        theta[strike] = new Theta(optionContract, mirrorOption: mirrorContract, optionModel: OptionPricingModelType.ForwardTree);
        rho[strike] = new Rho(optionContract, mirrorOption: mirrorContract, optionModel: OptionPricingModelType.ForwardTree);
    }
  7. Iterate through the historical data and calculate the values.
  8. df = pd.DataFrame()
    
    for option_contract, mirror_contract in zip(option_contracts, mirror_contracts):
        strike = option_contract.id.strike_price
    
        for bar in history:
            # Update the option indicators with indicator data points of the 3 symbols
            equity_point = IndicatorDataPoint(equity_symbol, bar[equity_symbol].end_time, bar[equity_symbol].close)
            option_point = IndicatorDataPoint(option_contract, bar[option_contract].end_time, bar[option_contract].close)
            mirror_point = IndicatorDataPoint(mirror_contract, bar[mirror_contract].end_time, bar[mirror_contract].close)
    
            iv[strike].update(equity_point)
            iv[strike].update(option_point)
            iv[strike].update(mirror_point)
            
            delta[strike].update(equity_point)
            delta[strike].update(option_point)
            delta[strike].update(mirror_point)
            
            gamma[strike].update(equity_point)
            gamma[strike].update(option_point)
            gamma[strike].update(mirror_point)
            
            vega[strike].update(equity_point)
            vega[strike].update(option_point)
            vega[strike].update(mirror_point)
            
            theta[strike].update(equity_point)
            theta[strike].update(option_point)
            theta[strike].update(mirror_point)
            
            rho[strike].update(equity_point)
            rho[strike].update(option_point)
            rho[strike].update(mirror_point)
    
            new_data = pd.Series({
                "Strike": strike,
                "OptionPrice": bar[option_contract].close,
                "UnderlyingPrice": bar[equity_symbol].close,
                "IV": iv[strike].current.value,
                "Delta": delta[strike].current.value,
                "Gamma": gamma[strike].current.value,
                "Vega": vega[strike].current.value,
                "Theta": theta[strike].current.value,
                "Rho": rho[strike].current.value,
            }, name=bar[option_contract].end_time).to_frame().T
            df = pd.concat([df, new_data])
    var ivs = new Dictionary<decimal, decimal>();
    
    foreach (var pair in optionContracts.Zip(mirrorContracts, (x, y) => new {OptionContract = x, MirrorContract = y}))
    {
        var strike = pair.OptionContract.ID.StrikePrice;
        var optionContract = pair.OptionContract;
        var mirrorContract = pair.MirrorContract;
        
        foreach (var bar in history)
        {
            // Update the option indicators with indicator data points of the 3 symbols
            var equityPoint = new IndicatorDataPoint(equitySymbol, bar[equitySymbol].EndTime, bar[equitySymbol].Close);
            var optionPoint = new IndicatorDataPoint(optionContract, bar[optionContract].EndTime, bar[optionContract].Close);
            var mirrorPoint = new IndicatorDataPoint(mirrorContract, bar[mirrorContract].EndTime, bar[mirrorContract].Close);
    
            iv[strike].Update(equityPoint);
            iv[strike].Update(optionPoint);
            iv[strike].Update(mirrorPoint);
            
            delta[strike].Update(equityPoint);
            delta[strike].Update(optionPoint);
            delta[strike].Update(mirrorPoint);
            
            gamma[strike].Update(equityPoint);
            gamma[strike].Update(optionPoint);
            gamma[strike].Update(mirrorPoint);
            
            vega[strike].Update(equityPoint);
            vega[strike].Update(optionPoint);
            vega[strike].Update(mirrorPoint);
            
            theta[strike].Update(equityPoint);
            theta[strike].Update(optionPoint);
            theta[strike].Update(mirrorPoint);
            
            rho[strike].Update(equityPoint);
            rho[strike].Update(optionPoint);
            rho[strike].Update(mirrorPoint);
    
            ivs[strike] = iv[strike].Current.Value;
    
            var line = $"OptionPrice: {bar[optionContract].Close:0.0000}, UnderlyingPrice: {bar[equitySymbol].Close:0.0000}, Strike: {strike}, "
                + $"IV: {iv[strike].Current.Value:0.0000}, Delta: {delta[strike].Current.Value:0.0000}, Gamma: {gamma[strike].Current.Value:0.0000}, "
                + $"Vega: {vega[strike].Current.Value:0.0000}, Theta: {theta[strike].Current.Value:0.0000}, Rho: {rho[strike].Current.Value:0.0000}";
            Console.WriteLine(line);
        }
    }

    We can also plot the Implied Volatility smile across different strike prices:

    df.reset_index().set_index(["index", "Strike"]).loc[pd.to_datetime("2021-12-30 16:00:00")]["IV"].plot(title="Implied Volatility of Calls", ylabel="IV", figsize=(8, 6))
    var chart = Chart2D.Chart.Line<decimal, decimal, string>(
        ivs.Select(kvp => kvp.Key),
        ivs.Select(kvp => kvp.Value)
    );
    
    LinearAxis xAxis = new LinearAxis();
    xAxis.SetValue("title", "Strike");
    LinearAxis yAxis = new LinearAxis();
    yAxis.SetValue("title", "IV");
    Title title = Title.init($"Implied Volatilities of Calls");
    
    Layout layout = new Layout();
    layout.SetValue("xaxis", xAxis);
    layout.SetValue("yaxis", yAxis);
    layout.SetValue("title", title);
    
    chart.WithLayout(layout);
    HTML(GenericChart.toChartHTML(chart))
    Implied Volatilities of Calls by IV indicator Implied Volatilities of Calls by IV indicator

For a full example, see the following project:

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: