More Options Tradier Fixes (#2309)

* Added features

* Fixed tests

Co-authored-by: James Maslek <jmaslek11@gmail.com>
This commit is contained in:
Colin Delahunty
2022-08-16 10:30:39 -04:00
committed by GitHub
parent 71ba66fc5a
commit fc8dec2b7a
8 changed files with 148 additions and 60 deletions

View File

@@ -43,7 +43,10 @@ def get_option_history(ticker: str, date: str, call: bool, price: str) -> pd.Dat
data = requests.get(url, headers={"User-Agent": get_user_agent()}).content
soup = BeautifulSoup(data, "html.parser")
table = soup.find("div", attrs={"style": "display: table; font-size: 0.9em; "})
rows = table.find_all("div", attrs={"style": "display: table-row;"})
if table:
rows = table.find_all("div", attrs={"style": "display: table-row;"})
else:
return pd.DataFrame()
clean_rows = []
if rows:

View File

@@ -17,7 +17,7 @@ from openbb_terminal.helper_funcs import (
)
from openbb_terminal.stocks.options import chartexchange_model
from openbb_terminal.config_terminal import theme
from openbb_terminal.rich_config import console
from openbb_terminal.helper_funcs import (
plot_autoscale,
lambda_long_number_format_y_axis,
@@ -55,6 +55,9 @@ def display_raw(
"""
df = chartexchange_model.get_option_history(ticker, date, call, price)[::-1]
if df.empty:
console.print("[red]No data found[/red]\n")
return
df["Date"] = pd.to_datetime(df["Date"])
df = df.set_index("Date")

View File

@@ -545,9 +545,15 @@ class OptionsController(BaseController):
console.print("")
if self.ticker and self.selected_date:
self.chain = yfinance_model.get_option_chain(
self.ticker, self.selected_date
)
try:
self.chain = yfinance_model.get_option_chain(
self.ticker, self.selected_date
)
except ValueError:
console.print(
f"[red]{self.ticker} does not have expiration"
f" {self.selected_date}.[/red]"
)
@log_start_end(log=logger)
def call_exp(self, other_args: List[str]):
@@ -679,7 +685,10 @@ class OptionsController(BaseController):
)
else:
if TRADIER_TOKEN != "REPLACE_ME": # nosec
if (
TRADIER_TOKEN != "REPLACE_ME"
or self.source == "tradier"
): # nosec
tradier_view.display_historical(
ticker=self.ticker,
expiry=self.selected_date,
@@ -835,7 +844,7 @@ class OptionsController(BaseController):
if (
ns_parser.source == "tradier"
and TRADIER_TOKEN != "REPLACE_ME" # nosec
):
) or self.source == "tradier":
tradier_view.plot_vol(
ticker=self.ticker,
expiry=self.selected_date,
@@ -904,7 +913,7 @@ class OptionsController(BaseController):
if (
ns_parser.source == "tradier"
and TRADIER_TOKEN != "REPLACE_ME" # nosec
):
) or self.source == "tradier":
tradier_view.plot_volume_open_interest(
ticker=self.ticker,
expiry=self.selected_date,
@@ -934,7 +943,8 @@ class OptionsController(BaseController):
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="oi",
description="Plot open interest. Open interest represents the number of contracts that exist.",
description="""Plot open interest. Open interest represents the number of
contracts that exist.""",
)
parser.add_argument(
"-m",
@@ -979,7 +989,7 @@ class OptionsController(BaseController):
if (
ns_parser.source == "tradier"
and TRADIER_TOKEN != "REPLACE_ME" # nosec
):
) or self.source == "tradier":
tradier_view.plot_oi(
ticker=self.ticker,
expiry=self.selected_date,

View File

@@ -241,7 +241,10 @@ def last_price(ticker: str):
},
)
if r.status_code == 200:
return float(r.json()["quotes"]["quote"]["last"])
last = r.json()["quotes"]["quote"]["last"]
if last is None:
return 0
return float(last)
else:
console.print("Error getting last price")
return None

View File

@@ -1,11 +1,12 @@
"""Tradier options view"""
__docformat__ = "numpy"
import warnings
import argparse
import logging
import os
from bisect import bisect_left
from typing import List, Optional
from typing import List, Optional, Tuple
import matplotlib.pyplot as plt
import mplfinance as mpf
@@ -31,6 +32,28 @@ from openbb_terminal import rich_config
logger = logging.getLogger(__name__)
column_map = {"mid_iv": "iv", "open_interest": "oi", "volume": "vol"}
warnings.filterwarnings("ignore")
def get_strike_bounds(
options: pd.DataFrame, current_price: float, min_sp: float, max_sp: float
) -> Tuple[float, float]:
if min_sp == -1:
if current_price == 0:
min_strike = options["strike"].iat[0]
else:
min_strike = 0.75 * current_price
else:
min_strike = min_sp
if max_sp == -1:
if current_price == 0:
max_strike = options["strike"].iat[-1]
else:
max_strike = 1.25 * current_price
else:
max_strike = max_sp
return min_strike, max_strike
def lambda_red_highlight(val) -> str:
@@ -145,15 +168,7 @@ def display_chains(
columns = to_display + ["strike", "option_type"]
chains_df = chains_df[columns].rename(columns=column_map)
if min_sp == -1:
min_strike = np.percentile(chains_df["strike"], 25)
else:
min_strike = min_sp
if max_sp == -1:
max_strike = np.percentile(chains_df["strike"], 75)
else:
max_strike = max_sp
min_strike, max_strike = get_strike_bounds(chains_df, 0, min_sp, max_sp)
chains_df = chains_df[chains_df["strike"] >= min_strike]
chains_df = chains_df[chains_df["strike"] <= max_strike]
@@ -245,15 +260,11 @@ def plot_oi(
options = tradier_model.get_option_chains(ticker, expiry)
current_price = tradier_model.last_price(ticker)
if min_sp == -1:
min_strike = 0.75 * current_price
else:
min_strike = min_sp
min_strike, max_strike = get_strike_bounds(options, current_price, min_sp, max_sp)
if max_sp == -1:
max_strike = 1.25 * current_price
else:
max_strike = max_sp
if max_strike == min_strike:
console.print("[red]Not enough data for analysis[/red]\n")
return
if calls_only and puts_only:
console.print("Both flags selected, please select one", "\n")
@@ -340,15 +351,7 @@ def plot_vol(
options = tradier_model.get_option_chains(ticker, expiry)
current_price = tradier_model.last_price(ticker)
if min_sp == -1:
min_strike = 0.75 * current_price
else:
min_strike = min_sp
if max_sp == -1:
max_strike = 1.25 * current_price
else:
max_strike = max_sp
min_strike, max_strike = get_strike_bounds(options, current_price, min_sp, max_sp)
if calls_only and puts_only:
console.print("Both flags selected, please select one", "\n")

View File

@@ -1,23 +1,45 @@
vol_x strike vol_y
0 [green]0[/green] 148.0 [red]15[/red]
1 [green]0[/green] 149.0 [red]11[/red]
2 [green]144[/green] 150.0 [red]375[/red]
3 [green]1[/green] 152.5 [red]82[/red]
4 [green]3[/green] 155.0 [red]745[/red]
5 [green]1[/green] 157.5 [red]291[/red]
6 [green]158[/green] 160.0 [red]1204[/red]
7 [green]36[/green] 162.5 [red]747[/red]
8 [green]140[/green] 165.0 [red]1968[/red]
9 [green]82[/green] 167.5 [red]2392[/red]
10 [green]439[/green] 170.0 [red]2361[/red]
11 [green]1043[/green] 172.5 [red]1860[/red]
12 [green]4640[/green] 175.0 [red]1046[/red]
13 [green]1442[/green] 177.5 [red]80[/red]
14 [green]5482[/green] 180.0 [red]158[/red]
15 [green]1218[/green] 182.5 [red]25[/red]
16 [green]2680[/green] 185.0 [red]20[/red]
17 [green]385[/green] 187.5 [red]1[/red]
18 [green]519[/green] 190.0 [red]1[/red]
19 [green]875[/green] 192.5 [red]0[/red]
20 [green]394[/green] 195.0 [red]1[/red]
21 [green]19[/green] 197.5 [red]0[/red]
0 [green]0[/green] 105.0 [red]370[/red]
1 [green]0[/green] 110.0 [red]0[/red]
2 [green]0[/green] 115.0 [red]9[/red]
3 [green]0[/green] 120.0 [red]921[/red]
4 [green]0[/green] 125.0 [red]28[/red]
5 [green]0[/green] 130.0 [red]146[/red]
6 [green]0[/green] 135.0 [red]33[/red]
7 [green]4[/green] 140.0 [red]125[/red]
8 [green]2[/green] 145.0 [red]203[/red]
9 [green]20[/green] 146.0 [red]21[/red]
10 [green]0[/green] 147.0 [red]5[/red]
11 [green]0[/green] 148.0 [red]15[/red]
12 [green]0[/green] 149.0 [red]11[/red]
13 [green]144[/green] 150.0 [red]375[/red]
14 [green]1[/green] 152.5 [red]82[/red]
15 [green]3[/green] 155.0 [red]745[/red]
16 [green]1[/green] 157.5 [red]291[/red]
17 [green]158[/green] 160.0 [red]1204[/red]
18 [green]36[/green] 162.5 [red]747[/red]
19 [green]140[/green] 165.0 [red]1968[/red]
20 [green]82[/green] 167.5 [red]2392[/red]
21 [green]439[/green] 170.0 [red]2361[/red]
22 [green]1043[/green] 172.5 [red]1860[/red]
23 [green]4640[/green] 175.0 [red]1046[/red]
24 [green]1442[/green] 177.5 [red]80[/red]
25 [green]5482[/green] 180.0 [red]158[/red]
26 [green]1218[/green] 182.5 [red]25[/red]
27 [green]2680[/green] 185.0 [red]20[/red]
28 [green]385[/green] 187.5 [red]1[/red]
29 [green]519[/green] 190.0 [red]1[/red]
30 [green]875[/green] 192.5 [red]0[/red]
31 [green]394[/green] 195.0 [red]1[/red]
32 [green]19[/green] 197.5 [red]0[/red]
33 [green]202[/green] 200.0 [red]0[/red]
34 [green]46[/green] 205.0 [red]0[/red]
35 [green]315[/green] 210.0 [red]0[/red]
36 [green]0[/green] 215.0 [red]0[/red]
37 [green]7[/green] 220.0 [red]0[/red]
38 [green]1[/green] 225.0 [red]0[/red]
39 [green]0[/green] 230.0 [red]0[/red]
40 [green]0[/green] 235.0 [red]0[/red]
41 [green]164[/green] 240.0 [red]0[/red]
42 [green]21[/green] 245.0 [red]0[/red]
43 [green]1[/green] 250.0 [red]0[/red]

View File

@@ -1,4 +1,15 @@
vol strike
0 370 105.0
2 0 110.0
4 9 115.0
6 921 120.0
8 28 125.0
10 146 130.0
12 33 135.0
14 125 140.0
16 203 145.0
19 21 146.0
20 5 147.0
22 15 148.0
24 11 149.0
26 375 150.0
@@ -21,3 +32,14 @@
61 0 192.5
62 1 195.0
65 0 197.5
66 0 200.0
68 0 205.0
70 0 210.0
72 0 215.0
74 0 220.0
77 0 225.0
78 0 230.0
80 0 235.0
82 0 240.0
84 0 245.0
86 0 250.0

View File

@@ -1,4 +1,15 @@
vol strike
1 0 105.0
3 0 110.0
5 0 115.0
7 0 120.0
9 0 125.0
11 0 130.0
13 0 135.0
15 4 140.0
17 2 145.0
18 20 146.0
21 0 147.0
23 0 148.0
25 0 149.0
27 144 150.0
@@ -21,3 +32,14 @@
60 875 192.5
63 394 195.0
64 19 197.5
67 202 200.0
69 46 205.0
71 315 210.0
73 0 215.0
75 7 220.0
76 1 225.0
79 0 230.0
81 0 235.0
83 164 240.0
85 21 245.0
87 1 250.0