diff --git a/gamestonk_terminal/options/chartexchange_model.py b/gamestonk_terminal/options/chartexchange_model.py new file mode 100644 index 00000000000..53bdb4c3e23 --- /dev/null +++ b/gamestonk_terminal/options/chartexchange_model.py @@ -0,0 +1,60 @@ +"""Chartexchange model""" +__docformat__ = "numpy" + +import requests +import pandas as pd +from bs4 import BeautifulSoup + +from gamestonk_terminal.options.op_helpers import convert + + +def get_option_history(ticker: str, date: str, call: bool, price: str) -> pd.DataFrame: + """Historic prices for a specific option [chartexchange] + + Parameters + ---------- + ticker : str + Ticker to get historical data from + date : str + Date as a string YYYYMMDD + call : bool + Whether to show a call or a put + price : str + Strike price for a specific option + + Returns + ------- + historical : pd.Dataframe + Historic information for an option + """ + url = ( + f"https://chartexchange.com/symbol/opra-{ticker.lower()}{date.replace('-', '')}" + ) + url += f"{'c' if call else 'p'}{float(price):g}/historical/" + + data = requests.get(url, headers={"User-Agent": "test"}).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;"}) + clean_rows = [] + + if rows: + for row in rows[1:]: + item = row.find_all("div") + clean_rows.append([x.text for x in item]) + else: + print("No data for this option\n") + return pd.DataFrame() + + df = pd.DataFrame() + df["Date"] = [x[0] for x in clean_rows] + df["Open"] = [convert(x[1], ",") for x in clean_rows] + df["High"] = [convert(x[2], ",") for x in clean_rows] + df["Low"] = [convert(x[3], ",") for x in clean_rows] + df["Close"] = [convert(x[4], ",") for x in clean_rows] + df["Change"] = [convert(x[5], "%") for x in clean_rows] + df["Volume"] = [convert(x[6], ",") for x in clean_rows] + df["Open Interest"] = [convert(x[7], ",") for x in clean_rows] + df["Change Since"] = [convert(x[8], "%") for x in clean_rows] + + return df diff --git a/gamestonk_terminal/options/chartexchange_view.py b/gamestonk_terminal/options/chartexchange_view.py new file mode 100644 index 00000000000..f70e37545e3 --- /dev/null +++ b/gamestonk_terminal/options/chartexchange_view.py @@ -0,0 +1,56 @@ +"""Chartexchange view""" +__docformat__ = "numpy" + +import os + +from tabulate import tabulate + +from gamestonk_terminal.helper_funcs import export_data +from gamestonk_terminal import feature_flags as gtff +from gamestonk_terminal.options import chartexchange_model + + +def display_raw( + export: str, ticker: str, date: str, call: bool, price: str, num: int = 20 +) -> None: + """Return raw stock data[chartexchange] + + Parameters + ---------- + export : str + Export data as CSV, JSON, XLSX + ticker : str + Ticker for the given option + date : str + Date of expiration for the option + call : bool + Whether the underlying asset should be a call or a put + price : float + The stike of the expiration + num : int + Number of rows to show + """ + + df = chartexchange_model.get_option_history(ticker, date, call, price) + + export_data( + export, + os.path.dirname(os.path.abspath(__file__)), + "hist", + df, + ) + + if gtff.USE_TABULATE_DF: + print( + tabulate( + df.head(num), + headers=df.columns, + tablefmt="fancy_grid", + showindex=True, + floatfmt=".2f", + ) + ) + else: + print(df.to_string(index=False)) + + print("") diff --git a/gamestonk_terminal/options/op_helpers.py b/gamestonk_terminal/options/op_helpers.py index 0162704da87..f08380f5d64 100644 --- a/gamestonk_terminal/options/op_helpers.py +++ b/gamestonk_terminal/options/op_helpers.py @@ -62,6 +62,26 @@ def calculate_max_pain(chain: pd.DataFrame) -> int: 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 + """ + if to == "%": + clean = orig.replace("%", "").replace("+", "") + return float(clean) / 100 + if to == ",": + clean = orig.replace(",", "") + return float(clean) + raise ValueError("Invalid to format, please use '%' or ','.") + + opt_chain_cols = { "lastTradeDate": {"format": "date", "label": "Last Trade Date"}, "strike": {"format": "${x:.2f}", "label": "Strike"}, diff --git a/gamestonk_terminal/options/options_controller.py b/gamestonk_terminal/options/options_controller.py index a2149612094..ae7c74ad470 100644 --- a/gamestonk_terminal/options/options_controller.py +++ b/gamestonk_terminal/options/options_controller.py @@ -30,7 +30,7 @@ from gamestonk_terminal.options import ( yfinance_view, ) from gamestonk_terminal.stocks import stocks_controller -from gamestonk_terminal.options import payoff_controller +from gamestonk_terminal.options import payoff_controller, chartexchange_view class OptionsController: @@ -631,7 +631,7 @@ Current Expiry: {self.selected_date or None} "--strike", dest="strike", type=float, - required="--chain" not in other_args or "-h" not in other_args, + required="--chain" not in other_args and "-h" not in other_args, help="Strike price to look at", ) parser.add_argument( @@ -660,6 +660,21 @@ Current Expiry: {self.selected_date or None} dest="export", help="Export dataframe data to csv,json,xlsx file", ) + parser.add_argument( + "--source", + dest="source", + type=str, + choices=["td", "ce"], + default="ce" if TRADIER_TOKEN == "REPLACE_ME" else "td", + help="Choose Tradier(TD) or ChartExchange (CE), only affects raw data", + ) + parser.add_argument( + "-n", + "--num", + dest="num", + type=int, + help="Number of data rows to show", + ) try: if ( @@ -678,9 +693,21 @@ Current Expiry: {self.selected_date or None} if not self.selected_date: print("No expiry loaded. First use `exp ` \n") return + if ns_parser.source.lower() == "ce": + chartexchange_view.display_raw( + ns_parser.export, + self.ticker, + self.selected_date, + not ns_parser.put, + ns_parser.strike, + ns_parser.num, + ) + return + if TRADIER_TOKEN == "REPLACE_ME": print("TRADIER TOKEN not supplied. \n") return + tradier_view.display_historical( ticker=self.ticker, expiry=self.selected_date, diff --git a/website/content/options/hist/_index.md b/website/content/options/hist/_index.md index 0fd0e4b35d6..b1b80d409c6 100644 --- a/website/content/options/hist/_index.md +++ b/website/content/options/hist/_index.md @@ -1,5 +1,5 @@ ``` -usage: hist [-s STRIKE] [-p] [--chain CHAIN_ID] [-r,--raw] [--export {csv,json,xlsx}] [-h] +usage: hist [-s STRIKE] [-p] [--chain CHAIN_ID] [-r,--raw] [--export {csv,json,xlsx}] [--source SOURCE] [-h] ``` Gets historical quotes for given option chain @@ -10,6 +10,7 @@ optional arguments: Strike price to look at (default: None) -p, --put Flag for showing put option (default: False) --chain CHAIN_ID OCC option symbol (default: None) + --source SOURCE Source of data (default: TradierView) -r,--raw Display raw data (default: False) --export {csv,json,xlsx} Export dataframe data to csv,json,xlsx file (default: )