|
|
|
|
|
|
|
|
import streamlit as st |
|
|
import pandas as pd |
|
|
import numpy as np |
|
|
import plotly.express as px |
|
|
|
|
|
import os |
|
|
import time |
|
|
|
|
|
from dotenv import load_dotenv |
|
|
from datetime import datetime |
|
|
|
|
|
from utils import upload_to_hf_dataset, download_from_hf_dataset, load_hf_dataset |
|
|
|
|
|
|
|
|
|
|
|
current_datetime = datetime.now().strftime("%Y-%m-%d") |
|
|
|
|
|
|
|
|
load_dotenv() |
|
|
|
|
|
|
|
|
dataset_name_TradingView_input = os.getenv("dataset_name_TradingView_input") |
|
|
|
|
|
|
|
|
dataset_name_YfOptions_output = os.getenv("dataset_name_YfOptions_output") |
|
|
|
|
|
|
|
|
HF_TOKEN_YfOptions = os.getenv("HF_TOKEN_YfOptions") |
|
|
|
|
|
|
|
|
st.set_page_config(page_title="Option Data Screener App", page_icon="π", layout="wide") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@st.cache_data |
|
|
def get_TD_DF(current_datetime): |
|
|
|
|
|
|
|
|
DF = load_hf_dataset( |
|
|
"america.csv", HF_TOKEN_YfOptions, dataset_name_TradingView_input |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
tickerlst = list(DF.query("`Market Capitalization`>10e9").Ticker) |
|
|
|
|
|
return DF, tickerlst |
|
|
|
|
|
|
|
|
@st.cache_data |
|
|
def get_options_DF(current_datetime): |
|
|
DF = load_hf_dataset( |
|
|
"optionchain.csv", HF_TOKEN_YfOptions, dataset_name_YfOptions_output |
|
|
) |
|
|
return DF |
|
|
|
|
|
|
|
|
def convert_df(df): |
|
|
return df.to_csv().encode("utf-8") |
|
|
|
|
|
|
|
|
def convert_df_watchlist(df): |
|
|
return ",".join(map(str, df["Ticker"].unique())) |
|
|
|
|
|
|
|
|
@st.cache_data |
|
|
def get_options_merge(current_datetime): |
|
|
DF, tickerlst = get_TD_DF(current_datetime) |
|
|
|
|
|
DF_options_origin = get_options_DF(current_datetime) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DF_options_origin["Volume_OpenInterest_Ratio"] = ( |
|
|
DF_options_origin["volume"] |
|
|
.div(DF_options_origin["openInterest"]) |
|
|
.replace([np.inf, -np.inf], 0) |
|
|
.fillna(0) |
|
|
) |
|
|
|
|
|
|
|
|
DF_options_origin["Ticker"] = DF_options_origin["contractSymbol"].str.extract( |
|
|
r"([A-Z]+)" |
|
|
) |
|
|
TD_interestedColumns = ["Ticker", "Market Capitalization", "Relative Volume"] |
|
|
DF_options_merged = pd.merge( |
|
|
DF_options_origin, DF[TD_interestedColumns], on="Ticker", how="left" |
|
|
) |
|
|
|
|
|
|
|
|
volume_pivot = ( |
|
|
DF_options_merged.groupby(["Ticker", "Type"])["volume"].sum().unstack() |
|
|
) |
|
|
volume_pivot.columns = ["Call_Volume", "Put_Volume"] |
|
|
|
|
|
|
|
|
openInterest_pivot = ( |
|
|
DF_options_merged.groupby(["Ticker", "Type"])["openInterest"].sum().unstack() |
|
|
) |
|
|
openInterest_pivot.columns = ["Call_openInterest", "Put_openInterest"] |
|
|
|
|
|
|
|
|
merged_df = volume_pivot.merge( |
|
|
openInterest_pivot, left_index=True, right_index=True |
|
|
) |
|
|
|
|
|
|
|
|
merged_df["Put_Call_Volume_Ratio"] = ( |
|
|
merged_df["Put_Volume"] / merged_df["Call_Volume"] |
|
|
) |
|
|
|
|
|
|
|
|
merged_df["Put_Call_OI_Ratio"] = ( |
|
|
merged_df["Put_openInterest"] / merged_df["Call_openInterest"] |
|
|
) |
|
|
|
|
|
DFtotal = pd.merge( |
|
|
DF_options_merged, merged_df, left_on="Ticker", right_index=True, how="left" |
|
|
) |
|
|
DFtotal["Moneyvolume"] = DFtotal["lastPrice"] * DFtotal["volume"] *100 |
|
|
DFtotal["MoneyopenInterest"] = DFtotal["lastPrice"] * DFtotal["openInterest"] * 100 |
|
|
return DFtotal, tickerlst |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DF_options, tickerlst = get_options_merge(current_datetime) |
|
|
|
|
|
|
|
|
st.title("π Unusual Options Activity Dashboard") |
|
|
|
|
|
st.write(f"Number of avialable tickers: **{len(tickerlst)}**") |
|
|
|
|
|
st.write(f"Number of options contract records: **{len(DF_options)}** with volume of **{round(DF_options['volume'].sum()/1e+6,2)}M** contracts and **{round(DF_options['openInterest'].sum()/1e+6,2)}M** open interest") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if st.sidebar.button("Options Statistics", use_container_width=True): |
|
|
st.header("Statistics of Options Data") |
|
|
st.write(f'Value of Today volume options contracts: **{round(DF_options["Moneyvolume"].sum()/1e+9,2)}$B**') |
|
|
st.write(f'Value of open interest options contracts: **{round(DF_options["MoneyopenInterest"].sum()/1e+9,2)}$B**') |
|
|
|
|
|
st.write(f'Maximum Volume {int( DF_options["volume"].max())} beloing to Ticker **{DF_options.loc[DF_options["volume"].idxmax(), "Ticker"]}** and contractSymbol {DF_options.loc[DF_options["volume"].idxmax(), "contractSymbol"]}') |
|
|
st.write(f'Maximum Open Interest { int(DF_options["openInterest"].max())} beloing to Ticker **{DF_options.loc[DF_options["openInterest"].idxmax(), "Ticker"]}** and contractSymbol {DF_options.loc[DF_options["openInterest"].idxmax(), "contractSymbol"]}') |
|
|
st.write(f'Maximum Implied Volatility { round(DF_options["impliedVolatility"].max(),2)} beloing to Ticker **{DF_options.loc[DF_options["impliedVolatility"].idxmax(), "Ticker"]}**') |
|
|
st.write(f'Maximum Volume/Open Interest Ratio { DF_options["Volume_OpenInterest_Ratio"].max()} beloing to Ticker {DF_options.loc[DF_options["Volume_OpenInterest_Ratio"].idxmax(), "Ticker"]}') |
|
|
st.write(f'Maximum Relative Volume { round(DF_options["Relative Volume"].max(),2)} beloing to Ticker {DF_options.loc[DF_options["Relative Volume"].idxmax(), "Ticker"]}') |
|
|
|
|
|
|
|
|
|
|
|
fig = px.bar( |
|
|
DF_options.nlargest(100, "volume"), |
|
|
x="Ticker", |
|
|
y="volume", |
|
|
color="Type", |
|
|
title="Top Options by Volume", |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig.update_layout( |
|
|
xaxis_title="Ticker", |
|
|
yaxis_title="Volume", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
fig = px.bar( |
|
|
DF_options.nlargest(100, "openInterest"), |
|
|
x="Ticker", |
|
|
y="openInterest", |
|
|
color="Type", |
|
|
title="Top Options by Open Interest", |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig.update_layout( |
|
|
xaxis_title="Ticker", |
|
|
yaxis_title="Open Interest", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.sidebar.header("Controls") |
|
|
st.sidebar.markdown("### Filter Options Data") |
|
|
|
|
|
|
|
|
volume_range = st.sidebar.slider( |
|
|
"Volume Range", |
|
|
min_value=0, |
|
|
max_value=DF_options["volume"].max().astype(int), |
|
|
value=(0, DF_options["volume"].max().astype(int)), |
|
|
step=100, |
|
|
) |
|
|
|
|
|
open_interest_range = st.sidebar.slider( |
|
|
"Open Interest Range", |
|
|
min_value=0, |
|
|
max_value=DF_options["openInterest"].max().astype(int), |
|
|
value=(0, DF_options["openInterest"].max().astype(int)), |
|
|
step=100, |
|
|
) |
|
|
|
|
|
|
|
|
vol_oi_ratio_range = st.sidebar.slider( |
|
|
"Volume/Open Interest Ratio Range", |
|
|
min_value=0.0, |
|
|
max_value= np.nanmax( |
|
|
DF_options["Volume_OpenInterest_Ratio"][ |
|
|
~np.isinf(DF_options["Volume_OpenInterest_Ratio"]) |
|
|
] |
|
|
), |
|
|
value=(0.0, 10.0), |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
step=0.1, |
|
|
) |
|
|
|
|
|
|
|
|
expiration_dates = sorted(DF_options["expirationDate"].unique()) |
|
|
selected_expiry = st.sidebar.multiselect( |
|
|
"Select Expiration Dates", |
|
|
options=expiration_dates, |
|
|
default=expiration_dates[:4], |
|
|
) |
|
|
|
|
|
|
|
|
st.sidebar.markdown("---") |
|
|
|
|
|
st.sidebar.markdown("### Filter Stock Data") |
|
|
min_relative_volume = st.sidebar.number_input( |
|
|
"Minimum Relative Volume", min_value=0.0, value=1.5, step=0.1 |
|
|
) |
|
|
|
|
|
|
|
|
put_call_volume_range = st.sidebar.slider( |
|
|
"Put/Call Volume Ratio Range", |
|
|
min_value=0.0, |
|
|
max_value=np.nanmax( |
|
|
DF_options["Put_Call_Volume_Ratio"][ |
|
|
~np.isinf(DF_options["Put_Call_Volume_Ratio"]) |
|
|
] |
|
|
), |
|
|
value=(0.0, 0.6), |
|
|
step=0.1, |
|
|
) |
|
|
|
|
|
put_call_oi_range = st.sidebar.slider( |
|
|
"Put/Call OI Ratio Range", |
|
|
min_value=0.0, |
|
|
max_value=np.nanmax( |
|
|
DF_options["Put_Call_OI_Ratio"][~np.isinf(DF_options["Put_Call_OI_Ratio"])] |
|
|
), |
|
|
value=(0.0, 3.0), |
|
|
step=0.1, |
|
|
) |
|
|
|
|
|
if st.sidebar.button("Filter", use_container_width=True): |
|
|
|
|
|
st.header("Filtering Options Data") |
|
|
|
|
|
|
|
|
filtered_df = DF_options[ |
|
|
(DF_options["volume"] >= volume_range[0]) |
|
|
& (DF_options["volume"] <= volume_range[1]) |
|
|
& (DF_options["openInterest"] >= open_interest_range[0]) |
|
|
& (DF_options["openInterest"] <= open_interest_range[1]) |
|
|
& (DF_options["Relative Volume"] >= min_relative_volume) |
|
|
& (DF_options["Put_Call_Volume_Ratio"] >= put_call_volume_range[0]) |
|
|
& (DF_options["Put_Call_Volume_Ratio"] <= put_call_volume_range[1]) |
|
|
& (DF_options["Put_Call_OI_Ratio"] >= put_call_oi_range[0]) |
|
|
& (DF_options["Put_Call_OI_Ratio"] <= put_call_oi_range[1]) |
|
|
& (DF_options["Volume_OpenInterest_Ratio"] >= vol_oi_ratio_range[0]) |
|
|
& (DF_options["Volume_OpenInterest_Ratio"] <= vol_oi_ratio_range[1]) |
|
|
& (DF_options["expirationDate"].isin(selected_expiry)) |
|
|
] |
|
|
|
|
|
st.write(f"Filtered records: {len(filtered_df)} rows") |
|
|
|
|
|
interestedColumns = [ |
|
|
"contractSymbol", |
|
|
"expirationDate", |
|
|
"volume", |
|
|
"openInterest", |
|
|
"impliedVolatility", |
|
|
"Volume_OpenInterest_Ratio", |
|
|
"Relative Volume", |
|
|
"Put_Call_Volume_Ratio", |
|
|
"Put_Call_OI_Ratio", |
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if interestedColumns: |
|
|
st.dataframe(filtered_df[interestedColumns].reset_index(drop=True)) |
|
|
|
|
|
|
|
|
csv = convert_df(filtered_df) |
|
|
st.download_button( |
|
|
label="Download Options Data as CSV", |
|
|
data=csv, |
|
|
file_name=f"options_data_{current_datetime}.csv", |
|
|
mime="text/csv", |
|
|
) |
|
|
|
|
|
csv = convert_df_watchlist(filtered_df) |
|
|
st.download_button( |
|
|
label="Download Stock WatchList for TradingView", |
|
|
data=csv, |
|
|
file_name=f"filtered_options_data_{current_datetime}.txt", |
|
|
mime="text/csv", |
|
|
) |
|
|
st.write(f"Unique Filtered Tickers: **{csv}** ") |
|
|
|
|
|
|
|
|
st.sidebar.markdown("---") |
|
|
st.sidebar.header("Ticker") |
|
|
|
|
|
selectedTicker = st.sidebar.selectbox( |
|
|
"Select Ticker", |
|
|
options=tickerlst, |
|
|
index=tickerlst.index("NVDA") if "NVDA" in tickerlst else 0, |
|
|
) |
|
|
|
|
|
if st.sidebar.button("Option Chain Visualization", use_container_width=True): |
|
|
st.header(f"Options Chain Visualization for Ticker {selectedTicker}") |
|
|
|
|
|
|
|
|
filtered_ticker_df = DF_options[DF_options["Ticker"] == selectedTicker] |
|
|
|
|
|
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
|
|
with col1: |
|
|
fig_3d = px.scatter_3d( |
|
|
filtered_ticker_df, |
|
|
x="volume", |
|
|
y="openInterest", |
|
|
z="impliedVolatility", |
|
|
color="Type", |
|
|
title=f"3D Scatter Plot for {selectedTicker}", |
|
|
hover_data=[ |
|
|
"strike", |
|
|
"lastPrice", |
|
|
"mark", |
|
|
"daysleft", |
|
|
"contractSymbol", |
|
|
"expirationDate", |
|
|
], |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_3d.update_layout( |
|
|
autosize=True, height=600, margin=dict(l=50, r=50, b=50, t=50) |
|
|
) |
|
|
st.plotly_chart(fig_3d, use_container_width=True) |
|
|
|
|
|
with col2: |
|
|
|
|
|
fig_surface = px.scatter_3d( |
|
|
filtered_ticker_df, |
|
|
x="strike", |
|
|
y="daysleft", |
|
|
z="impliedVolatility", |
|
|
color="Type", |
|
|
title=f"Implied Volatility Surface for {selectedTicker}", |
|
|
hover_data=[ |
|
|
"volume", |
|
|
"openInterest", |
|
|
"lastPrice", |
|
|
"mark", |
|
|
"contractSymbol", |
|
|
], |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_surface.update_traces(marker=dict(size=5)) |
|
|
fig_surface.update_layout( |
|
|
scene=dict( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Days to Expiration", |
|
|
zaxis_title="Implied Volatility", |
|
|
), |
|
|
autosize=True, |
|
|
height=600, |
|
|
margin=dict(l=50, r=50, b=50, t=50), |
|
|
) |
|
|
st.plotly_chart(fig_surface, use_container_width=True) |
|
|
|
|
|
with col3: |
|
|
|
|
|
fig_surface2 = px.scatter_3d( |
|
|
filtered_ticker_df, |
|
|
x="strike", |
|
|
y="daysleft", |
|
|
z="lastPrice", |
|
|
color="Type", |
|
|
title=f"Option Price Surface for {selectedTicker}", |
|
|
hover_data=[ |
|
|
"volume", |
|
|
"openInterest", |
|
|
"impliedVolatility", |
|
|
"mark", |
|
|
"contractSymbol", |
|
|
], |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_surface2.update_traces(marker=dict(size=5)) |
|
|
fig_surface2.update_layout( |
|
|
scene=dict( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Days to Expiration", |
|
|
zaxis_title="Option Price", |
|
|
), |
|
|
autosize=True, |
|
|
height=600, |
|
|
margin=dict(l=50, r=50, b=50, t=50), |
|
|
) |
|
|
st.plotly_chart(fig_surface2, use_container_width=True) |
|
|
|
|
|
|
|
|
st.dataframe( |
|
|
filtered_ticker_df.query("Ticker ==@selectedTicker")[ |
|
|
[ |
|
|
"contractSymbol", |
|
|
"daysleft", |
|
|
"Type", |
|
|
"strike", |
|
|
"lastPrice", |
|
|
"volume", |
|
|
"openInterest", |
|
|
"impliedVolatility", |
|
|
"inTheMoney", |
|
|
] |
|
|
].reset_index(drop=True), |
|
|
use_container_width=True, |
|
|
hide_index=True, |
|
|
height=600, |
|
|
) |
|
|
|
|
|
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
|
|
with col1: |
|
|
|
|
|
fig_bar = px.bar( |
|
|
filtered_ticker_df, |
|
|
x="strike", |
|
|
y="volume", |
|
|
color="Type", |
|
|
title=f"Volume by Strike Price for {selectedTicker}", |
|
|
barmode="group", |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_bar.update_layout( |
|
|
xaxis_title="Strike Price", yaxis_title="Volume", autosize=True, height=600 |
|
|
) |
|
|
st.plotly_chart(fig_bar, use_container_width=True) |
|
|
|
|
|
with col2: |
|
|
|
|
|
fig_bar2 = px.bar( |
|
|
filtered_ticker_df, |
|
|
x="expirationDate", |
|
|
y="openInterest", |
|
|
color="Type", |
|
|
title=f"Open Interest by Expiration Date for {selectedTicker}", |
|
|
barmode="group", |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_bar.update_layout( |
|
|
xaxis_title="Expiration Date", |
|
|
yaxis_title="Open Interest", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig_bar2, use_container_width=True) |
|
|
|
|
|
with col3: |
|
|
|
|
|
fig_bar3 = px.bar( |
|
|
filtered_ticker_df, |
|
|
x="strike", |
|
|
y="impliedVolatility", |
|
|
color="Type", |
|
|
title=f"Implied Volatility by Strike Price for {selectedTicker}", |
|
|
barmode="group", |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
st.plotly_chart(fig_bar3, use_container_width=True) |
|
|
|
|
|
st.write( |
|
|
"*Tips: in Open Interest by Strike Bar Chart, High call OI at a particular strike may indicate a resistance level, while high put OI may suggest support!*" |
|
|
) |
|
|
|
|
|
filtered_ticker_df_soon = filtered_ticker_df[filtered_ticker_df["daysleft"] <= 14] |
|
|
|
|
|
fig_bar4 = px.bar( |
|
|
filtered_ticker_df_soon, |
|
|
x="strike", |
|
|
y="openInterest", |
|
|
color="Type", |
|
|
title=f"Open Interest by Strike Price for {selectedTicker}", |
|
|
barmode="group", |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_bar4.update_layout( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Open Interest", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig_bar4, use_container_width=True) |
|
|
|
|
|
|
|
|
st.markdown("---") |
|
|
st.write( |
|
|
"*Tips: in Open Interest Heatmap visualizes where significant open interest concentrations exist across different strikes and expirations." |
|
|
) |
|
|
fig_bar5 = px.density_heatmap( |
|
|
filtered_ticker_df_soon, |
|
|
x="strike", |
|
|
y="expirationDate", |
|
|
z="openInterest", |
|
|
color_continuous_scale="Viridis", |
|
|
title=f"Open Interest Heatmap for {selectedTicker}", |
|
|
labels={"x": "Strike Price", "y": "Expiration Date", "z": "Open Interest"}, |
|
|
) |
|
|
fig_bar5.update_layout( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Expiration Date", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig_bar5, use_container_width=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.markdown("---") |
|
|
st.write( |
|
|
"*Tips: in Combined Open Interest and Volume Chart, High open interest with high volume may indicate strong interest in that strike price.*" |
|
|
) |
|
|
fig_bar6 = px.line( |
|
|
filtered_ticker_df_soon, |
|
|
x="strike", |
|
|
y=["openInterest", "volume"], |
|
|
title=f"Combined Open Interest and Volume for {selectedTicker}", |
|
|
labels={"value": "Value", "variable": "Metric"}, |
|
|
) |
|
|
fig_bar6.update_layout( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Value", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig_bar6, use_container_width=True) |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.write( |
|
|
"*Tips: in Price vs. Strike Scatter Plot with OI Sizing, Larger points indicate higher open interest, helping to identify popular strike prices.*" |
|
|
) |
|
|
fig_bar7 = px.scatter( |
|
|
filtered_ticker_df_soon, |
|
|
x="strike", |
|
|
y="lastPrice", |
|
|
size="openInterest", |
|
|
color="Type", |
|
|
title=f"Price vs. Strike Scatter Plot for {selectedTicker}", |
|
|
labels={"x": "Strike Price", "y": "Option Price"}, |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_bar7.update_layout( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Option Price", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig_bar7, use_container_width=True) |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.write( |
|
|
"*Tips: in Price vs. Strike Scatter Plot with Days Left Sizing, Larger points indicate higher open interest, helping to identify popular strike prices.*" |
|
|
) |
|
|
fig_bar7_2 = px.scatter( |
|
|
filtered_ticker_df, |
|
|
x="strike", |
|
|
y="lastPrice", |
|
|
size="daysleft", |
|
|
color="Type", |
|
|
title=f"Price vs. Strike Scatter Plot for {selectedTicker}", |
|
|
labels={"x": "Strike Price", "y": "Option Price"}, |
|
|
color_discrete_map={"CALL": "green", "PUT": "red"}, |
|
|
) |
|
|
fig_bar7_2.update_layout( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Option Price", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig_bar7_2, use_container_width=True) |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.write( |
|
|
"*Tips: in Support and Resistance Levels on Price Chart, High call OI at a particular strike may indicate a resistance level, while high put OI may suggest support!*" |
|
|
) |
|
|
fig_bar8 = px.line( |
|
|
filtered_ticker_df_soon, |
|
|
x="strike", |
|
|
y="lastPrice", |
|
|
title=f"Support and Resistance Levels for {selectedTicker}", |
|
|
labels={"x": "Strike Price", "y": "Option Price"}, |
|
|
) |
|
|
fig_bar8.update_layout( |
|
|
xaxis_title="Strike Price", |
|
|
yaxis_title="Option Price", |
|
|
autosize=True, |
|
|
height=600, |
|
|
) |
|
|
st.plotly_chart(fig_bar8, use_container_width=True) |
|
|
|
|
|
|
|
|
st.sidebar.markdown("---") |
|
|
st.sidebar.header("Advanced (Placeholder)") |
|
|
|
|
|
|
|
|
|
|
|
if st.sidebar.button("Daily Change in Open Interest ", use_container_width=True): |
|
|
st.write("Daily Change in Open Interest - Shows the change in open interest") |
|
|
st.info("Daily change in open interest analysis coming soon...") |
|
|
|
|
|
|
|
|
if st.sidebar.button("Gamma Squeeze", use_container_width=True): |
|
|
st.write( |
|
|
"Gamma Squeeze - Shows the potential for a rapid price movement in the underlying asset" |
|
|
) |
|
|
st.info("Gamma squeeze analysis coming soon...") |
|
|
|
|
|
|
|
|
if st.sidebar.button("Vanna Exposure Analysis", use_container_width=True): |
|
|
st.write( |
|
|
"Vanna Exposure Analysis - Shows sensitivity of delta to volatility changes" |
|
|
) |
|
|
|
|
|
|
|
|
st.info("Vanna exposure analysis coming soon...") |
|
|
|
|
|
if st.sidebar.button("Charm Analysis", use_container_width=True): |
|
|
st.write("Charm Analysis - Shows rate of change of delta with respect to time") |
|
|
|
|
|
|
|
|
st.info("Charm analysis coming soon...") |
|
|
|
|
|
if st.sidebar.button("Gamma Exposure Analysis", use_container_width=True): |
|
|
st.write( |
|
|
"Gamma Exposure Analysis - Shows how delta changes with underlying price movement" |
|
|
) |
|
|
|
|
|
filtered_gamma = DF_options[DF_options["Ticker"] == selectedTicker] |
|
|
st.info("Gamma exposure analysis coming soon...") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|