AlgoSeek
US Equity Options
Introduction
The US Equity Options data by AlgoSeek provides Option data, including prices, strikes, expires, and open interest. The data covers 4,000 Symbols, starts in January 2012, and is delivered on a minute frequency. This dataset is created by monitoring Options Price Reporting Authority (OPRA) data feed, which consolidates last sale and quotation information originating from the national securities exchanges that have been approved by the Securities and Exchange Commission.
This dataset depends on the following datasets:
- US Equity Security Master - data on splits, dividends, and symbol changes for the underlying Equities.
- US Equity Option Universe - data on the available contracts and their daily Greeks and implied volatility values.
- US Equities - trade and quote data on the underlying Equities.
For more information about the US Equity Options dataset, including CLI commands and pricing, see the dataset listing.
About the Provider
AlgoSeek was in 2014 with the goal of providing the highest quality, most accurate, ready-to-use data in the financial data industry. AlgoSeek provides access to Equities, ETFs, ETNs, Equity Indices, Equity Options, Futures, and Future Options for quantitative firms and traders.
Getting Started
The following snippet demonstrates how to request data from the US Equity Options dataset:
option = self.add_option("GOOG") self.option_symbol = option.symbol option.set_filter(-2, +2, 0, 180)
var option = AddOption("GOOG"); _optionSymbol = option.Symbol; option.SetFilter(-2, +2, 0, 180);
Data Summary
The following table describes the dataset properties:
Property | Value |
---|---|
Start Date | January 2012* |
Asset Coverage | 4,000 Symbols |
Data Density | Dense |
Resolution | Minute, Hourly, & Daily |
Timezone | New York |
Market Hours | Regular Only |
* Some data is available before this date. In 2012, AlgoSeek started to fetch data from 48 OPRA channels instead of 24, increasing the quality of the data.
Requesting Data
To add US Equity Options data to your algorithm, call the AddOption
add_option
method. Save a reference to the Equity Option Symbol
so you can access the data later in your algorithm.
class USEquityOptionsDataAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2020, 6, 1) self.set_end_date(2021, 6, 1) self.set_cash(100000) self.universe_settings.asynchronous = True # Request GOOG option data option = self.add_option("GOOG") self.option_symbol = option.symbol # Set our strike/expiry filter for this option chain option.set_filter(-2, +2, 0, 180)
public class USEquityOptionsDataAlgorithm : QCAlgorithm { private Symbol _optionSymbol; public override void Initialize() { SetStartDate(2020, 6, 1); SetEndDate(2021, 6, 1); SetCash(100000); UniverseSettings.Asynchronous = True; // Request GOOG option data var option = AddOption("GOOG"); _optionSymbol = option.Symbol; // Set our strike/expiry filter for this option chain option.SetFilter(-2, +2, 0, 180); } }
The Equity resolution must be less than or equal to the Equity Option resolution. For example, if you set the Equity resolution to minute, then you must set the Equity Option resolution to minute, hour, or daily.
For more information about creating US Equity Option subscriptions, see Requesting Data or Equity Options Universes.
Accessing Data
To get the current US Equity Options data, index the OptionChains
option_chains
property of the current Slice
with the canonical Equity Option Symbol
. Slice objects deliver unique events to your algorithm as they happen, but the Slice
may not contain data for your Index Option at every time step. To avoid issues, call the Get
get
method.
def on_data(self, slice: Slice) -> None: # Get the wanted option chain with the canonical symbol chain = slice.option_chains.get(self.option_symbol) if chain: # Iterate the option contracts in chain for contract in chain: self.log(f"{contract.symbol} price at {slice.time}: {contract.last_price}")
public override void OnData(Slice slice) { // Get the wanted option chain with the canonical symbol if (slice.OptionChains.TryGetValue(_optionSymbol, out var chain)) { // Iterate the option contracts in chain foreach (var contract in chain) { Log($"{contract.Symbol} price at {slice.Time}: {contract.LastPrice}"); } } }
You can also iterate through all of the OptionChain
objects in the current Slice
.
def on_data(self, slice: Slice) -> None: # Iterate all option chains of all symbols for canonical_symbol, chain in slice.option_chains.items(): # Iterate the option contracts in chain for contract in chain: self.log(f"{contract.symbol} price at {slice.time}: {contract.last_price}")
public override void OnData(Slice slice) { // Iterate all option chains of all symbols foreach (var kvp in slice.OptionChains) { var canonicalSymbol = kvp.Key; var chain = kvp.Value; // Iterate the option contracts in chain foreach (var contract in chain) { Log($"{contract.Symbol} price at {slice.Time}: {contract.LastPrice}"); } } }
For more information about accessing US Equity Options data, see Handling Data.
Historical Data
You can get historical US Equity Options data in an algorithm and the Research Environment.
Historical Data In Algorithms
To get historical US Equity Options data in an algorithm, call the History
history
method with the Equity Option contract Symbol
. If there is no data in the period you request, the history result is empty.
# DataFrame of trade and quote data history_df = self.history(contract.symbol, 100, Resolution.MINUTE) # DataFrame of open interest data history_oi_df = self.history(OpenInterest, contract.symbol, 100, Resolution.MINUTE) # TradeBar objects history_trade_bars = self.history[TradeBar](contract.symbol, 100, Resolution.MINUTE) # QuoteBar objects history_quote_bars = self.history[QuoteBar](contract.symbol, 100, Resolution.MINUTE) # OpenInterest objects history_oi = self.history[OpenInterest](contract.symbol, 100, Resolution.MINUTE)
// TradeBar objects var historyTradeBars = History(contract.Symbol, 100, Resolution.Minute); // QuoteBar objects var historyQuoteBars = History<QuoteBar>(contract.Symbol, 100, Resolution.Minute); // OpenInterest objects var historyOpenInterest = History<OpenInterest>(contract.Symbol, 100, Resolution.Minute);
For more information about historical data in algorithms, see History Requests.
Historical Data In Research
To get historical US Equity Options data in the Research Environment, call the History
history
or OptionHistory
option_history
method. The History
history
method returns the price, volume, and open interest history for some given Option contract(s). The OptionHistory
option_history
method returns the price and volume history for the contracts that pass your daily universe filter.
qb = QuantBook() option = qb.add_option("GOOG") option.set_filter(-2, 2, 0, 90) history = qb.option_history(option.symbol.underlying, datetime(2020, 6, 1), datetime(2020, 6, 5)) history_df = history.data_frame expiries = history.get_expiry_dates() strikes = history.get_strikes()
var qb = new QuantBook(); var option = qb.AddOption("GOOG"); option.SetFilter(-2, 2, 0, 90); var history = qb.OptionHistory(option.Symbol, new DateTime(2020, 6, 1), new DateTime(2020, 6, 5)); var contracts = history .SelectMany(x => x.OptionChains.SelectMany(y => y.Value.Contracts.Keys)) .Distinct().ToList(); var expiries = contracts.Select(x => x.ID.Date).Distinct().ToList(); var strikes = contracts.Select(x => x.ID.StrikePrice).Distinct().ToList();
To get historical data for arbitrary US Equity Option contracts instead of just the that pass your universe filter, call the History
history
method like you would in an algorithm, but on the QuantBook
object. For more information about historical data in the Research Environment, see Key Concepts.
Historical Greeks and IV Data
To get historical data for the Greeks and implied volatility of Equity Options, see the US Equity Option Universe dataset.
Supported Assets
To view the supported assets in the US Equity Options dataset, see the Data Explorer.
Example Applications
The US Equity Options dataset enables you to accurately design Option strategies. Examples include the following strategies:
- Buying put Options to hedge against downward price movement in positive Equity positions
- Exploiting arbitrage opportunities that arise when the price of Option contracts deviates from their theoretical value
Classic Algorithm Example
The following example algorithm subscribes to Google Options that fall within two strikes of the underlying stock price and expire within seven days. Within this Option chain, the algorithm buys the call Option contract that has the furthest expiry and has its strike price closest to the underlying stock price. When the contract expires, the algorithm rolls over to the next contract that meets this criteria.
from AlgorithmImports import * from QuantConnect.DataSource import * class USEquityOptionsDataAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2020, 6, 1) self.set_end_date(2020, 8, 1) self.set_cash(100000) self.universe_settings.asynchronous = True # Requesting data self.underlying = self.add_equity("GOOG").symbol option = self.add_option("GOOG") self.option_symbol = option.symbol # To speculate trade the underlying with a low cost, filter for the ATM calls that expiring in the current week # -2/+2 strike buffer is given for small price change option.set_filter(lambda u: u.include_weeklys().calls_only().strikes(-2, +2).expiration(0, 6)) self.contract = None def on_data(self, slice: Slice) -> None: # Close the underlying position if the option contract is exercised if self.portfolio[self.underlying].invested: self.liquidate(self.underlying) # Select with the lastest option chain data only chain = slice.option_chains.get(self.option_symbol) if self.contract and not self.portfolio[self.contract.symbol].invested and chain: # Select the call contracts with the furthest expiration (week end) furthest_expiry = sorted(calls, key = lambda x: x.expiry, reverse=True)[0].expiry furthest_expiry_calls = [contract for contract in calls if contract.expiry == furthest_expiry] # Get the ATM call for speculate trade with low cost and limited loss self.contract = sorted(furthest_expiry_calls, key = lambda x: abs(chain.underlying.price - x.strike))[0] self.market_order(self.contract.symbol, 1) def on_securities_changed(self, changes: SecurityChanges) -> None: for security in changes.added_securities: # Historical data history = self.history(security.symbol, 10, Resolution.MINUTE) self.debug(f"We got {len(history)} from our history request for {security.symbol}")
public class USEquityOptionsDataAlgorithm : QCAlgorithm { private Symbol _underlying; private Symbol _optionSymbol; private OptionContract? _contract = None; public override void Initialize() { SetStartDate(2020, 6, 1); SetEndDate(2020, 8, 1); SetCash(100000); UniverseSettings.Asynchronous = True; // Requesting data _underlying = AddEquity("GOOG").Symbol; var option = AddOption("GOOG"); _optionSymbol = option.Symbol; // To speculate trade the underlying with a low cost, filter for the ATM calls that expiring in the current week // -2/+2 strike buffer is given for small price change option.SetFilter((u) => u.IncludeWeeklys().CallsOnly().Strikes(-2, +2).Expiration(0, 7)); } public override void OnData(Slice slice) { // Close the underlying position if the option contract is exercised if (Portfolio[_underlying].Invested) { Liquidate(_underlying); } // Select with the lastest option chain data only if (_contract != None && !Portfolio[_contract.Symbol].Invested && slice.OptionChains.TryGetValue(_optionSymbol, out var chain)) { // Select the call contracts with the furthest expiration (week end) var furthestExpiry = calls.OrderByDescending(x => x.Expiry).First().Expiry; var furthestExpiryCalls = calls.Where(x => x.Expiry == furthestExpiry).ToList(); // Get the ATM call for speculate trade with low cost and limited loss var contract = furthestExpiryCalls.OrderByDescending(x => Math.Abs(chain.Underlying.Price - x.Strike)).Last(); _contract = contract; MarketOrder(contract.Symbol, 1); } } public override void OnSecuritiesChanged(SecurityChanges changes) { foreach (var security in changes.AddedSecurities) { // Historical data var history = History(security.Symbol, 100, Resolution.Minute); Debug($"We got {history.Count()} from our history request for {security.Symbol}"); } } }
Framework Algorithm Example
The following example algorithm buys a call Option contract for Google that falls within one strike of the underlying stock price and expires within seven days. When the contract expires, the algorithm rolls over to the next contract that meets this criteria.
from AlgorithmImports import * from QuantConnect.DataSource import * from Selection.OptionUniverseSelectionModel import OptionUniverseSelectionModel class USEquityOptionsDataAlgorithm(QCAlgorithm): def initialize(self) -> None: self.set_start_date(2020, 6, 1) self.set_end_date(2020, 8, 1) self.set_cash(100000) self.universe_settings.asynchronous = True # Requesting data self.set_universe_selection(EarliestExpiringWeeklyAtTheMoneyCallOptionUniverseSelectionModel()) self.set_alpha(ConstantOptionsAlphaModel()) self.set_portfolio_construction(SingleSharePortfolioConstructionModel()) class EarliestExpiringWeeklyAtTheMoneyCallOptionUniverseSelectionModel(OptionUniverseSelectionModel): def __init__(self) -> None: # Daily update with the select_option_chain_symbols function super().__init__(timedelta(1), self.select_option_chain_symbols) def select_option_chain_symbols(self, utcTime: datetime) -> List[Symbol]: # Always select only GOOG options as our focus return [ Symbol.create("GOOG", SecurityType.OPTION, Market.USA) ] def filter(self, filter: OptionFilterUniverse) -> OptionFilterUniverse: # To speculate trade the underlying with a low cost, filter for the ATM calls that expiring in the current week # -1/+1 strike buffer is given for small price change return (filter.weeklys_only() .calls_only() .strikes(-1, -1) .expiration(0, 7)) class ConstantOptionsAlphaModel(AlphaModel): underlying = None contract = None def update(self, algorithm: QCAlgorithm, slice: Slice) -> List[Insight]: insights = [] # Liquidate the underlying if the option is being exercised/assigned if algorithm.portfolio[self.underlying].invested: insights.append(Insight.price(self.underlying, timedelta(days=7), InsightDirection.FLAT)) if self.contract is not None and algorithm.portfolio[self.contract.symbol].invested: return insights # Get the ATM call for speculate trade with low cost and limited loss that expires at week end for kvp in slice.option_chains: chain = kvp.Value expiry = max(x.expiry for x in chain) self.contract = sorte([x for x in chain if x.expiry == expiry], key=lambda x: abs(x.strike - x.underlying_last_price))[0] insights.append(Insight.price(self.contract.symbol, self.contract.expiry + timedelta(days=1), InsightDirection.UP)) return insights def on_securities_changed(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None: for security in changes.added_securities: if security.type == SecurityType.EQUITY: self.underlying = security.symbol else: # Historical data history = algorithm.history(security.symbol, 10, Resolution.MINUTE) algorithm.debug(f"We got {len(history)} from our history request for {security.symbol}") class SingleSharePortfolioConstructionModel(PortfolioConstructionModel): def create_targets(self, algorithm: QCAlgorithm, insights: List[Insight]) -> List[PortfolioTarget]: targets = [] for insight in insights: if algorithm.securities[insight.symbol].is_tradable: targets.append(PortfolioTarget(insight.symbol, insight.direction)) return targets
public class USEquityOptionsDataAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2020, 6, 1); SetEndDate(2020, 8, 1); SetCash(100000); UniverseSettings.Asynchronous = True; // Requesting data SetUniverseSelection(new EarliestExpiringWeeklyAtTheMoneyCallOptionUniverseSelectionModel()); SetAlpha(new ConstantOptionsAlphaModel()); SetPortfolioConstruction(new SingleSharePortfolioConstructionModel()); } } class EarliestExpiringWeeklyAtTheMoneyCallOptionUniverseSelectionModel : OptionUniverseSelectionModel { // Daily update with the SelectOptionChainSymbols function public EarliestExpiringWeeklyAtTheMoneyCallOptionUniverseSelectionModel() : base(TimeSpan.FromDays(1), SelectOptionChainSymbols) {} private static IEnumerable<Symbol> SelectOptionChainSymbols(DateTime utcTime) { // Select only GOOG options as our focus return new[] {QuantConnect.Symbol.Create("GOOG", SecurityType.Option, Market.USA)}; } protected override OptionFilterUniverse Filter(OptionFilterUniverse filter) { // To speculate trade the underlying with a low cost, filter for the ATM calls that expiring in the current week // -2/+2 strike buffer is given for small price change return filter .Strikes(-1, -1) .Expiration(0, 7) .WeeklysOnly() .CallsOnly(); } } class ConstantOptionsAlphaModel : AlphaModel { private Symbol? _underlying = None; private OptionContract? _contract = None; public override IEnumerable<Insight> Update(QCAlgorithm algorithm, Slice slice) { var insights = new List<Insight>(); // Liquidate the underlying if the option is being exercised/assigned if (algorithm.Portfolio[_underlying].Invested) { insights.Add(Insight.Price(_underlying, TimeSpan.FromDays(7), InsightDirection.Flat)); } if (_contract != None && algorithm.Portfolio[_contract.Symbol].Invested) { return insights; } // Get the ATM call for speculate trade with low cost and limited loss that expires at week end foreach (var kvp in slice.OptionChains) { var chain = kvp.Value; var expiry = chain.Max(x => x.Expiry); _contract = chain.Where(x => x.Expiry == expiry) .OrderBy(x => Math.Abs(x.Strike - x.UnderlyingLastPrice)) .First(); insights.Add(Insight.Price(_contract.Symbol, _contract.Expiry + TimeSpan.FromDays(1), InsightDirection.Up)); } return insights; } public override void OnSecuritiesChanged(QCAlgorithm algorithm, SecurityChanges changes) { foreach (var security in changes.AddedSecurities) { if (security.Type == SecurityType.Equity) { _underlying = security.Symbol; } else { // Historical data var history = algorithm.History(security.Symbol, 100, Resolution.Minute); algorithm.Debug($"We got {history.Count()} from our history request for {security.Symbol}"); } } } } class SingleSharePortfolioConstructionModel : PortfolioConstructionModel { public override IEnumerable<PortfolioTarget> CreateTargets(QCAlgorithm algorithm, Insight[] insights) { var targets = new List<PortfolioTarget>(); foreach (var insight in insights) { if (algorithm.Securities[insight.Symbol].IsTradable) { targets.Add(new PortfolioTarget(insight.Symbol, (int) insight.Direction)); } } return targets; } }
Data Point Attributes
The US Equity Options dataset provides TradeBar
, QuoteBar
, and OpenInterest
objects.
TradeBar Attributes
TradeBar
objects have the following attributes:
QuoteBar Attributes
QuoteBar
objects have the following attributes:
OpenInterest Attributes
OpenInterest
objects have the following attributes: