Skip to content

Instantly share code, notes, and snippets.

@huoding
Last active April 1, 2024 10:47
Show Gist options
  • Save huoding/a60fa2fdf3af7c0e9acb011bf06a8573 to your computer and use it in GitHub Desktop.
Save huoding/a60fa2fdf3af7c0e9acb011bf06a8573 to your computer and use it in GitHub Desktop.
import math
import click
import pandas
import pendulum
import yfinance
from rich.console import Console
from rich.table import Table
SPX = "^SPX"
VIX = "^VIX"
VIX1D = "^VIX1D"
def expected_move(s, iv, dte=1):
return s * (iv/100) * math.sqrt(dte/365)
def all(data: pandas.DataFrame):
table = Table(show_footer=True)
columns = [
{"name":"DATE", "style":"cyan"},
{"name":"PRICE"},
{"name":"CHANGE"},
{"name":"VIX", "style":"magenta"},
{"name":"EM AT OPEN"},
{"name":"EM AT CLOSE"},
{"name":"1.0X EM LOW", "style":"green"},
{"name":"1.0X EM HIGH", "style":"green"},
{"name":"1.5X EM LOW", "style":"yellow"},
{"name":"1.5X EM HIGH", "style":"yellow"},
{"name":"2.0X EM LOW", "style":"red"},
{"name":"2.0X EM HIGH", "style":"red"},
]
for column in columns:
table.add_column(column.get("name"), column.get("name"), style=column.get("style"), justify="right")
for _, row in data.iterrows():
x = 0
em_at_open = expected_move(row["Open"][SPX], row["Open"][VIX1D])
em_at_close = expected_move(row["Close"][SPX], row["Close"][VIX1D])
for i in range(0, 100):
x = i / 10
high = row["Open"][SPX] + x * em_at_open
low = row["Open"][SPX] - x * em_at_open
if high > row["High"][SPX] and row["Low"][SPX] > low:
break
price_style = "green"
if row["Change"].item() < 0:
price_style = "red"
em_style = "yellow"
if x <= 1.0:
em_style = "green"
elif x >= 2.0:
em_style = "red"
table.add_row(
row.name.strftime("%Y-%m-%d"),
"[%s]%.2f[/%s]" % (price_style, row["Close"][SPX], price_style),
"[%s]%.2f%%[/%s]" % (price_style, row["Change"].item(), price_style),
"%.2f" % row["Close"][VIX],
"[%s]%.2f[/%s]" % (em_style, em_at_open, em_style),
"[%s]%.2f[/%s]" % (em_style, em_at_close, em_style),
"%.2f" % (row["Close"][SPX] - 1.0 * em_at_close),
"%.2f" % (row["Close"][SPX] + 1.0 * em_at_close),
"%.2f" % (row["Close"][SPX] - 1.5 * em_at_close),
"%.2f" % (row["Close"][SPX] + 1.5 * em_at_close),
"%.2f" % (row["Close"][SPX] - 2.0 * em_at_close),
"%.2f" % (row["Close"][SPX] + 2.0 * em_at_close),
)
console = Console()
console.print(table)
@click.command()
@click.option("--start", default=pendulum.now().subtract(months=1).to_date_string(), show_default=True)
@click.option("--end", default=pendulum.now().to_date_string(), show_default=True)
def main(start, end):
s = pendulum.parse(start).subtract(months=1).to_date_string()
data = yfinance.download([SPX, VIX, VIX1D], start=s, end=end, progress=False)
data["Change"] = (data["Close"][SPX] - data["Close"][SPX].shift()) / data["Close"][SPX].shift() * 100
data.drop(data[pandas.to_datetime(data.index) < pandas.to_datetime(start)].index, inplace=True)
all(data)
if __name__ == "__main__":
# pandas.set_option('display.max_columns', None)
# pandas.set_option('display.max_rows', None)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment