Skip to main content

Options Chains

Overview

Options Data Object

Options chains data is loaded to memory by using the function, openbb.stocks.options.load_options_chains(), and is available from six sources:

  • CBOE
  • Intrinio (no free data)
  • Nasdaq
  • TMX
  • Tradier (requires Sandbox developer key)
  • YahooFinance

Every source will return the same object which has data and additional callable functions bound to the class. They are methods for filtering, sorting, and analyzing the data contained within.

from openbb_terminal.sdk import openbb
openbb.stocks.options.load_options_chains?
Parameters
----------
symbol: str
The ticker symbol to load the data for.
source: str
The source for the data. Defaults to "CBOE". ["CBOE", "Intrinio", "Nasdaq", "TMX", "Tradier", "YahooFinance"]
date: str
The date for EOD chains data. Only available for "Intrinio" and "TMX".
pydantic: bool
Whether to return as a Pydantic Model or as a Pandas object. Defaults to False.

Returns
------
OptionsChains
chains: pd.DataFrame
The complete options chain for the ticker. Returns as a dictionary if pydantic is True.
expirations: list[str]
List of unique expiration dates. (YYYY-MM-DD)
strikes: list[float]
List of unique strike prices.
last_price: float
The last price of the underlying asset.
underlying_name: str
The name of the underlying asset.
underlying_price: pd.Series
The price and recent performance of the underlying asset. Returns as a dictionary if pydantic is True.
hasIV: bool
Returns implied volatility.
hasGreeks: bool
Returns greeks data.
symbol: str
The symbol entered by the user.
source: str
The source of the data.
date: str
The date, when the chains data is historical EOD.
SYMBOLS: pd.DataFrame
The symbol directory for the source, when available. Returns as a dictionary if pydantic is True.

Methods
------
chart_skew: Callable
Function to chart the implied volatility skew.
chart_stats: Callable
Function to chart a variety of volume and open interest statistics.
chart_surface: Callable
Function to chart the volatility as a 3-D surface.
chart_volatility: Callable
Function to chart the implied volatility smile.
get_skew: Callable
Function to calculate horizontal and vertical skewness.
get_stats: Callable
Function to return a table of summary statistics, by strike or by expiration.
get_straddle: Callable
Function to calculate straddles and the payoff profile.
get_strangle: Callable
Function to calculate strangles and the payoff profile.
get_synthetic_long: Callable
Function to calculate a synthetic long position.
get_synthetic_short: Callable
Function to calculate a synthetic short position.
get_vertical_call_spread: Callable
Function to calculate vertical call spreads.
get_vertical_put_spreads: Callable
Function to calculate vertical put spreads.
get_strategies: Callable
Function for calculating multiple straddles and strangles at different expirations and moneyness.

Loading Data

load_options_chains()

The default source to load data from is, CBOE. Use the command below to get started.

from openbb_terminal.sdk import openbb
spy = openbb.stocks.options.load_options_chains("SPY")

The result is returned as the object described in the previous section.

Options Data Object

The object is still returned if an unsupported symbol is requested and a message will be printed.

In [4]: data = openbb.stocks.options.load_options_chains("spyyy")
The symbol, SPYYY, was not found in the CBOE directory.

In [5]: data.chains
Out[5]: pandas.core.frame.DataFrame

Where available, symbols are verified against a source-specific symbol directory. This is accessible from the Options data object as the attribute named, SYMBOLS.

data.SYMBOLS.filter(like = "SPY", axis = 0)
SymbolCompany NameDPM NamePost/Station
SPYSPDR S&P 500 ETF TR TR UNITMorgan Stanley & Co. LLC8/1
SPYGSPDR SER TR PRTFLO S&P500 GWBelvedere Trading LLC6/1
SPYDSPDR SER TR PRTFLO S&P500 HICitadel Securities LLC6/1
SPYVSPDR SER TR PRTFLO S&P500 VLBelvedere Trading LLC6/1
NSPYUNIFIED SER TR NIGHTSHARES 500Wolverine Trading, LLC3/1
note

A valid symbol will not always have listed options.

Key information for the underlying asset are stored in the object as last_price, underlying_name, and underlying_price. The information returned to underlying_price will vary by source, but all column headers and index names related to the raw data are formatted in camelCase.

CBOE:

In [7]: data.underlying_price
Out[7]:
type stock
tick down
bid 449.18
bidSize 1
askSize 5
ask 449.2
price 449.28
open 450.56
high 451.36
low 448.49
close 449.28
volume 69772484
previousClose 449.28
change -0.28
changePercent -0.0623
ivThirty 10.947
ivThirtyChange 0.0
lastTradeTimestamp 2023-07-14T16:00:00
ivThirtyOneYearHigh 30.646999
hvThirtyOneYearHigh 30.648199
ivThirtyOneYearLow 10.692
hvThirtyOneYearLow 10.0721
ivSixtyOneYearHigh 28.674999
hvSixtyOneYearHigh 29.5842
ivSixtyOneYearLow 11.245
hvsixtyOneYearLow 11.833
ivNinetyOneYearHigh 27.862
hvNinetyOneYearHigh 26.808901
ivNinetyOneYearLow 11.827
hvNinetyOneYearLow 13.3855
Name: SPY, dtype: object

TMX:

In [8]: data = openbb.stocks.options.load_options_chains("XIU", "TMX")

In [9]: data.underlying_price
Out[9]:
time 15:59:56.910
previousClose 30.86
transactions 393
volume 50751
value 1567628
valueCAD 1567628
open 30.97
price 30.85
change -0.01
changePercent -0.03
tick 0.01
low 30.835
high 30.97
vwap 30.89
fiftyTwoWeekHigh 31.86
fiftyTwoWeekLow 27.375
Name: XIU, dtype: object

Not every source will return implied volatility or Greeks data. The two object attributes, hasGreeks and hasIV, act as validators for downstream functions.

In [10]: data.hasIV
Out[10]: False

In [11]: data.get_skew()
Options data object does not have Implied Volatility and is required for this function.

Historical EOD Chains

Historical EOD chains data is currently available from Intrinio or TMX. The amount of historical data will depend on the subscription status with Intrinio, but is available from the beginning of 2009 from TMX. Add the date argument when loading the data. The price data of the underlying asset will reflect the closing price on the date entered.

In [12]: data = openbb.stocks.options.load_options_chains("CCO", "TMX", date = "2016-06-29")

In [13]: data.underlying_price
Out[13]:
date 2016-06-29
bid 13.99
ask 14.01
bidSize 29
askSize 20
price 14.0
volume 801176
previousClose 13.73
change 0.27
open 13.88
high 14.09
low 13.8
valueCAD 11198995
transactions 3283
symbol CCO
Name: Cameco Corporation, dtype: object

Additional Class Methods

The class methods work with the Options data object to query the loaded chains data in different ways. Column headers at this stage are cleaned and presentable for view. There are two types of operations, get and chart, with the latter being a subset of the former. The docstring (data? - and as shown in a section above) lists them all, as Methods, with a short description. The nuances of the functions are explained within the docstrings of each. Variations to the combinations of parameters will yield over thirty unique charts and provide nearly infinite ways to query to data stored in the object.

note

All chart_ methods have boolean arguments for raw and external_axes. These return an interactive table in the PyWry window or the Plotly figure object, respectively. In a Jupyter Notebook, they will be displayed inline.

Returning the command to a variable provides the ability to style and customize charts as desired.

fig = data.chart_volatility(expirations=data.expirations[1], external_axes = True)

get_stats()

Parameters
----------
by: str
Whether to calculate by strike or expiration. Default is expiration.
query: DataFrame
Entry point to perform DataFrame operations on self.chains at the input stage.

Returns
-------
pd.DataFrame
Pandas DataFrame with the calculated statistics.

Ratios are defined as Put/Call.

data = openbb.stocks.options.load_options_chains("VIX")
data.get_stats().iloc[1]
2023-07-26
Puts OI2018
Calls OI45875
Total OI47893
OI Ratio0.04
Puts OTM873
Calls OTM45747
Puts ITM1145
Calls ITM128
OTM Ratio0.02
ITM Percent2.66
Puts Volume264
Calls Volume2156
Total Volume2420
Volume Ratio0.12
Vol-OI Ratio0.05

The query parameter provides an entry point for DataFrame operations to take place prior to calculating. For example, filtering for only the options which traded during the last session.

data.get_stats(query = data.chains[vix.chains["lastTradeTimestamp"] > "2023-07-14"])
ExpirationPuts OICalls OITotal OIOI RatioPuts VolumeCalls VolumeTotal VolumeVolume RatioVol-OI Ratio
2023-07-191569778332339648931740.471134601304162438760.870.05
2023-07-26185529273311280.06264215624200.120.08
2023-08-021154249836520.46127867980.020.22
2023-08-0933096112910.34433543970.120.31
2023-08-16907980224670731546870.4486681971482458160.250.08
2023-08-2304949071451520.053.1
2023-09-20614369209774227121110.292075019260400101.080.01
2023-10-18165239109985812650970.15330414912182160.220.01
2023-11-15701427426988128400.09825145960.160
2023-12-20445802598153043950.171079712471232680.870.08
2024-01-172086043733645930.4823574236904726410.73
2024-02-141347656779140.21672032700.330.03
2024-03-2063186119240.0382192270.040.12

chart_stats()

The volume and open interest metrics can be visualized in a number of ways. In general, they are bucketed as volume and open interest by strike or expiration.

data.chart_stats()

Vix % of Total Volume vs. Strike

data.chart_stats(by="strike", oi=True)

VIX % of Total Open Interest vs. Strike

data.chart_stats(by="strike", oi=True, percent=False)

VIX Open Interest vs. Strike

data.chart_stats(ratios=True)

VIX Volume and Open Interest Ratios

Options Strategies

These methods calculate common, single-leg, strategies and return one result. The target expiry date is expressed as the number of days until expiration, and the closest expiry to supplied value will be returned. There are six types of strategies currently supported:

  • get_straddle()
  • get_strangle()
  • get_synthetic_long()
  • get_synthetic_short()
  • get_vertical_call_spread()
  • get_vertical_put_spread()
note

Looking for a place to get started as a contributor, and enjoy trading options? Strategies are an excellent starting point!

All strategies share a common default setting, days=30. Vertical spreads require two strike prices, and they are entered as sold, bought. A bull call or put spread is entered with a bought price lower than the sold price.

data.get_vertical_call_spread(30,13,12.50)
Bull Call Spread
SymbolVIX
Underlying Price13.34
Expiration2023-08-16
DTE31
Strike 113.0
Strike 212.5
Strike 1 Premium2.9
Strike 2 Premium3.4
Cost0.5
Cost Percent3.7481
Breakeven Lower13.0
Breakeven Lower Percent-2.5487
Breakeven Uppernan
Breakeven Upper Percentnan
Max Profit0.0
Max Loss-0.5
Payoff Ratio0.0
data.get_vertical_put_spread(30,13,12.5)
Bull Put Spread
SymbolVIX
Underlying Price13.34
Expiration2023-08-16
DTE31
Strike 113.0
Strike 212.5
Strike 1 Premium-0.17
Strike 2 Premium0.12
Cost-0.05
Cost Percent0.3748
Breakeven Lowernan
Breakeven Lower Percentnan
Breakeven Upper12.95
Breakeven Upper Percent2.92
Max Profit0.05
Max Loss-0.45
Payoff Ratio0.1111

get_strategies()

This takes all of the individual strategies and combines them into a single endpoint that can iterate over all expiry dates.

data.get_strategies(days = 30, straddle_strike = data.last_price, strangle_moneyness = 30, vertical_calls = [20,15], vertical_puts = [12,15], synthetic_longs = 16, synthetic_shrots = 14)
2023-08-162023-08-162023-08-162023-08-162023-08-162023-08-16
DTE313131313131
StrategyLong StraddleLong StrangleSynthetic LongSynthetic ShortBull Call SpreadBear Put Spread
Underlying Price13.3413.3413.3413.3413.3413.34
Strike 113.517.014.016.020.012.0
Strike 213.510.014.016.015.015.0
Strike 1 Premium2.621.282.31-1.46-0.83-0.04
Strike 2 Premium0.330.01-0.491.741.831.04
Cost2.951.291.820.281.01.0
Cost Percent22.11399.670213.64322.0997.49637.4963
Breakeven Upper16.4518.2915.82nannannan
Breakeven Upper Percent23.313337.106418.5907nannannan
Breakeven Lower10.558.71nan15.7216.014.0
Breakeven Lower Percent-20.9145-34.7076nan17.841119.9417.5412
Max Profitinfinfinf15.724.02.0
Max Loss-2.95-1.29-15.82inf-1.0-1.0
Payoff Ratioinfinfnannan4.02.0

The default state of get_strategies() is to return all ATM straddles. This information can be useful for charting the term structure and expected move of the underlying asset.

Volatility

There are two types of views for volatility, smiles and surfaces.

chart_volatility()

As a default state, the put and call volatility smiles from the expiration in position 1, contained in the list data.expirations[1], are displayed.

data.chart_volatility()

VIX IV Smile

The implied volatility can also be visualized as the forward curve at a specific strike or % moneyness.

data.chart_volatility(strike=20)

VIX Volatility at $20 Strike

data.chart_volatility(moneyness=30)

VIX Volatility at 30% OTM

chart_surface()

A portion, or the entire, volatility surface is presented as a 3-D chart. The data is arranged by types, selectable with the option_type parameter, choosing one of: otm, itm, calls, puts. The default state is otm. The X and Y axes can be narrowed to focus on a range of time and strike.

data.chart_surface(dte_range = [30,300], strike_range = [10,30])

VIX OTM IV Surface

Skew

Unlike volatility, there are both model and view components for the IV skew of the chain.

get_skew()

By default, this callable calculates the skew of every option. It can return either vertical or horizontal skew. Vertical skew can be narrowed to a specific expiry, and horizontal skew is determined by % OTM.

data.get_skew(data.expirations[1]).query("12 <= `Strike` <= 15")
ExpirationStrikeOption TypeIVATM IVSkew
1162023-07-2612put1.11360.92830.1853
1172023-07-2612.5put1.02460.92830.0963
1182023-07-2613put0.96660.92830.0383
1192023-07-2613.5put0.92830.92830
1202023-07-2614call0.49940.49940
1212023-07-2614put0.87020.9283-0.0581
1222023-07-2614.5call0.61560.49940.1162
1232023-07-2614.5put0.88990.9283-0.0384
1242023-07-2615call0.62450.49940.1251
1252023-07-2615put0.90020.9283-0.0281
vix.get_skew(moneyness=20)
expirationCall StrikeCall IVCall ATM IVCall SkewPut StrikePut IVPut ATM IVPut SkewATM SkewIV Skew
2023-07-19161.09960.5990.500610.51.05050.63280.4177-0.03380.0829
2023-07-26160.87080.49940.371410.50.91010.9283-0.0182-0.42890.3896
2023-08-02160.8550.50260.352410.50.74380.67550.0683-0.17290.2841
2023-08-09160.78610.49260.293510.50.67120.65750.0137-0.16490.2798
2023-08-16160.83640.62840.20810.50.60410.6117-0.00760.01670.2156
2023-08-23160.92730.89180.035510.50.54920.6356-0.08640.25620.1219
2023-09-20160.70230.54810.1542100.53440.548-0.01360.00010.1678
2023-10-18160.64470.51830.1264100.47510.5178-0.04270.00050.1691
2023-11-15160.60640.50690.0995100.45480.4947-0.03990.01220.1394
2023-12-20160.57160.47540.0962100.4260.4734-0.04740.0020.1436
2024-01-17160.52240.42480.0976100.43720.43720-0.01240.0976
2024-02-14160.4940.42280.0712100.41360.4258-0.0122-0.0030.0834
2024-03-20160.45330.40080.0525100.46650.41620.0503-0.01540.0022

chart_skew()

As a default state, the put and call skew smiles from the expiration in position 1, contained in the list data.expirations[1], are displayed.

data.chart_skew()

VIX IV Skew

Multiple expirations can be displayed by entering a list to the expirations parameter.

data.chart_skew(expirations=[data.expirations[6],data.expirations[10]])

Multiple Expirations - VIX IV Skew

The forward curve is also callable by strike.

data.chart_skew(strike = 20)

VIX IV Skew at $20 Strike