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.
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)
Symbol | Company Name | DPM Name | Post/Station |
---|---|---|---|
SPY | SPDR S&P 500 ETF TR TR UNIT | Morgan Stanley & Co. LLC | 8/1 |
SPYG | SPDR SER TR PRTFLO S&P500 GW | Belvedere Trading LLC | 6/1 |
SPYD | SPDR SER TR PRTFLO S&P500 HI | Citadel Securities LLC | 6/1 |
SPYV | SPDR SER TR PRTFLO S&P500 VL | Belvedere Trading LLC | 6/1 |
NSPY | UNIFIED SER TR NIGHTSHARES 500 | Wolverine Trading, LLC | 3/1 |
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.
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 OI | 2018 |
Calls OI | 45875 |
Total OI | 47893 |
OI Ratio | 0.04 |
Puts OTM | 873 |
Calls OTM | 45747 |
Puts ITM | 1145 |
Calls ITM | 128 |
OTM Ratio | 0.02 |
ITM Percent | 2.66 |
Puts Volume | 264 |
Calls Volume | 2156 |
Total Volume | 2420 |
Volume Ratio | 0.12 |
Vol-OI Ratio | 0.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"])
Expiration | Puts OI | Calls OI | Total OI | OI Ratio | Puts Volume | Calls Volume | Total Volume | Volume Ratio | Vol-OI Ratio |
---|---|---|---|---|---|---|---|---|---|
2023-07-19 | 1569778 | 3323396 | 4893174 | 0.47 | 113460 | 130416 | 243876 | 0.87 | 0.05 |
2023-07-26 | 1855 | 29273 | 31128 | 0.06 | 264 | 2156 | 2420 | 0.12 | 0.08 |
2023-08-02 | 1154 | 2498 | 3652 | 0.46 | 12 | 786 | 798 | 0.02 | 0.22 |
2023-08-09 | 330 | 961 | 1291 | 0.34 | 43 | 354 | 397 | 0.12 | 0.31 |
2023-08-16 | 907980 | 2246707 | 3154687 | 0.4 | 48668 | 197148 | 245816 | 0.25 | 0.08 |
2023-08-23 | 0 | 49 | 49 | 0 | 7 | 145 | 152 | 0.05 | 3.1 |
2023-09-20 | 614369 | 2097742 | 2712111 | 0.29 | 20750 | 19260 | 40010 | 1.08 | 0.01 |
2023-10-18 | 165239 | 1099858 | 1265097 | 0.15 | 3304 | 14912 | 18216 | 0.22 | 0.01 |
2023-11-15 | 70142 | 742698 | 812840 | 0.09 | 82 | 514 | 596 | 0.16 | 0 |
2023-12-20 | 44580 | 259815 | 304395 | 0.17 | 10797 | 12471 | 23268 | 0.87 | 0.08 |
2024-01-17 | 20860 | 43733 | 64593 | 0.48 | 23574 | 23690 | 47264 | 1 | 0.73 |
2024-02-14 | 1347 | 6567 | 7914 | 0.21 | 67 | 203 | 270 | 0.33 | 0.03 |
2024-03-20 | 63 | 1861 | 1924 | 0.03 | 8 | 219 | 227 | 0.04 | 0.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()
data.chart_stats(by="strike", oi=True)
data.chart_stats(by="strike", oi=True, percent=False)
data.chart_stats(ratios=True)
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()
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 | |
---|---|
Symbol | VIX |
Underlying Price | 13.34 |
Expiration | 2023-08-16 |
DTE | 31 |
Strike 1 | 13.0 |
Strike 2 | 12.5 |
Strike 1 Premium | 2.9 |
Strike 2 Premium | 3.4 |
Cost | 0.5 |
Cost Percent | 3.7481 |
Breakeven Lower | 13.0 |
Breakeven Lower Percent | -2.5487 |
Breakeven Upper | nan |
Breakeven Upper Percent | nan |
Max Profit | 0.0 |
Max Loss | -0.5 |
Payoff Ratio | 0.0 |
data.get_vertical_put_spread(30,13,12.5)
Bull Put Spread | |
---|---|
Symbol | VIX |
Underlying Price | 13.34 |
Expiration | 2023-08-16 |
DTE | 31 |
Strike 1 | 13.0 |
Strike 2 | 12.5 |
Strike 1 Premium | -0.17 |
Strike 2 Premium | 0.12 |
Cost | -0.05 |
Cost Percent | 0.3748 |
Breakeven Lower | nan |
Breakeven Lower Percent | nan |
Breakeven Upper | 12.95 |
Breakeven Upper Percent | 2.92 |
Max Profit | 0.05 |
Max Loss | -0.45 |
Payoff Ratio | 0.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-16 | 2023-08-16 | 2023-08-16 | 2023-08-16 | 2023-08-16 | 2023-08-16 | |
---|---|---|---|---|---|---|
DTE | 31 | 31 | 31 | 31 | 31 | 31 |
Strategy | Long Straddle | Long Strangle | Synthetic Long | Synthetic Short | Bull Call Spread | Bear Put Spread |
Underlying Price | 13.34 | 13.34 | 13.34 | 13.34 | 13.34 | 13.34 |
Strike 1 | 13.5 | 17.0 | 14.0 | 16.0 | 20.0 | 12.0 |
Strike 2 | 13.5 | 10.0 | 14.0 | 16.0 | 15.0 | 15.0 |
Strike 1 Premium | 2.62 | 1.28 | 2.31 | -1.46 | -0.83 | -0.04 |
Strike 2 Premium | 0.33 | 0.01 | -0.49 | 1.74 | 1.83 | 1.04 |
Cost | 2.95 | 1.29 | 1.82 | 0.28 | 1.0 | 1.0 |
Cost Percent | 22.1139 | 9.6702 | 13.6432 | 2.099 | 7.4963 | 7.4963 |
Breakeven Upper | 16.45 | 18.29 | 15.82 | nan | nan | nan |
Breakeven Upper Percent | 23.3133 | 37.1064 | 18.5907 | nan | nan | nan |
Breakeven Lower | 10.55 | 8.71 | nan | 15.72 | 16.0 | 14.0 |
Breakeven Lower Percent | -20.9145 | -34.7076 | nan | 17.8411 | 19.94 | 17.5412 |
Max Profit | inf | inf | inf | 15.72 | 4.0 | 2.0 |
Max Loss | -2.95 | -1.29 | -15.82 | inf | -1.0 | -1.0 |
Payoff Ratio | inf | inf | nan | nan | 4.0 | 2.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()
The implied volatility can also be visualized as the forward curve at a specific strike or % moneyness.
data.chart_volatility(strike=20)
data.chart_volatility(moneyness=30)
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])
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")
Expiration | Strike | Option Type | IV | ATM IV | Skew | |
---|---|---|---|---|---|---|
116 | 2023-07-26 | 12 | put | 1.1136 | 0.9283 | 0.1853 |
117 | 2023-07-26 | 12.5 | put | 1.0246 | 0.9283 | 0.0963 |
118 | 2023-07-26 | 13 | put | 0.9666 | 0.9283 | 0.0383 |
119 | 2023-07-26 | 13.5 | put | 0.9283 | 0.9283 | 0 |
120 | 2023-07-26 | 14 | call | 0.4994 | 0.4994 | 0 |
121 | 2023-07-26 | 14 | put | 0.8702 | 0.9283 | -0.0581 |
122 | 2023-07-26 | 14.5 | call | 0.6156 | 0.4994 | 0.1162 |
123 | 2023-07-26 | 14.5 | put | 0.8899 | 0.9283 | -0.0384 |
124 | 2023-07-26 | 15 | call | 0.6245 | 0.4994 | 0.1251 |
125 | 2023-07-26 | 15 | put | 0.9002 | 0.9283 | -0.0281 |
vix.get_skew(moneyness=20)
expiration | Call Strike | Call IV | Call ATM IV | Call Skew | Put Strike | Put IV | Put ATM IV | Put Skew | ATM Skew | IV Skew |
---|---|---|---|---|---|---|---|---|---|---|
2023-07-19 | 16 | 1.0996 | 0.599 | 0.5006 | 10.5 | 1.0505 | 0.6328 | 0.4177 | -0.0338 | 0.0829 |
2023-07-26 | 16 | 0.8708 | 0.4994 | 0.3714 | 10.5 | 0.9101 | 0.9283 | -0.0182 | -0.4289 | 0.3896 |
2023-08-02 | 16 | 0.855 | 0.5026 | 0.3524 | 10.5 | 0.7438 | 0.6755 | 0.0683 | -0.1729 | 0.2841 |
2023-08-09 | 16 | 0.7861 | 0.4926 | 0.2935 | 10.5 | 0.6712 | 0.6575 | 0.0137 | -0.1649 | 0.2798 |
2023-08-16 | 16 | 0.8364 | 0.6284 | 0.208 | 10.5 | 0.6041 | 0.6117 | -0.0076 | 0.0167 | 0.2156 |
2023-08-23 | 16 | 0.9273 | 0.8918 | 0.0355 | 10.5 | 0.5492 | 0.6356 | -0.0864 | 0.2562 | 0.1219 |
2023-09-20 | 16 | 0.7023 | 0.5481 | 0.1542 | 10 | 0.5344 | 0.548 | -0.0136 | 0.0001 | 0.1678 |
2023-10-18 | 16 | 0.6447 | 0.5183 | 0.1264 | 10 | 0.4751 | 0.5178 | -0.0427 | 0.0005 | 0.1691 |
2023-11-15 | 16 | 0.6064 | 0.5069 | 0.0995 | 10 | 0.4548 | 0.4947 | -0.0399 | 0.0122 | 0.1394 |
2023-12-20 | 16 | 0.5716 | 0.4754 | 0.0962 | 10 | 0.426 | 0.4734 | -0.0474 | 0.002 | 0.1436 |
2024-01-17 | 16 | 0.5224 | 0.4248 | 0.0976 | 10 | 0.4372 | 0.4372 | 0 | -0.0124 | 0.0976 |
2024-02-14 | 16 | 0.494 | 0.4228 | 0.0712 | 10 | 0.4136 | 0.4258 | -0.0122 | -0.003 | 0.0834 |
2024-03-20 | 16 | 0.4533 | 0.4008 | 0.0525 | 10 | 0.4665 | 0.4162 | 0.0503 | -0.0154 | 0.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()
Multiple expirations can be displayed by entering a list to the expirations
parameter.
data.chart_skew(expirations=[data.expirations[6],data.expirations[10]])
The forward curve is also callable by strike.
data.chart_skew(strike = 20)