mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-01 23:12:21 +00:00
* add model file for Montreal Options Exchange * mypy fixes * define attributes under __init__ * type error fix * another pylint fix * adds tests for tmx_model * black * mypy * adds expirations test and re-records * black * capture error message in test * mypy * add __docformat__ line * improves get_all_ticker_symbols * removes python magic command for new cell * adds TMX as source for SDK chains * starts on a new method for loading options data returning a standardized object * add load_options as SDK endpoint * intrinio response - not complete * adds tradier to load_options * add source attribute to options object * restore legacy nasdaq last price function * yFinance underlying_price fixes * yFinance model fix * adds cboe to sdk options load * table fix * creates options_chains_model.py and updates SDK map * docstrings added for the class. * updates tmx_model tests * fix options_controller test * adds cboe_model tests * spelling in docstring * ruff - unused import * mypy fixes * more mypy fixes * pylint * attempt to manually resolve merge conflict. * nasdaq_model fix * adds test coverage for options/nasdaq_model * docstrings update for nasdaq_model * mypy fix * adds unit testing for options_chains_model * adds additional tests for intrinio_model * unused import fix * fix for .TO symbol and TMX EOD chains * make CBOE Pydantic * cboe update * adds switch for pydantic output from all sources * black * index options error handling for Intrinio * add warning message for index options from Intrinio * tmx_model enhancements * cleans up get_ticker_iv() in cboe_model * fix ticker info for index symbols from cboe * typo in comments * adds test for tradier_model.load_options * cboe optionType as lower case * add function for calculating chains stats * black * trailmap for calculate_chains_stats * adds test for calculate_stats() * more details to nasdaq.underlying_price * typo in docstrings * mypy - options_chains_model.py * black - options_chains_model.py * pylint options_chains_model.py * standardize response from intrinio underlying price * add function to validate input of function * missed type hint * additional error handling for stats * adds DTE as column for all sources * adds strategies function and input validation * add yFinance test for load_options() * add Nasdaq test for load_options() * tests for new functions in options_chains_model * update sdk trailmap * rewrite tests * fixes for tests * fix tmx_model test * more pytest * pytest.. * add vertical call spread function * some cleanup * update nasdaq tests * more cleanup * black * pylint * black * ruff * black * pylint * black * pylint.. * tests rewrite * more pytest * recapture tests * Different tests were collected between gw1 and gw0 * adds vertical spreads * vertical_put_spread * improve calculate_stats * mypy * edge cases * black * update tmx,yfinance tests * new cboe tests * new tmx_model tests * fix nasdaq test * test updates * fix nasdaq tests * add test_options_chains_model * refactor data sources * black * pylint * fixing stuff * forgot a file.. * codespell * linting * mypy... * refactor OptionsChains class * pylint * reconfigure SDK entry point * fix error handling when data request fails * ruff * pylint * pylint * Add inheritance and a repr string * add method for skew * add method for skew * fix nasdaq test * add skew to tests --------- Co-authored-by: James Maslek <jmaslek11@gmail.com>
707 lines
20 KiB
Python
707 lines
20 KiB
Python
"""Option helper functions"""
|
|
__docformat__ = "numpy"
|
|
|
|
import logging
|
|
from datetime import datetime, timedelta
|
|
from math import e, log
|
|
from typing import Optional, Tuple, Union
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
from pydantic import BaseModel, Extra, Field
|
|
from scipy.stats import norm
|
|
|
|
from openbb_terminal.decorators import log_start_end
|
|
from openbb_terminal.helper_funcs import get_rf
|
|
from openbb_terminal.rich_config import console
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# pylint: disable=too-many-arguments
|
|
|
|
|
|
def get_strikes(
|
|
min_sp: float, max_sp: float, chain: pd.DataFrame
|
|
) -> Tuple[float, float]:
|
|
"""Function to get the min and max strikes for a given expiry"""
|
|
|
|
min_strike = chain["strike"].min() if min_sp == -1 else min_sp
|
|
max_strike = chain["strike"].max() if max_sp == -1 else max_sp
|
|
|
|
return min_strike, max_strike
|
|
|
|
|
|
def get_loss_at_strike(strike: float, chain: pd.DataFrame) -> float:
|
|
"""Function to get the loss at the given expiry
|
|
|
|
Parameters
|
|
----------
|
|
strike : Union[int,float]
|
|
Value to calculate total loss at
|
|
chain : Dataframe:
|
|
Dataframe containing at least strike and openInterest
|
|
|
|
Returns
|
|
-------
|
|
loss : Union[float,int]
|
|
Total loss
|
|
"""
|
|
|
|
itm_calls = chain[chain.index < strike][["OI_call"]]
|
|
itm_calls["loss"] = (strike - itm_calls.index) * itm_calls["OI_call"]
|
|
call_loss = itm_calls["loss"].sum()
|
|
|
|
itm_puts = chain[chain.index > strike][["OI_put"]]
|
|
itm_puts["loss"] = (itm_puts.index - strike) * itm_puts["OI_put"]
|
|
put_loss = itm_puts.loss.sum()
|
|
loss = call_loss + put_loss
|
|
|
|
return loss
|
|
|
|
|
|
def calculate_max_pain(chain: pd.DataFrame) -> Union[int, float]:
|
|
"""Returns the max pain for a given call/put dataframe
|
|
|
|
Parameters
|
|
----------
|
|
chain : DataFrame
|
|
Dataframe to calculate value from
|
|
|
|
Returns
|
|
-------
|
|
max_pain : int
|
|
Max pain value
|
|
"""
|
|
|
|
strikes = np.array(chain.index)
|
|
if ("OI_call" not in chain.columns) or ("OI_put" not in chain.columns):
|
|
console.print("Incorrect columns. Unable to parse max pain")
|
|
return np.nan
|
|
|
|
loss = [get_loss_at_strike(price_at_exp, chain) for price_at_exp in strikes]
|
|
chain["loss"] = loss
|
|
max_pain = chain["loss"].idxmin()
|
|
|
|
return max_pain
|
|
|
|
|
|
def convert(orig: str, to: str) -> float:
|
|
"""Convert a string to a specific type of number
|
|
Parameters
|
|
----------
|
|
orig : str
|
|
String to convert
|
|
Returns
|
|
-------
|
|
number : float
|
|
Decimal value of string
|
|
"""
|
|
clean = orig.replace("%", "").replace("+", "").replace(",", "")
|
|
if to == "%":
|
|
return float(clean) / 100
|
|
if to == ",":
|
|
return float(clean)
|
|
raise ValueError("Invalid to format, please use '%' or ','.")
|
|
|
|
|
|
def rn_payoff(x: str, df: pd.DataFrame, put: bool, delta: int, rf: float) -> float:
|
|
"""The risk neutral payoff for a stock
|
|
Parameters
|
|
----------
|
|
x : str
|
|
Strike price
|
|
df : pd.DataFrame
|
|
Dataframe of stocks prices and probabilities
|
|
put : bool
|
|
Whether the asset is a put or a call
|
|
delta : int
|
|
Difference between today's date and expirations date in days
|
|
rf : float
|
|
The current risk-free rate
|
|
|
|
Returns
|
|
-------
|
|
number : float
|
|
Risk neutral value of option
|
|
"""
|
|
if put:
|
|
df["Gain"] = np.where(x > df["Price"], x - df["Price"], 0)
|
|
else:
|
|
df["Gain"] = np.where(x < df["Price"], df["Price"] - x, 0)
|
|
df["Vals"] = df["Chance"] * df["Gain"]
|
|
risk_free = (1 + rf) ** (delta / 365)
|
|
return sum(df["Vals"]) / risk_free
|
|
|
|
|
|
@log_start_end(log=logger)
|
|
def process_option_chain(data: pd.DataFrame, source: str) -> pd.DataFrame:
|
|
"""
|
|
Create an option chain DataFrame from the given symbol.
|
|
Does additional processing in order to get some homogeneous between the sources.
|
|
|
|
Parameters
|
|
----------
|
|
data : pd.DataFrame
|
|
The option chain data
|
|
source: str, optional
|
|
The source of the data. Valid values are "Tradier", "Nasdaq", and
|
|
"YahooFinance". The default value is "Tradier".
|
|
|
|
Returns
|
|
-------
|
|
pd.DataFrame
|
|
A DataFrame containing the option chain data, with columns as specified
|
|
in the `option_chain_column_mapping` mapping, and an additional column
|
|
"optionType" that indicates whether the option is a call or a put.
|
|
"""
|
|
if source == "Tradier":
|
|
df = data.rename(columns=option_chain_column_mapping["Tradier"])
|
|
|
|
elif source == "Nasdaq":
|
|
call_columns = ["expiration", "strike"] + [
|
|
col for col in data.columns if col.startswith("c_")
|
|
]
|
|
calls = data[call_columns].rename(columns=option_chain_column_mapping["Nasdaq"])
|
|
calls["optionType"] = "call"
|
|
|
|
put_columns = ["expiration", "strike"] + [
|
|
col for col in data.columns if col.startswith("p_")
|
|
]
|
|
puts = data[put_columns].rename(columns=option_chain_column_mapping["Nasdaq"])
|
|
puts["optionType"] = "put"
|
|
|
|
df = pd.concat([calls, puts]).drop_duplicates()
|
|
|
|
elif source == "Intrinio":
|
|
df = data.copy()
|
|
|
|
elif source == "YahooFinance":
|
|
call_columns = ["expiration", "strike"] + [
|
|
col for col in data.columns if col.endswith("_c")
|
|
]
|
|
calls = data[call_columns].rename(
|
|
columns=option_chain_column_mapping["YahooFinance"]
|
|
)
|
|
calls["optionType"] = "call"
|
|
|
|
put_columns = ["expiration", "strike"] + [
|
|
col for col in data.columns if col.endswith("_p")
|
|
]
|
|
puts = data[put_columns].rename(
|
|
columns=option_chain_column_mapping["YahooFinance"]
|
|
)
|
|
puts["optionType"] = "put"
|
|
|
|
df = pd.concat([calls, puts]).drop_duplicates()
|
|
|
|
else:
|
|
df = pd.DataFrame()
|
|
|
|
return df
|
|
|
|
|
|
@log_start_end(log=logger)
|
|
def get_greeks(
|
|
current_price: float,
|
|
calls: pd.DataFrame,
|
|
puts: pd.DataFrame,
|
|
expire: str,
|
|
div_cont: float = 0,
|
|
rf: Optional[float] = None,
|
|
opt_type: int = 0,
|
|
show_all: bool = False,
|
|
show_extra_greeks: bool = False,
|
|
) -> pd.DataFrame:
|
|
"""
|
|
Gets the greeks for a given option
|
|
|
|
Parameters
|
|
----------
|
|
current_price: float
|
|
The current price of the underlying
|
|
div_cont: float
|
|
The dividend continuous rate
|
|
expire: str
|
|
The date of expiration
|
|
rf: float
|
|
The risk-free rate
|
|
opt_type: Union[-1, 0, 1]
|
|
The option type 1 is for call and -1 is for put
|
|
mini: float
|
|
The minimum strike price to include in the table
|
|
maxi: float
|
|
The maximum strike price to include in the table
|
|
show_all: bool
|
|
Whether to show all columns from puts and calls
|
|
show_extra_greeks: bool
|
|
Whether to show all greeks
|
|
"""
|
|
|
|
chain = pd.DataFrame()
|
|
|
|
if opt_type not in [-1, 0, 1]:
|
|
console.print("[red]Invalid option type[/red]")
|
|
elif opt_type == 1:
|
|
chain = calls
|
|
elif opt_type == -1:
|
|
chain = puts
|
|
else:
|
|
chain = pd.concat([calls, puts])
|
|
|
|
chain_columns = chain.columns.tolist()
|
|
if not all(
|
|
col in chain_columns for col in ["strike", "impliedVolatility", "optionType"]
|
|
):
|
|
if "delta" not in chain_columns:
|
|
console.print(
|
|
"[red]It's not possible to calculate the greeks without the following "
|
|
"columns: `strike`, `impliedVolatility`, `optionType`.\n[/red]"
|
|
)
|
|
return pd.DataFrame()
|
|
|
|
risk_free = rf if rf is not None else get_rf()
|
|
expire_dt = datetime.strptime(expire, "%Y-%m-%d")
|
|
dif = (expire_dt - datetime.now() + timedelta(hours=16)).total_seconds() / (
|
|
60 * 60 * 24
|
|
)
|
|
strikes = []
|
|
for _, row in chain.iterrows():
|
|
vol = row["impliedVolatility"]
|
|
is_call = row["optionType"] == "call"
|
|
result = (
|
|
[row[col] for col in row.index.tolist()]
|
|
if show_all
|
|
else [row[col] for col in ["strike", "impliedVolatility"]]
|
|
)
|
|
try:
|
|
opt = Option(
|
|
current_price, row["strike"], risk_free, div_cont, dif, vol, is_call
|
|
)
|
|
tmp = [
|
|
opt.Delta(),
|
|
opt.Gamma(),
|
|
opt.Vega(),
|
|
opt.Theta(),
|
|
]
|
|
result += tmp
|
|
|
|
if show_extra_greeks:
|
|
result += [
|
|
opt.Rho(),
|
|
opt.Phi(),
|
|
opt.Charm(),
|
|
opt.Vanna(0.01),
|
|
opt.Vomma(0.01),
|
|
]
|
|
except ValueError:
|
|
result += [np.nan] * 4
|
|
|
|
if show_extra_greeks:
|
|
result += [np.nan] * 5
|
|
strikes.append(result)
|
|
|
|
greek_columns = [
|
|
"Delta",
|
|
"Gamma",
|
|
"Vega",
|
|
"Theta",
|
|
]
|
|
columns = (
|
|
chain_columns + greek_columns
|
|
if show_all
|
|
else ["Strike", "Implied Vol"] + greek_columns
|
|
)
|
|
|
|
if show_extra_greeks:
|
|
additional_columns = ["Rho", "Phi", "Charm", "Vanna", "Vomma"]
|
|
columns += additional_columns
|
|
|
|
df = pd.DataFrame(strikes, columns=columns)
|
|
|
|
return df
|
|
|
|
|
|
opt_chain_cols = {
|
|
"lastTradeDate": {"format": "date", "label": "Last Trade Date"},
|
|
"strike": {"format": "${x:.2f}", "label": "Strike"},
|
|
"lastPrice": {"format": "${x:.2f}", "label": "Last Price"},
|
|
"bid": {"format": "${x:.2f}", "label": "Bid"},
|
|
"ask": {"format": "${x:.2f}", "label": "Ask"},
|
|
"change": {"format": "${x:.2f}", "label": "Change"},
|
|
"percentChange": {"format": "{x:.2f}%", "label": "Percent Change"},
|
|
"volume": {"format": "{x:.2f}", "label": "Volume"},
|
|
"openInterest": {"format": "", "label": "Open Interest"},
|
|
"impliedVolatility": {"format": "{x:.2f}", "label": "Implied Volatility"},
|
|
}
|
|
|
|
option_chain_column_mapping = {
|
|
"Nasdaq": {
|
|
"strike": "strike",
|
|
"c_Last": "last",
|
|
"c_Change": "change",
|
|
"c_Bid": "bid",
|
|
"c_Ask": "ask",
|
|
"c_Volume": "volume",
|
|
"c_Openinterest": "openInterest",
|
|
"p_Last": "last",
|
|
"p_Change": "change",
|
|
"p_Bid": "bid",
|
|
"p_Ask": "ask",
|
|
"p_Volume": "volume",
|
|
"p_Openinterest": "openInterest",
|
|
},
|
|
"Tradier": {
|
|
"open_interest": "openInterest",
|
|
"option_type": "optionType",
|
|
},
|
|
"YahooFinance": {
|
|
"contractSymbol_c": "contractSymbol",
|
|
"lastTradeDate_c": "lastTradeDate",
|
|
"strike": "strike",
|
|
"lastPrice_c": "lastPrice",
|
|
"bid_c": "bid",
|
|
"ask_c": "ask",
|
|
"change_c": "change",
|
|
"percentChange_c": "percentChange",
|
|
"volume_c": "volume",
|
|
"openInterest_c": "openInterest",
|
|
"impliedVolatility_c": "impliedVolatility",
|
|
"inTheMoney_c": "inTheMoney",
|
|
"contractSize_c": "contractSize",
|
|
"currency_c": "currency",
|
|
"contractSymbol_p": "contractSymbol",
|
|
"lastTradeDate_p": "lastTradeDate",
|
|
"lastPrice_p": "lastPrice",
|
|
"bid_p": "bid",
|
|
"ask_p": "ask",
|
|
"change_p": "change",
|
|
"percentChange_p": "percentChange",
|
|
"volume_p": "volume",
|
|
"openInterest_p": "openInterest",
|
|
"impliedVolatility_p": "impliedVolatility",
|
|
"inTheMoney_p": "inTheMoney",
|
|
"contractSize_p": "contractSize",
|
|
"currency_p": "currency",
|
|
"expiration": "expiration",
|
|
},
|
|
}
|
|
|
|
|
|
class Option:
|
|
def __init__(
|
|
self,
|
|
s: float,
|
|
k: float,
|
|
rf: float,
|
|
div_cont: float,
|
|
expiry: float,
|
|
vol: float,
|
|
is_call: bool = True,
|
|
):
|
|
"""
|
|
Class for getting the greeks of options. Inspiration from:
|
|
http://www.smileofthales.com/computation/option-pricing-python-inheritance/
|
|
|
|
Parameters
|
|
----------
|
|
s : float
|
|
The underlying asset price
|
|
k : float
|
|
The option strike price
|
|
rf : float
|
|
The risk-free rate
|
|
div_cont : float
|
|
The dividend continuous rate
|
|
expiry : float
|
|
The number of days until expiration
|
|
vol : float
|
|
The underlying volatility for an option
|
|
is_call : bool
|
|
True if call, False if put
|
|
"""
|
|
if expiry <= 0:
|
|
raise ValueError("Expiry must be greater than 0")
|
|
if vol <= 0:
|
|
raise ValueError("Volatility must be greater than 0")
|
|
if s <= 0:
|
|
raise ValueError("Price must be greater than 0")
|
|
if k <= 0:
|
|
raise ValueError("Strike must be greater than 0")
|
|
self.Type = 1 if is_call else -1
|
|
self.price = float(s)
|
|
self.strike = float(k)
|
|
self.risk_free = float(rf)
|
|
self.div_cont = float(div_cont)
|
|
self.exp_time = float(expiry) / 365.0
|
|
self._sigma = float(vol)
|
|
self.sigmaT = self._sigma * self.exp_time**0.5
|
|
|
|
@property
|
|
def d1(self):
|
|
return (
|
|
log(self.price / self.strike)
|
|
+ (self.risk_free - self.div_cont + 0.5 * (self.sigma**2)) * self.exp_time
|
|
) / self.sigmaT
|
|
|
|
@property
|
|
def d2(self):
|
|
return self.d1 - self.sigmaT
|
|
|
|
@property
|
|
def sigma(self):
|
|
return self._sigma
|
|
|
|
@sigma.setter
|
|
def sigma(self, val):
|
|
self._sigma = val
|
|
self.sigmaT = val * self.exp_time**0.5
|
|
|
|
def Premium(self):
|
|
tmpprem = self.Type * (
|
|
self.price
|
|
* e ** (-self.div_cont * self.exp_time)
|
|
* norm.cdf(self.Type * self.d1)
|
|
- self.strike
|
|
* e ** (-self.risk_free * self.exp_time)
|
|
* norm.cdf(self.Type * self.d2)
|
|
)
|
|
return tmpprem
|
|
|
|
# 1st order greeks
|
|
|
|
def Delta(self):
|
|
dfq = np.exp(-self.div_cont * self.exp_time)
|
|
if self.Type == 1:
|
|
return dfq * norm.cdf(self.d1)
|
|
return dfq * (norm.cdf(self.d1) - 1)
|
|
|
|
def Vega(self):
|
|
"""Vega for 1% change in vol"""
|
|
dfq = np.exp(-self.div_cont * self.exp_time)
|
|
return 0.01 * self.price * dfq * norm.pdf(self.d1) * self.exp_time**0.5
|
|
|
|
def Theta(self, time_factor=1.0 / 365.0):
|
|
"""Theta, by default for 1 calendar day change"""
|
|
df = np.exp(-self.risk_free * self.exp_time)
|
|
dfq = np.exp(-self.div_cont * self.exp_time)
|
|
tmptheta = time_factor * (
|
|
-0.5
|
|
* self.price
|
|
* dfq
|
|
* norm.pdf(self.d1)
|
|
* self.sigma
|
|
/ (self.exp_time**0.5)
|
|
+ self.Type
|
|
* (
|
|
self.div_cont * self.price * dfq * norm.cdf(self.Type * self.d1)
|
|
- self.risk_free * self.strike * df * norm.cdf(self.Type * self.d2)
|
|
)
|
|
)
|
|
return tmptheta
|
|
|
|
def Rho(self):
|
|
df = np.exp(-self.risk_free * self.exp_time)
|
|
return (
|
|
self.Type
|
|
* self.strike
|
|
* self.exp_time
|
|
* df
|
|
* 0.01
|
|
* norm.cdf(self.Type * self.d2)
|
|
)
|
|
|
|
def Phi(self):
|
|
dfq = np.exp(-self.div_cont * self.exp_time)
|
|
return (
|
|
0.01
|
|
* -self.Type
|
|
* self.exp_time
|
|
* self.price
|
|
* dfq
|
|
* norm.cdf(self.Type * self.d1)
|
|
)
|
|
|
|
# 2nd order greeks
|
|
|
|
def Gamma(self):
|
|
dfq = np.exp(-self.div_cont * self.exp_time)
|
|
return dfq * norm.pdf(self.d1) / (self.price * self.sigmaT)
|
|
|
|
def Charm(self, time_factor=1.0 / 365.0):
|
|
"""Calculates Charm, by default for 1 calendar day change"""
|
|
dfq = np.exp(-self.div_cont * self.exp_time)
|
|
cdf = norm.cdf(self.Type * self.d1)
|
|
return (
|
|
time_factor
|
|
* -dfq
|
|
* (
|
|
norm.pdf(self.d1)
|
|
* (
|
|
(self.risk_free - self.div_cont) / (self.sigmaT)
|
|
- self.d2 / (2 * self.exp_time)
|
|
)
|
|
+ (self.Type * -self.div_cont) * cdf
|
|
)
|
|
)
|
|
|
|
def Vanna(self, change: float):
|
|
"""
|
|
Vanna for a given percent change in volatility
|
|
|
|
Parameters
|
|
----------
|
|
change : float
|
|
The change in volatility
|
|
|
|
Returns
|
|
----------
|
|
num : float
|
|
The Vanna
|
|
|
|
"""
|
|
|
|
return (
|
|
change
|
|
* -(e ** (-self.div_cont * self.exp_time))
|
|
* self.d2
|
|
/ self.sigma
|
|
* norm.pdf(self.d1)
|
|
)
|
|
|
|
def Vomma(self, change):
|
|
"""
|
|
Vomma for a given percent change in volatility
|
|
|
|
Parameters
|
|
----------
|
|
change : float
|
|
The change in volatility
|
|
|
|
Returns
|
|
----------
|
|
num : float
|
|
The Vomma
|
|
|
|
"""
|
|
return (
|
|
change
|
|
* np.exp(-self.div_cont * self.exp_time)
|
|
* self.d1
|
|
* self.d2
|
|
* np.sqrt(self.exp_time)
|
|
* self.price
|
|
* norm.pdf(self.d1)
|
|
/ self._sigma
|
|
)
|
|
|
|
|
|
def get_dte(chain: pd.DataFrame) -> pd.DataFrame:
|
|
"""
|
|
Returns a new column containing the DTE as an integer, including 0.
|
|
Requires the chain to have the column labeled as, expiration.
|
|
"""
|
|
if "expiration" not in chain.columns:
|
|
raise ValueError("No column labeled 'expiration' was found.")
|
|
|
|
now = datetime.now()
|
|
temp = pd.DatetimeIndex(chain.expiration)
|
|
temp_ = (temp - now).days + 1
|
|
chain["dte"] = temp_
|
|
|
|
return chain
|
|
|
|
|
|
class Options: # pylint: disable=too-few-public-methods,too-many-instance-attributes
|
|
"""The Options data object.
|
|
|
|
Returns
|
|
-------
|
|
object: Options
|
|
chains: pd.DataFrame
|
|
The complete options chain for the ticker.
|
|
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.
|
|
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.
|
|
"""
|
|
|
|
chains = pd.DataFrame
|
|
expirations: list
|
|
strikes: list
|
|
last_price: float
|
|
underlying_name: str
|
|
underlying_price: pd.Series
|
|
hasIV: bool
|
|
hasGreeks: bool
|
|
symbol: str
|
|
source: str
|
|
date: str
|
|
SYMBOLS: pd.DataFrame
|
|
|
|
|
|
class PydanticOptions( # type: ignore [call-arg]
|
|
BaseModel, extra=Extra.allow
|
|
): # pylint: disable=too-few-public-methods
|
|
|
|
"""Pydantic model for the Options data object.
|
|
|
|
Returns
|
|
-------
|
|
Pydantic: Options
|
|
chains: dict
|
|
The complete options chain for the ticker.
|
|
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: dict
|
|
The price and recent performance of the underlying asset.
|
|
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: dict
|
|
The symbol directory for the source, when available.
|
|
"""
|
|
|
|
chains: dict = Field(default=None)
|
|
expirations: list = Field(default=None)
|
|
strikes: list = Field(default=None)
|
|
last_price: float = Field(default=None)
|
|
underlying_name: str = Field(default=None)
|
|
underlying_price: dict = Field(default=None)
|
|
hasIV: bool = Field(default=False)
|
|
hasGreeks: bool = Field(default=False)
|
|
symbol: str = Field(default=None)
|
|
source: str = Field(default=None)
|
|
date: str = Field(default=None)
|
|
SYMBOLS: dict = Field(default=None)
|