Files
OpenBB/openbb_terminal/dashboards/stream/pages/Options.py
Colin Delahunty 1ca7fd9beb Improves the settings/userdata command, and upgrade ruff (#5359)
* Began the fax

* Bumped ruff

* Fixed a BUNCH of ruff errors

* Fixed a lot of ruff errors

* Simplify if statements

* Fixed black

* Updated some stuff

* Updated some stuff

* A lot more ruff fixes

* Added a fix

* Added a fix

* Fixed mypy

* Fixed some stuff

* Reverted one thing

* Small fix

* Small fix

* Small fix

* Added fix

* Added fix

* Update requirements
2023-08-22 20:11:48 +00:00

955 lines
35 KiB
Python

# type: ignore
# pylint: disable=[W0621,R1714]
from typing import Any, Tuple
import pandas as pd
import streamlit as st
from openbb_terminal.core.plots.plotly_helper import OpenBBFigure
from openbb_terminal.core.session.current_system import set_system_variable
from openbb_terminal.dashboards.stream import streamlit_helpers as st_helpers
from openbb_terminal.stocks.options.cboe_model import INDEXES, SYMBOLS
from openbb_terminal.stocks.options.options_chains_model import (
get_nearest_call_strike,
get_nearest_otm_strike,
get_nearest_put_strike,
)
from openbb_terminal.stocks.options.options_sdk_helper import (
OptionsChains,
load_options_chains,
)
EXCEPTIONS = ["NDX", "RUT"]
analysis_type: str = ""
strike_price: float = 0
moneyness: float = 0
strangle_moneyness: float = 0
price_data = pd.DataFrame()
strategy_data = pd.DataFrame()
title: str = ""
_strikes: Any = None
chart_data_type: str = ""
target_column: dict[str, str] = {
"Last Price": "lastTradePrice",
"Bid Price": "bid",
"Ask Price": "ask",
"Theoretical Price": "theoretical",
"Breakeven Price": "Breakeven",
"Open Interest": "openInterest",
"Volume": "volume",
"Implied Volatility": "impliedVolatility",
"Gamma": "gamma",
"Theta": "theta",
"Vega": "vega",
"Delta Dollars": "DEX",
"GEX Per 1% Move": "GEX",
}
strategy_target_column_dict = {
"Cost of Position": "Cost",
"Cost as % of Underlying": "Cost Percent",
}
surface_choice_dict = {
"OTM Only": "otm",
"ITM Only": "itm",
"Calls Only": "calls",
"Puts Only": "puts",
}
chains_df = pd.DataFrame()
symbol_choices = SYMBOLS.sort_index().reset_index()
default_symbol = int(symbol_choices.query("`Symbol` == 'SPY'").index[0])
chains_strikes: dict[str, float] = {}
pd.options.plotting.backend = "plotly"
# Suppressing sdk logs
set_system_variable("LOGGING_SUPPRESS", True)
st.set_page_config(
layout="wide",
page_title="CBOE Options Dashboard",
initial_sidebar_state="expanded",
menu_items={
"Get help": "https://discord.com/invite/Y4HDyB6Ypu",
},
)
st_helpers.set_current_page("Options")
st_helpers.set_css()
def format_plotly(fig: OpenBBFigure):
fig.update_layout(
margin=dict(t=40),
autosize=False,
width=1050,
height=700,
title=dict(y=0.99, x=0.5, xanchor="center", yanchor="top", automargin=True),
legend=dict(bgcolor="rgba(0,0,0,0)"),
)
return fig
@st.cache_data(show_spinner=False, experimental_allow_widgets=True)
def load_data(ticker):
df = load_options_chains(ticker)
_calls = df.chains[df.chains["optionType"] == "call"].copy()
_puts = df.chains[df.chains["optionType"] == "put"].copy()
_calls.loc[:, ("$ To Spot")] = (
(_calls.loc[:, ("strike")]) + (_calls.loc[:, ("ask")]) - (df.last_price)
)
_calls.loc[:, ("% To Spot")] = (_calls.loc[:, ("$ To Spot")] / df.last_price) * 100
_calls.loc[:, ("Breakeven")] = _calls.loc[:, ("strike")] + _calls.loc[:, ("ask")]
_calls.loc[:, ("DEX")] = (
(_calls.loc[:, ("delta")] * 100)
* (_calls.loc[:, ("openInterest")])
* df.last_price
)
_calls["DEX"] = _calls["DEX"].convert_dtypes(convert_floating=True)
_calls.loc[:, ("GEX")] = (
_calls.loc[:, ("gamma")]
* 100
* _calls.loc[:, ("openInterest")]
* (df.last_price * df.last_price)
* 0.01
)
_calls.GEX = _calls.GEX.convert_dtypes(convert_floating=True)
_calls.set_index(keys=["expiration", "strike", "optionType"], inplace=True)
_puts.loc[:, ("$ To Spot")] = (
(_puts.loc[:, ("strike")]) - (_puts.loc[:, ("ask")]) - (df.last_price)
)
_puts.loc[:, ("% To Spot")] = (_puts.loc[:, ("$ To Spot")] / df.last_price) * 100
_puts.loc[:, ("Breakeven")] = _puts.loc[:, ("strike")] - _puts.loc[:, ("ask")]
_puts.loc[:, ("DEX")] = (
(_puts.loc[:, ("delta")] * 100)
* (_puts.loc[:, ("openInterest")])
* df.last_price
)
_puts.loc[:, ("GEX")] = (
_puts.loc[:, ("gamma")]
* 100
* _puts.loc[:, ("openInterest")]
* (df.last_price * df.last_price)
* 0.01
* (-1)
)
_puts.GEX = _puts.GEX.convert_dtypes(convert_floating=True)
_puts["DEX"] = _puts["DEX"].convert_dtypes(convert_floating=True)
_puts.set_index(keys=["expiration", "strike", "optionType"], inplace=True)
_calls.GEX = round(_calls.GEX, ndigits=2)
_calls["DEX"] = round(_calls["DEX"], ndigits=2)
_puts.GEX = round(_puts.GEX, ndigits=2)
_puts["DEX"] = round(_puts["DEX"], ndigits=2)
df.chains = pd.concat([_puts, _calls])
df.chains.sort_index(inplace=True)
df.chains.reset_index(inplace=True)
return df
def get_exposure(df: OptionsChains) -> Tuple[pd.DataFrame, pd.DataFrame]:
by_strike = pd.DataFrame()
by_expiration = pd.DataFrame()
puts_by_strike = (
df.chains.query("`optionType` == 'put'").groupby("strike")[["DEX", "GEX"]].sum()
)
puts_by_strike.columns = ["Put DEX", "Put GEX"]
calls_by_strike = (
df.chains.query("`optionType` == 'call'")
.groupby("strike")[["DEX", "GEX"]]
.sum()
)
calls_by_strike.columns = ["Call DEX", "Call GEX"]
by_strike = pd.concat([calls_by_strike, puts_by_strike], axis=1)
puts_by_expiration = (
df.chains.query("`optionType` == 'put'")
.groupby("expiration")[["DEX", "GEX"]]
.sum()
)
puts_by_expiration.columns = ["Put DEX", "Put GEX"]
calls_by_expiration = (
df.chains.query("`optionType` == 'call'")
.groupby("expiration")[["DEX", "GEX"]]
.sum()
)
calls_by_expiration.columns = ["Call DEX", "Call GEX"]
by_expiration = pd.concat([calls_by_expiration, puts_by_expiration], axis=1)
return by_strike.astype("int64"), by_expiration.astype("int64")
def get_highest_oi(df: OptionsChains) -> pd.DataFrame:
highest_oi = df.chains[df.chains["openInterest"] == max(df.chains["openInterest"])][
[
"optionType",
"strike",
"dte",
"openInterest",
"volume",
"impliedVolatility",
"bid",
"ask",
"Breakeven",
]
]
highest_oi.columns = [
"Type",
"Strike",
"DTE",
"OI",
"Volume",
"IV",
"Bid",
"Ask",
"Breakeven",
]
return highest_oi
def get_highest_volume(df: OptionsChains) -> pd.DataFrame:
highest_volume = df.chains[df.chains["volume"] == max(df.chains["volume"])][
[
"optionType",
"strike",
"dte",
"openInterest",
"volume",
"impliedVolatility",
"bid",
"ask",
"Breakeven",
]
]
highest_volume.columns = [
"Type",
"Strike",
"DTE",
"OI",
"Volume",
"IV",
"Bid",
"Ask",
"Breakeven",
]
return highest_volume
with st.sidebar:
ticker = st.selectbox(
label="Ticker",
options=symbol_choices["Symbol"].tolist(),
index=default_symbol,
key="ticker",
)
df = load_data(ticker)
chains_df = df.chains
if ticker == "":
st.write("Please enter a symbol")
if hasattr(df, "underlying_name"):
ticker_good = True
stats = df.get_stats()
net_calls = stats.sum()["Calls OI"].astype(int)
net_puts = stats.sum()["Puts OI"].astype(int)
pcr_ratio = round((net_puts / net_calls), 4)
net_calls_vol = stats.sum()["Calls Volume"].astype(int)
net_puts_vol = stats.sum()["Puts Volume"].astype(int)
straddle_30d = df.get_straddle()
st.write(df.underlying_name)
st.write("Last Price: ", f"${df.last_price:0,.2f}")
_change = round(df.underlying_price["changePercent"], 2)
st.write("Change: ", f"{_change:0,.2f}%")
st.write(
f"Cost of {straddle_30d.loc['DTE']['Long Straddle']} DTE Straddle: ",
f"${round(straddle_30d.loc['Cost']['Long Straddle'], 2)}",
)
if df.underlying_price["ivThirty"] != 0:
st.write("IV 30: ", str(df.underlying_price["ivThirty"]))
if ticker.upper() not in INDEXES and ticker.upper() not in EXCEPTIONS:
st.write("Stock Volume :", format(df.underlying_price["volume"], ","))
st.write("Call Volume: ", format(net_calls_vol, ","))
st.write("Put Volume: ", format(net_puts_vol, ","))
st.write("Put/Call Ratio: ", str(pcr_ratio))
analysis_type = st.selectbox(
"Analysis Type", options=["Charts", "Tables"], key="analysis_type"
)
if analysis_type == "Tables":
table_choices = ["Chains", "Stats"]
table_choice = st.selectbox("Table Type", options=table_choices)
if table_choice == "Chains":
chains_selections = ["% OTM", "Delta", "None"]
chains_select = st.selectbox(
"Limit Range of Results",
options=chains_selections,
key="chains_select",
)
if chains_select == "% OTM":
chains_moneyness: float = st.number_input(
label="% OTM Range",
min_value=0.01,
max_value=99.99,
value=2.0,
step=0.25,
)
chains_strikes = get_nearest_otm_strike(df, chains_moneyness)
if chains_select == "Delta":
delta_choice: float = st.number_input(
label="Delta Value",
min_value=0.01,
max_value=1.0,
value=0.5,
step=0.05,
)
chains_choice = st.selectbox(
"Chain Type", options=["Calls", "Puts", "Both"], key="chains_choice"
)
expiration_choices = ["All"]
expiration_choices.extend(df.expirations)
expiration_choice = st.selectbox(
"Expiration Date",
options=expiration_choices,
key="expiration_choice",
)
if analysis_type == "Charts":
stats_type: str = ""
chart_data_type = st.selectbox(
"Chart Data Type",
options=["Stats", "Strikes", "Strategies", "Volatility"],
key="chart_data_type",
)
expiry = "All"
if chart_data_type == "Stats":
stats_type = st.selectbox(
"Stat Type",
options=["Open Interest", "Volume", "Ratios"],
key="stats_type",
)
if stats_type in ("Open Interest", "Volume"):
is_percent = st.checkbox(
"Percent of Total", value=False, key="is_percent"
)
if is_percent is False and stats_type == "Open Interest":
expiries = ["All"]
expiries.extend(df.expirations)
expiry = st.selectbox("Expiry", options=expiries, key="expiry")
if chart_data_type == "Strikes":
strike_choice = st.selectbox(
"Strike Selection Type",
options=(["Single Strike", "Separate Calls and Puts", "% OTM"]),
key="strike_choice",
)
if strike_choice == "Separate Calls and Puts":
_default_call = get_nearest_call_strike(
df, strike_price=df.last_price
)
_default_put = get_nearest_put_strike(
df, strike_price=df.last_price
)
_default_strikes = pd.Series(df.strikes)
default_call = int(
_default_strikes[_default_strikes == _default_call].index[0]
)
default_put = int(
_default_strikes[_default_strikes == _default_put].index[0]
)
col1, col2 = st.columns(2)
with col1:
_call = st.selectbox(
"Call Strike",
options=df.strikes,
index=default_call,
key="call_strike",
)
with col2:
_put = st.selectbox(
"Put Strike",
options=df.strikes,
index=default_put,
key="put_strike",
)
_strikes = {"call": _call, "put": _put}
if strike_choice == "% OTM":
moneyness: float = st.number_input(
label="% OTM Moneyness",
min_value=0.01,
max_value=99.99,
value=2.0,
step=0.25,
key="moneyness",
)
_strikes = get_nearest_otm_strike(df, moneyness)
if strike_choice == "Single Strike":
default_strike_price = get_nearest_call_strike(
df, strike_price=df.last_price
)
_strikes = pd.Series(df.strikes)
default_strike = int(
_strikes[_strikes == default_strike_price].index[0]
)
strike_price = st.selectbox(
"Strike Price",
options=df.strikes,
index=default_strike,
key="strike_price",
)
strike_data_point = st.selectbox(
"Data Point",
options=list(target_column.keys()),
key="strike_data_point",
)
if chart_data_type == "Strategies":
_strikes = pd.Series(df.strikes)
strategy_choice = st.selectbox(
"Strategy Type",
options=(
[
"Straddle",
"Strangle",
"Synthetic Long",
"Synthetic Short",
"Vertical Call",
"Vertical Put",
]
),
key="strategy_choice",
)
if strategy_choice == "Strangle":
strangle_moneyness: float = st.number_input(
label="% OTM Moneyness",
min_value=0.01,
max_value=99.99,
value=2.0,
step=0.25,
key="strangle_moneyness",
)
if strategy_choice == "Straddle":
default_strike_price = get_nearest_call_strike(
df, strike_price=df.last_price
)
default_strike = int(
_strikes[_strikes == default_strike_price].index[0]
)
straddle_strike: float = st.selectbox(
"Strike Price",
options=df.strikes,
index=default_strike,
key="straddle_strike",
)
if strategy_choice in ("Synthetic Long", "Synthetic Short"):
default_strike_price = get_nearest_call_strike(
df, strike_price=df.last_price
)
default_strike = int(
_strikes[_strikes == default_strike_price].index[0]
)
synthetic_strike = st.selectbox(
"Strike Price",
options=df.strikes,
index=default_strike,
key="synthetic_strike",
)
if strategy_choice in ("Vertical Call", "Vertical Put"):
default_strike_price1 = get_nearest_call_strike(
df,
strike_price=df.last_price + 5
if strategy_choice == "Vertical Call"
else df.last_price - 5,
)
default_strike_price2 = get_nearest_call_strike(
df, strike_price=df.last_price
)
default_strike1 = int(
_strikes[_strikes == default_strike_price1].index[0]
)
default_strike2 = int(
_strikes[_strikes == default_strike_price2].index[0]
)
col1, col2 = st.columns(2)
with col1:
strike1 = st.selectbox(
"Sold Strike Price",
options=df.strikes,
index=default_strike1,
key="strike1",
)
with col2:
strike2 = st.selectbox(
"Bought Strike Price",
options=df.strikes,
index=default_strike2,
key="strike2",
)
strategy_target_column = st.selectbox(
"Data Type",
options=list(strategy_target_column_dict.keys()),
key="strategy_target_column",
)
if chart_data_type == "Volatility":
vol_choices = ["Smile", "Skew", "Surface"]
vol_choice = st.selectbox(
"Volatility Type", options=vol_choices, index=0, key="vol_choice"
)
if vol_choice in ("Smile", "Skew"):
if vol_choice == "Smile":
col1, col2 = st.columns(2)
with col1:
with_volume = st.checkbox(
"With Volume", value=False, key="with_volume"
)
with col2:
with_oi = st.checkbox("With OI", value=False, key="with_oi")
if vol_choice == "Skew":
otm_only = st.checkbox("OTM Only", value=False, key="otm_only")
with st.expander("Select Expiration Dates"):
expiration_choice = st.multiselect(
"Expiration Date",
options=df.expirations,
default=df.expirations[2],
key="expiration_choice",
)
if vol_choice == "Surface":
surface_choices = [
"Calls Only",
"Puts Only",
"OTM Only",
"ITM Only",
]
surface_choice = st.selectbox(
"Surface Type",
options=surface_choices,
index=2,
key="surface_choice",
)
else:
st.write("Please enter a valid symbol.")
ticker_good = False
if analysis_type == "Tables" and table_choice == "Chains" and ticker_good is True:
if chains_select == "% OTM":
upper = chains_strikes["call"]
lower = chains_strikes["put"]
chains_df = df.chains.query("@lower <= `strike` <= @upper")
if chains_select == "Delta":
upper_call = delta_choice + 0.01
lower_call = delta_choice - 0.01
upper_put = (delta_choice + 0.01) * (-1)
lower_put = (delta_choice - 0.01) * (-1)
chains_df = df.chains.query(
"@lower_call <= `delta` <= @upper_call or @lower_put >= `delta` >= @upper_put"
)
if chains_select == "None":
chains_df = df.chains
if expiration_choice != "All":
chains_df = chains_df[chains_df["expiration"] == expiration_choice]
if expiration_choice == "All":
chains_df = chains_df[chains_df["dte"] >= 0]
chains_df = chains_df[
[
"strike",
"dte",
"optionType",
"theoretical",
"bidSize",
"bid",
"ask",
"askSize",
"lastTradePrice",
"openInterest",
"volume",
"impliedVolatility",
"delta",
"gamma",
"theta",
"rho",
"vega",
"open",
"high",
"low",
"previousClose",
"DEX",
"GEX",
"Breakeven",
"$ To Spot",
"% To Spot",
]
]
chains_df = chains_df.rename(
columns={
"strike": "Strike",
"dte": "DTE",
"optionType": "Type",
"theoretical": "Theoretical",
"bidSize": "Bid Size",
"bid": "Bid",
"ask": "Ask",
"askSize": "Ask Size",
"lastTradePrice": "Last",
"openInterest": "OI",
"volume": "Volume",
"impliedVolatility": "IV",
"delta": "Delta",
"gamma": "Gamma",
"theta": "Theta",
"rho": "Rho",
"vega": "Vega",
"open": "Open",
"high": "High",
"low": "Low",
"previousClose": "Prev Close",
}
)
chains_df.Theoretical = round(chains_df.Theoretical, 2)
chains_df = chains_df.set_index("Strike")
chains_df = chains_df[chains_df["Last"] > 0]
if chains_choice == "Calls":
chains_df = chains_df[chains_df["Type"] == "call"]
if chains_choice == "Puts":
chains_df = chains_df[chains_df["Type"] == "put"]
st.dataframe(chains_df, use_container_width=True, height=700)
if analysis_type == "Tables" and table_choice == "Stats" and ticker_good is True:
exposure_by_strike, exposure_by_expiration = get_exposure(df)
stats_df_expiration = df.get_stats()
stats_df_strike = df.get_stats("strike")
sc1, sc2, sc3, sc4, sc5 = st.columns(5)
with sc1:
st.write("Total OI: ", format(stats_df_expiration["Total OI"].sum(), ","))
with sc2:
st.write("Call OI: ", format(stats_df_expiration["Calls OI"].sum(), ","))
with sc3:
st.write("Put OI: ", format(stats_df_expiration["Puts OI"].sum(), ","))
with sc4:
st.write("Call DEX: $", format(exposure_by_expiration["Call DEX"].sum(), ","))
with sc5:
st.write(
"Put DEX: $", format(abs(exposure_by_expiration["Put DEX"]).sum(), ",")
)
with st.expander("Stats by Expiration", expanded=True):
st.dataframe(stats_df_expiration, use_container_width=True)
with st.expander("Stats by Strike", expanded=False):
st.dataframe(stats_df_strike, use_container_width=True)
with st.expander("Delta Dollars and GEX per 1% Move", expanded=False):
col1, col2 = st.columns(2)
with col1:
st.dataframe(exposure_by_expiration.abs(), use_container_width=True)
with col2:
st.dataframe(exposure_by_strike.abs(), use_container_width=True)
if analysis_type == "Charts" and ticker_good is True and chart_data_type == "Stats":
if stats_type == "Open Interest" and expiry != "All":
fig_oi_exp = df.chart_stats(
"strike", expiry=expiry, external_axes=True, oi=True, percent=False
)
fig_oi_exp = format_plotly(fig_oi_exp)
st.plotly_chart(
fig_oi_exp,
use_container_width=True,
)
elif stats_type in ("Open Interest", "Volume"):
tab1, tab2 = st.tabs(["By Expiration", "By Strike"])
with tab1:
if stats_type == "Open Interest":
fig_oi_exp = df.chart_stats(
percent=bool(is_percent), oi=True, external_axes=True
)
fig_oi_exp = format_plotly(fig_oi_exp)
st.plotly_chart(fig_oi_exp, use_container_width=True)
if stats_type == "Volume":
fig_vol_exp = df.chart_stats(
percent=bool(is_percent), oi=False, external_axes=True
)
fig_vol_exp = format_plotly(fig_vol_exp)
st.plotly_chart(fig_vol_exp, use_container_width=True)
with tab2:
if stats_type == "Open Interest":
fig_oi_strike = df.chart_stats(
"strike", percent=bool(is_percent), oi=True, external_axes=True
)
fig_oi_strike = format_plotly(fig_oi_strike)
st.plotly_chart(fig_oi_strike, use_container_width=True)
if stats_type == "Volume":
fig_vol_exp = df.chart_stats(
"strike", percent=bool(is_percent), oi=False, external_axes=True
)
fig_vol_exp = format_plotly(fig_vol_exp)
st.plotly_chart(fig_vol_exp, use_container_width=True)
elif stats_type == "Ratios":
ratios_fig = df.chart_stats(ratios=True, external_axes=True)
ratios_fig.update_layout(
legend=dict(
orientation="h",
yanchor="top",
y=1,
xanchor="left",
x=0.01,
)
)
ratios_fig = format_plotly(ratios_fig)
st.plotly_chart(
ratios_fig,
use_container_width=True,
config=dict(
scrollZoom=True,
displaylogo=False,
),
)
if analysis_type == "Charts" and chart_data_type == "Strikes" and ticker_good is True:
title = f"{strike_data_point} of {df.symbol} Options @ ${strike_price} Strike Price"
title = (
f"{strike_data_point} of {df.symbol} Options @ {moneyness}% OTM"
if strike_choice == "% OTM"
else title
)
title = (
f"{strike_data_point} of {df.symbol} Options"
if strike_choice == "Separate Calls and Puts"
else title
)
title = (
f"Gamma Exposure per 1% Move of {df.symbol}"
if strike_data_point == "GEX Per 1% Move"
else title
)
if strike_choice == "Single Strike":
_price_data = df.chains[df.chains["strike"] == strike_price]
call_price_data = _price_data[_price_data["optionType"] == "call"]
put_price_data = _price_data[_price_data["optionType"] == "put"]
call_price_data = call_price_data.drop_duplicates("expiration").set_index(
"expiration"
)
put_price_data = put_price_data.drop_duplicates("expiration").set_index(
"expiration"
)
price_data["Call"] = call_price_data[target_column[strike_data_point]]
price_data["Put"] = put_price_data[target_column[strike_data_point]]
if strike_choice in ("Separate Calls and Puts", "% OTM"):
call_price_data = (
df.chains[df.chains["strike"] == _strikes["call"]]
.query("`optionType` == 'call'")
.drop_duplicates("expiration")
.set_index("expiration")
)
put_price_data = (
df.chains[df.chains["strike"] == _strikes["put"]]
.query("`optionType` == 'put'")
.drop_duplicates("expiration")
.set_index("expiration")
)
price_data["Call"] = call_price_data[target_column[strike_data_point]]
price_data["Put"] = put_price_data[target_column[strike_data_point]]
fig_price_data = OpenBBFigure()
fig_price_data.add_scatter(
x=price_data.index,
y=price_data["Call"],
mode="lines+markers",
name="Calls"
if strike_choice == "Single Strike"
else f"Calls @ ${_strikes['call']}",
marker=dict(color="blue"),
)
fig_price_data.add_scatter(
x=price_data.index,
y=price_data["Put"],
mode="lines+markers",
name="Puts"
if strike_choice == "Single Strike"
else f"Puts @ {_strikes['put']}",
marker=dict(color="red"),
)
fig_price_data.update_xaxes(type="category")
fig_price_data.update_layout(
title=dict(text=title, x=0.5, y=0.97),
legend=dict(
orientation="h",
yanchor="top",
y=1.125,
xanchor="left",
x=0.01,
),
)
fig_price_data = format_plotly(fig_price_data)
st.plotly_chart(
fig_price_data,
use_container_width=True,
config=dict(
scrollZoom=True,
displaylogo=False,
),
)
if (
analysis_type == "Charts"
and chart_data_type == "Strategies"
and ticker_good is True
):
if strategy_choice == "Strangle":
title = f"Cost of {df.symbol} Strangle @ {strangle_moneyness}% OTM"
strategy_data = df.get_strategies(strangle_moneyness=strangle_moneyness)
if strategy_choice == "Straddle":
title = f"Cost of {df.symbol} Straddle @ ${straddle_strike} Strike"
strategy_data = df.get_strategies(straddle_strike=straddle_strike)
if strategy_choice == "Synthetic Long":
title = f"Cost of {df.symbol} Synthetic Long @ ${synthetic_strike} Strike"
strategy_data = df.get_strategies(synthetic_longs=synthetic_strike)
if strategy_choice == "Synthetic Short":
title = f"Cost of {df.symbol} Synthetic Short @ ${synthetic_strike} Strike"
strategy_data = df.get_strategies(synthetic_shorts=synthetic_strike)
if strategy_choice == "Vertical Call":
strategy_data = df.get_strategies(vertical_calls=[strike1, strike2])
strategy_name = strategy_data.iloc[0]["Strategy"]
title = f"Cost of {df.symbol} {strategy_name} @ ${strike1} & ${strike2} Strikes"
if strategy_choice == "Vertical Put":
strategy_data = df.get_strategies(vertical_puts=[strike1, strike2])
strategy_name = strategy_data.iloc[0]["Strategy"]
title = f"Cost of {df.symbol} {strategy_name} @ ${strike1} & ${strike2} Strikes"
title = (
title + " As % of Underlying Price"
if strategy_target_column == "Cost as % of Underlying"
else title
)
fig_strategy = OpenBBFigure()
fig_strategy.add_scatter(
x=strategy_data.Expiration,
y=strategy_data[strategy_target_column_dict[strategy_target_column]],
mode="lines+markers",
name="Cost of Long Strangle",
marker=dict(color="red"),
)
fig_strategy.update_xaxes(type="category")
fig_strategy.update_layout(title=dict(text=title, x=0.5, y=0.97))
fig_strategy = format_plotly(fig_strategy)
st.plotly_chart(
fig_strategy,
use_container_width=True,
config=dict(
scrollZoom=True,
displaylogo=False,
),
)
if (
analysis_type == "Charts"
and chart_data_type == "Volatility"
and ticker_good is True
):
if vol_choice == "Smile":
if len(expiration_choice) == 0:
expiration_choice = df.expirations[2]
if len(expiration_choice) > 5:
expiration_choice = expiration_choice[0:5]
smile_fig = df.chart_volatility(
expirations=expiration_choice,
oi=with_oi,
volume=with_volume,
external_axes=True,
)
smile_fig = format_plotly(smile_fig)
smile_fig.update_layout(
legend=dict(
orientation="h", yanchor="top", y=1.025, xanchor="center", x=0.5
)
)
st.plotly_chart(
smile_fig,
use_container_width=True,
config=dict(
scrollZoom=True,
displaylogo=False,
),
)
if vol_choice == "Skew":
if len(expiration_choice) == 0:
expiration_choice = df.expirations[2]
if otm_only is False and len(expiration_choice) > 5:
expiration_choice = expiration_choice[0:5]
if otm_only is True and len(expiration_choice) > 10:
expiration_choice = expiration_choice[0:10]
skew_fig = df.chart_skew(
expirations=expiration_choice, otm_only=otm_only, external_axes=True
)
skew_fig = format_plotly(skew_fig)
skew_fig.update_layout(
legend=dict(
orientation="h", yanchor="top", y=1.025, xanchor="center", x=0.5
)
)
st.plotly_chart(
skew_fig,
use_container_width=True,
config=dict(
scrollZoom=True,
displaylogo=False,
),
)
if vol_choice == "Surface":
dte_ranges = df.chains.dte.unique().tolist()
col1, col2, col3, col4 = st.columns(4)
with col1:
near_dte_limit = int(
st.select_slider(
"Near DTE Boundary",
options=dte_ranges,
value=dte_ranges[0],
key="near_dte_limit",
)
)
with col2:
far_dte_limit = int(
st.select_slider(
"Far DTE Boundary",
options=dte_ranges,
value=dte_ranges[-1],
key="far_dte_limit",
)
)
near = near_dte_limit if near_dte_limit < far_dte_limit else far_dte_limit
far = far_dte_limit if near_dte_limit < far_dte_limit else near_dte_limit
if near == far:
far += 1
dte_range = [far, near]
with col3:
lower_strike = float(
st.select_slider(
"Lower Strike",
options=df.strikes,
value=df.strikes[0],
key="lower_strike",
)
)
with col4:
upper_strike = float(
st.select_slider(
"Upper Strike",
options=df.strikes,
value=df.strikes[-1],
key="upper_strike",
)
)
lower = lower_strike if lower_strike < upper_strike else upper_strike
upper = upper_strike if lower_strike < upper_strike else lower_strike
strike_range = [lower, upper]
surface_fig = df.chart_surface(
surface_choice_dict[surface_choice],
dte_range,
strike_range,
external_axes=True,
)
surface_fig = format_plotly(surface_fig)
st.plotly_chart(surface_fig, use_container_width=True)