def metals_command(): """Displays metals futures data [Finviz]""" # Debug user input if cfg.DEBUG: logger.debug("econ-metals") # Retrieve data d_futures = finviz_model.get_futures() df = pd.DataFrame(d_futures["Metals"]) # Check for argument if df.empty: raise Exception("No available data found") formats = {"last": "${:.2f}", "prevClose": "${:.2f}"} for col, value in formats.items(): df[col] = df[col].map(lambda x: value.format(x)) # pylint: disable=W0640 # Debug user output if cfg.DEBUG: logger.debug(df) df = df.sort_values(by="ticker", ascending=False) df = df.fillna("") df.set_index("label", inplace=True) df = df[[ "prevClose", "last", "change", ]] df.index.names = [""] df = df.rename(columns={ "prevClose": "PrevClose", "last": "Last", "change": "Change" }) dindex = len(df.index) fig = df2img.plot_dataframe( df, fig_size=(800, (40 + (40 * dindex))), col_width=[6, 3, 3], tbl_cells=dict( align="left", height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("econ-metals.png", fig) return { "title": "Economy: [WSJ] Metals Futures", "imagefile": imagefile, }
def usbonds_command(): """US bonds overview [Wall St. Journal]""" # Debug user input if cfg.DEBUG: logger.debug("econ-usbonds") # Retrieve data df = wsj_model.us_bonds() # Check for argument if df.empty: raise Exception("No available data found") df["Rate (%)"] = pd.to_numeric(df["Rate (%)"].astype(float)) df["Yld (%)"] = pd.to_numeric(df["Yld (%)"].astype(float)) df["Yld Chg (%)"] = pd.to_numeric(df["Yld Chg (%)"].astype(float)) formats = { "Rate (%)": "{:.2f}%", "Yld (%)": "{:.2f}%", "Yld Chg (%)": "{:.2f}%", } for col, value in formats.items(): df[col] = df[col].map(lambda x: value.format(x)) # pylint: disable=W0640 df = df.fillna("") df.set_index(" ", inplace=True) df = df.set_axis( [ "Rate", "Yld", "Yld Chg", ], axis="columns", ) dindex = len(df.index) fig = df2img.plot_dataframe( df, fig_size=(800, (40 + (40 * dindex))), col_width=[8, 3, 3], tbl_cells=dict( align="left", height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("econ-usbonds.png", fig) return { "title": "Economy: [WSJ] US Bonds", "imagefile": imagefile, }
def quote_command(ticker: str = None): """Ticker Quote""" # Debug if cfg.DEBUG: logger.debug("quote %s", ticker) # Check for argument if ticker is None: raise Exception("Stock ticker is required") df = quote(ticker) fig = df2img.plot_dataframe( df, fig_size=(600, 1500), col_width=[2, 3], tbl_cells=dict( align="left", height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("quote.png", fig) return { "title": f"{ticker.upper()} Quote", "imagefile": imagefile, }
def currencies_command(): """Currencies overview [Wall St. Journal]""" # Debug user input if cfg.DEBUG: logger.debug("econ-currencies") # Retrieve data df = wsj_model.global_currencies() df = pd.DataFrame.from_dict(df) # Check for argument if df.empty: raise Exception("No available data found") df["Last"] = pd.to_numeric(df["Last"].astype(float)) df["Chng"] = pd.to_numeric(df["Chng"].astype(float)) df["%Chng"] = pd.to_numeric(df["%Chng"].astype(float)) formats = {"Last": "{:.2f}", "Chng": "{:.2f}", "%Chng": "{:.2f}%"} for col, value in formats.items(): df[col] = df[col].map(lambda x: value.format(x)) # pylint: disable=W0640 df = df.fillna("") df.set_index(" ", inplace=True) # Debug user output if cfg.DEBUG: logger.debug(df.to_string()) df = df[[ "Last", "Chng", "%Chng", ]] dindex = len(df.index) fig = df2img.plot_dataframe( df, fig_size=(800, (40 + (40 * dindex))), col_width=[8, 3, 3], tbl_cells=dict( align="left", height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("econ-currencies.png", fig) return { "title": "Economy: [WSJ] Currencies", "imagefile": imagefile, }
def analyst_command(ticker=""): """Displays analyst recommendations [Finviz]""" # Debug if cfg.DEBUG: logger.debug("dd-analyst %s", ticker) # Check for argument if not ticker: raise Exception("Stock ticker is required") df = finviz_model.get_analyst_data(ticker) df = df.replace(np.nan, 0) df.index.names = ["Date"] df = df.rename( columns={ "category": "Category", "analyst": "Analyst", "rating": "Rating", "target": "Target", "target_from": "Target From", "target_to": "Target To", }) dindex = len(df.index) fig = df2img.plot_dataframe( df, fig_size=(1500, (40 + (40 * dindex))), col_width=[5, 5, 8, 14, 5, 5, 5], tbl_cells=dict(height=35, ), font=dict( family="Consolas", size=20, ), template="plotly_dark", paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("dd-analyst.png", fig) return { "title": f"Stocks: [Finviz] Analyst Recommendations {ticker.upper()}", "imagefile": imagefile, }
def ford_command(): """Display Orders by Fidelity Customers. [Source: Fidelity]""" # Debug if cfg.DEBUG: logger.debug("disc-ford") order_header, df_orders = fidelity_model.get_orders() df_orders = df_orders.head(n=30).iloc[:, :-1] df_orders = df_orders.applymap(str) font_color = (["white"] * 2 + [[ "#ad0000" if boolv else "#0d5700" for boolv in df_orders["Price Change"].str.contains("-") ]] + [["white"] * 3]) df_orders.set_index("Symbol", inplace=True) df_orders = df_orders.apply(lambda x: x.str.slice(0, 20)) dindex = len(df_orders.index) fig = df2img.plot_dataframe( df_orders, fig_size=(1500, (40 + (40 * dindex))), col_width=[1, 3, 2.2, 3, 2, 2], tbl_cells=dict( align=["left", "center", "left", "left", "center"], font=dict(color=font_color), height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("disc-ford.png", fig) return { "title": "Fidelity Customer Orders", "imagefile": imagefile, }
def iv_command(ticker: str = None): """Options IV""" # Debug if cfg.DEBUG: logger.debug("opt-iv %s", ticker) # Check for argument if ticker is None: raise Exception("Stock ticker is required") df = barchart_model.get_options_info(ticker) df = df.fillna("") df = df.set_axis( [ " ", "", ], axis="columns", ) df.set_index(" ", inplace=True) fig = df2img.plot_dataframe( df, fig_size=(600, 1500), col_width=[3, 3], tbl_cells=dict( align="left", height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("opt-iv.png", fig) return { "title": f"{ticker.upper()} Options: IV", "imagefile": imagefile, }
def chain_command( ticker: str = None, expiry: str = None, opt_type: str = None, min_sp: float = None, max_sp: float = None, ): """Show calls/puts for given ticker and expiration""" # Debug if cfg.DEBUG: logger.debug("opt-chain %s %s %s %s %s", ticker, expiry, opt_type, min_sp, max_sp) # Check for argument if not ticker: raise Exception("Stock ticker is required") dates = yfinance_model.option_expirations(ticker) if not dates: raise Exception("Stock ticker is invalid") options = yfinance_model.get_option_chain(ticker, str(expiry)) calls_df = options.calls.fillna(0) puts_df = options.puts.fillna(0) column_map = { "openInterest": "oi", "volume": "vol", "impliedVolatility": "iv" } columns = [ "strike", "bid", "ask", "volume", "openInterest", "impliedVolatility", ] if opt_type == "Calls": df = calls_df[columns].rename(columns=column_map) if opt_type == "Puts": df = puts_df[columns].rename(columns=column_map) min_strike = np.percentile(df["strike"], 1) max_strike = np.percentile(df["strike"], 100) if min_sp: min_strike = min_sp if max_sp: max_strike = max_sp if min_sp > max_sp: # type: ignore min_sp, max_sp = max_strike, min_strike df = df[df["strike"] >= min_strike] df = df[df["strike"] <= max_strike] df["iv"] = pd.to_numeric(df["iv"].astype(float)) formats = {"iv": "{:.2f}"} for col, f in formats.items(): df[col] = df[col].map(lambda x: f.format(x)) # pylint: disable=W0640 df.set_index("strike", inplace=True) title = ( f"Stocks: {opt_type} Option Chain for {ticker.upper()} on {expiry} [yfinance]" ) embeds: list = [] # Output i, i2, end = 0, 0, 20 df_pg = [] embeds_img = [] dindex = len(df.index) while i < dindex: df_pg = df.iloc[i:end] df_pg.append(df_pg) fig = df2img.plot_dataframe( df_pg, fig_size=(1000, (40 + (40 * 20))), col_width=[3, 3, 3, 3], tbl_cells=dict(height=35, ), font=dict( family="Consolas", size=20, ), template="plotly_dark", paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image(f"opt-chain{i}.png", fig) uploaded_image = gst_imgur.upload_image(imagefile, title="something") image_link = uploaded_image.link embeds_img.append(f"{image_link}", ) embeds.append(disnake.Embed( title=title, colour=cfg.COLOR, ), ) i2 += 1 i += 20 end += 20 os.remove(imagefile) # Author/Footer for i in range(0, i2): embeds[i].set_author( name=cfg.AUTHOR_NAME, url=cfg.AUTHOR_URL, icon_url=cfg.AUTHOR_ICON_URL, ) embeds[i].set_footer( text=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) i = 0 for i in range(0, i2): embeds[i].set_image(url=embeds_img[i]) i += 1 embeds[0].set_footer(text=f"Page 1 of {len(embeds)}") choices = [ disnake.SelectOption(label="Home", value="0", emoji="🟢"), ] return { "view": Menu, "title": title, "embed": embeds, "choices": choices, "embeds_img": embeds_img, }
def est_command(ticker: str = ""): """Displays earning estimates [Business Insider]""" # Debug if cfg.DEBUG: logger.debug("dd-est %s", ticker) # Check for argument if ticker == "": raise Exception("Stock ticker is required") ( df_year_estimates, df_quarter_earnings, df_quarter_revenues, ) = business_insider_model.get_estimates(ticker) if (df_quarter_revenues.empty and df_year_estimates.empty and df_quarter_earnings.empty): raise Exception("Enter a valid ticker") # Debug user output if cfg.DEBUG: logger.debug(df_year_estimates.to_string()) logger.debug(df_quarter_earnings.to_string()) logger.debug(df_quarter_revenues.to_string()) dindex = len(df_year_estimates.index) fig = df2img.plot_dataframe( df_year_estimates, fig_size=(1200, (40 + (60 * dindex))), col_width=[12, 4, 4, 4, 4], tbl_cells=dict(height=35, ), font=dict( family="Consolas", size=20, ), template="plotly_dark", paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("estimates.png", fig) uploaded_image = gst_imgur.upload_image(imagefile, title="something") link_estimates = uploaded_image.link os.remove(imagefile) fig = df2img.plot_dataframe( df_quarter_earnings, fig_size=(1200, (40 + (40 * 20))), col_width=[5, 5, 4, 4, 5, 4], tbl_cells=dict(height=35, ), font=dict( family="Consolas", size=20, ), template="plotly_dark", paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("earnings.png", fig) uploaded_image = gst_imgur.upload_image(imagefile, title="something") link_earnings = uploaded_image.link os.remove(imagefile) fig = df2img.plot_dataframe( df_quarter_revenues, fig_size=(1200, (40 + (40 * 20))), col_width=[5, 5, 4, 4, 5, 4], tbl_cells=dict(height=35, ), font=dict( family="Consolas", size=20, ), template="plotly_dark", paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("revenues.png", fig) uploaded_image = gst_imgur.upload_image(imagefile, title="something") link_revenues = uploaded_image.link os.remove(imagefile) embeds = [ disnake.Embed( title=f"**{ticker.upper()} Year Estimates**", color=cfg.COLOR, ), disnake.Embed( title=f"**{ticker.upper()} Quarter Earnings**", colour=cfg.COLOR, ), disnake.Embed( title=f"**{ticker.upper()} Quarter Revenues**", colour=cfg.COLOR, ), ] embeds[0].set_image(url=link_estimates) embeds[1].set_image(url=link_earnings) embeds[2].set_image(url=link_revenues) titles = [ f"**{ticker.upper()} Year Estimates**", f"**{ticker.upper()} Quarter Earnings**", f"**{ticker.upper()} Quarter Revenues**", ] embeds_img = [ f"{link_estimates}", f"{link_earnings}", f"{link_revenues}", ] # Output data choices = [ disnake.SelectOption(label=f"{ticker.upper()} Year Estimates", value="0", emoji="🟢"), disnake.SelectOption(label=f"{ticker.upper()} Quarter Earnings", value="1", emoji="🟢"), disnake.SelectOption(label=f"{ticker.upper()} Quarter Revenues", value="2", emoji="🟢"), ] return { "view": Menu, "titles": titles, "embed": embeds, "choices": choices, "embeds_img": embeds_img, }
def unu_command(num: int = None): """Unusual Options""" # Debug if cfg.DEBUG: logger.debug("opt-unu %s", num) # Check for argument if num is None: num = 10 pages = np.arange(0, num // 20 + 1) data_list = [] for page_num in pages: r = requests.get( f"https://app.fdscanner.com/api2/unusualvolume?p=0&page_size=20&page={int(page_num)}", headers={"User-Agent": get_user_agent()}, ) if r.status_code != 200: logger.debug("Error in fdscanner request") return pd.DataFrame(), "request error" data_list.append(r.json()) ticker, expiry, option_strike, option_type, ask, bid, oi, vol, voi = ( [], [], [], [], [], [], [], [], [], ) for data in data_list: for entry in data["data"]: ticker.append(entry["tk"]) expiry.append(entry["expiry"]) option_strike.append(float(entry["s"])) option_type.append("Put" if entry["t"] == "P" else "Call") ask.append(entry["a"]) bid.append(entry["b"]) oi.append(entry["oi"]) vol.append(entry["v"]) voi.append(entry["vol/oi"]) df = pd.DataFrame({ "Ticker": ticker, "Exp": expiry, "Strike": option_strike, "Type": option_type, "Vol/OI": voi, "Vol": vol, "OI": oi, }) df = df.replace({"2021-", "2022-"}, "", regex=True) df.set_index("Ticker", inplace=True) dindex = len(df.index) fig = df2img.plot_dataframe( df, fig_size=(800, (40 + (40 * dindex))), col_width=[3, 3, 3, 3, 3, 3, 3], tbl_cells=dict( align="left", height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("opt-unu.png", fig) return { "title": "Unusual Options", "imagefile": imagefile, }
def valuation_command(economy_group="sector"): """Valuation of sectors, industry, country [Finviz]""" d_economy_group = { "sector": "Sector", "industry": "Industry", "basic_materials": "Industry (Basic Materials)", "communication_services": "Industry (Communication Services)", "consumer_cyclical": "Industry (Consumer Cyclical)", "consumer_defensive": "Industry (Consumer Defensive)", "energy": "Industry (Energy)", "financial": "Industry (Financial)", "healthcare": "Industry (Healthcare)", "industrials": "Industry (Industrials)", "real_estate": "Industry (Real Estate)", "technology": "Industry (Technology)", "utilities": "Industry (Utilities)", "country": "Country (U.S. listed stocks only)", "capitalization": "Capitalization", } # Debug user input if cfg.DEBUG: logger.debug("econ-valuation %s", economy_group) # Select default group if economy_group == "": if cfg.DEBUG: logger.debug("Use default economy_group: 'sector'") economy_group = "sector" # Check for argument possible_groups = list(d_economy_group.keys()) if economy_group not in possible_groups: raise Exception( f"Select a valid group from {', '.join(possible_groups)}" # nosec ) group = d_economy_group[economy_group] # Retrieve data df_group = finviz_model.get_valuation_performance_data(group, "valuation") # Check for argument if df_group.empty: raise Exception("No available data found") # Output data df = pd.DataFrame(df_group) df = df.replace(np.nan, 0) df = df.set_axis( [ "Name", "MarketCap", "P/E", "FwdP/E", "PEG", "P/S", "P/B", "P/C", "P/FCF", "EPSpast5Y", "EPSnext5Y", "Salespast5Y", "Change", "Volume", ], axis="columns", ) df["P/E"] = pd.to_numeric(df["P/E"].astype(float)) df["FwdP/E"] = pd.to_numeric(df["FwdP/E"].astype(float)) df["EPSpast5Y"] = pd.to_numeric(df["EPSpast5Y"].astype(float)) df["EPSnext5Y"] = pd.to_numeric(df["EPSnext5Y"].astype(float)) df["Salespast5Y"] = pd.to_numeric(df["Salespast5Y"].astype(float)) df["Volume"] = pd.to_numeric(df["Volume"].astype(float)) df["Volume"] = df["Volume"] / 1_000_000 formats = { "P/E": "{:.2f}", "FwdP/E": "{:.2f}", "EPSpast5Y": "{:.2f}", "EPSnext5Y": "{:.2f}", "Salespast5Y": "{:.2f}", "Change": "{:.2f}", "Volume": "{:.0f}M", } for col, value in formats.items(): df[col] = df[col].map(lambda x: value.format(x)) # pylint: disable=W0640 df = df.fillna("") df.set_index("Name", inplace=True) dindex = len(df.index) fig = df2img.plot_dataframe( df, fig_size=(1600, (40 + (50 * dindex))), col_width=[12, 5, 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 4, 4], tbl_cells=dict( align=["left", "center"], height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("econ-valuation.png", fig) return { "title": "Economy: [Finviz] Valuation", "imagefile": imagefile, }
def lins_command(ticker: str = "", num: int = 10): """Display insider activity for a given stock ticker. [Source: Finviz] Parameters ---------- ticker : Stock Ticker num : Number of latest insider activity to display """ # Debug if cfg.DEBUG: logger.debug("disc-lins %s", num) d_finviz_insider = finviz_model.get_last_insider_activity(ticker) df = pd.DataFrame.from_dict(d_finviz_insider) df.set_index("Date", inplace=True) df = df[[ "Relationship", "Transaction", "#Shares", "Cost", "Value ($)", "#Shares Total", "Insider Trading", "SEC Form 4", ]] df = df.head(num) df = df.replace(to_replace="Option Exercise", value="Opt Ex.", regex=True) title = f"Insider Trading for {ticker.upper()}" embeds: list = [] i, i2, end = 0, 0, 20 df_pg = [] embeds_img = [] dindex = len(df.index) while i < dindex: df_pg = df.iloc[i:end] df_pg.append(df_pg) fig = df2img.plot_dataframe( df_pg, fig_size=(1600, (40 + (40 * 20))), col_width=[5, 14, 4, 4, 3, 4, 5, 8, 7], tbl_cells=dict(height=35, ), font=dict( family="Consolas", size=20, ), template="plotly_dark", paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image(f"disc-insider{i}.png", fig) uploaded_image = gst_imgur.upload_image(imagefile, title="something") image_link = uploaded_image.link embeds_img.append(f"{image_link}", ) embeds.append(disnake.Embed( title=title, colour=cfg.COLOR, ), ) i2 += 1 i += 20 end += 20 os.remove(imagefile) # Author/Footer for i in range(0, i2): embeds[i].set_author( name=cfg.AUTHOR_NAME, url=cfg.AUTHOR_URL, icon_url=cfg.AUTHOR_ICON_URL, ) embeds[i].set_footer( text=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) i = 0 for i in range(0, i2): embeds[i].set_image(url=embeds_img[i]) i += 1 embeds[0].set_footer(text=f"Page 1 of {len(embeds)}") choices = [ disnake.SelectOption(label="Home", value="0", emoji="🟢"), ] return { "view": Menu, "title": title, "embed": embeds, "choices": choices, "embeds_img": embeds_img, }
def performance_command(economy_group="sector"): """Performance of sectors, industry, country [Finviz]""" d_economy_group = { "sector": "Sector", "industry": "Industry", "basic_materials": "Industry (Basic Materials)", "communication_services": "Industry (Communication Services)", "consumer_cyclical": "Industry (Consumer Cyclical)", "consumer_defensive": "Industry (Consumer Defensive)", "energy": "Industry (Energy)", "financial": "Industry (Financial)", "healthcare": "Industry (Healthcare)", "industrials": "Industry (Industrials)", "real_estate": "Industry (Real Estate)", "technology": "Industry (Technology)", "utilities": "Industry (Utilities)", "country": "Country (U.S. listed stocks only)", "capitalization": "Capitalization", } # Debug user input if cfg.DEBUG: logger.debug("econ-performance %s", economy_group) # Select default group if not economy_group: if cfg.DEBUG: logger.debug("Use default economy_group: 'sector'") economy_group = "sector" # Check for argument possible_groups = list(d_economy_group.keys()) if economy_group not in possible_groups: possible_group_list = ", ".join(possible_groups) raise Exception( f"Select a valid group from {possible_group_list}") # nosec group = d_economy_group[economy_group] # Retrieve data df_group = finviz_model.get_valuation_performance_data( group, "performance") # Check for argument if df_group.empty: raise Exception("No available data found") # Output data df = pd.DataFrame(df_group) df = df.replace(np.nan, 0) df["Volume"] = df["Volume"] / 1_000_000 df["Avg Volume"] = df["Avg Volume"] / 1_000_000 formats = { "Perf Month": "{:.2f}", "Perf Quart": "{:.2f}", "Perf Half": "{:.2f}", "Perf Year": "{:.2f}", "Perf YTD": "{:.2f}", "Avg Volume": "{:.0f}M", "Change": "{:.2f}", "Volume": "{:.0f}M", } for col, value in formats.items(): df[col] = df[col].map(lambda x: value.format(x)) # pylint: disable=W0640 df = df.set_axis( [ "Name", "Week", "Month", "3Month", "6Month", "1Year", "YTD", "Recom", "Avg Vol.", "RelVolume", "Change", "Volume", ], axis="columns", ) df = df.fillna("") df.set_index("Name", inplace=True) dindex = len(df.index) fig = df2img.plot_dataframe( df, fig_size=(1500, (40 + (50 * dindex))), col_width=[10, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3.5], tbl_cells=dict( align=["left", "center"], height=35, ), template="plotly_dark", font=dict( family="Consolas", size=20, ), paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image("econ-performance.png", fig) return { "title": f"Economy: [WSJ] Performance {group}", "imagefile": imagefile, }
def arktrades_command(ticker: str = "", num: int = 10): """Displays trades made by ark [cathiesark.com]""" # Debug user input if cfg.DEBUG: logger.debug("dd-arktrades %s", ticker) if ticker: ark_holdings = ark_model.get_ark_trades_by_ticker(ticker) if ark_holdings.empty: raise Exception( "Issue getting data from cathiesark.com. Likely no trades found.\n" ) ark_holdings["Total"] = ark_holdings["Total"] / 1_000_000 ark_holdings.rename(columns={ "direction": "B/S", "weight": "F %" }, inplace=True) ark_holdings = ark_holdings.drop( columns=["ticker", "everything.profile.companyName"]) ark_holdings.index = pd.Series( ark_holdings.index).apply(lambda x: x.strftime("%Y-%m-%d")) df = ark_holdings.head(num) df = df.fillna(0) dindex = len(df.head(num).index) formats = {"Close": "{:.2f}", "Total": "{:.2f}"} for col, f in formats.items(): df[col] = df[col].map(lambda x: f.format(x)) # pylint: disable=W0640 title = f"Stocks: [cathiesark.com] {ticker.upper()} Trades by Ark" embeds: list = [] i, i2, end = 0, 0, 20 df_pg = [] embeds_img = [] dindex = len(df.index) while i < dindex: df_pg = df.iloc[i:end] df_pg.append(df_pg) fig = df2img.plot_dataframe( df_pg, fig_size=(900, (40 + (40 * 20))), col_width=[5, 10, 4, 4, 3, 4, 5], tbl_cells=dict(height=35, ), font=dict( family="Consolas", size=20, ), template="plotly_dark", paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = save_image(f"dd-arktrades{i}.png", fig) uploaded_image = gst_imgur.upload_image(imagefile, title="something") image_link = uploaded_image.link embeds_img.append(f"{image_link}", ) embeds.append(disnake.Embed( title=title, colour=cfg.COLOR, ), ) i2 += 1 i += 20 end += 20 os.remove(imagefile) # Author/Footer for i in range(0, i2): embeds[i].set_author( name=cfg.AUTHOR_NAME, url=cfg.AUTHOR_URL, icon_url=cfg.AUTHOR_ICON_URL, ) embeds[i].set_footer( text=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) i = 0 for i in range(0, i2): embeds[i].set_image(url=embeds_img[i]) i += 1 embeds[0].set_footer(text=f"Page 1 of {len(embeds)}") choices = [ disnake.SelectOption(label="Home", value="0", emoji="🟢"), ] return { "view": Menu, "title": title, "embed": embeds, "choices": choices, "embeds_img": embeds_img, }
def overview_command( ticker: str = None, expiry: str = None, min_sp: float = None, max_sp: float = None, ): """Options Overview""" # Debug if cfg.DEBUG: logger.debug("opt-overview %s %s %s %s", ticker, expiry, min_sp, max_sp) # Check for argument if ticker is None: raise Exception("Stock ticker is required") # Get options info/dates, Look for logo_url df = get_options_info(ticker) # Barchart Options IV Overview dates = yfinance_model.option_expirations(ticker) # Expiration dates tup = f"{ticker.upper()}" url = yf.Ticker(tup).info["logo_url"] url += "?raw=true" if url else "" if not dates: raise Exception("Stock ticker is invalid") options = yfinance_model.get_option_chain(ticker, str(expiry)) calls = options.calls.fillna(0) puts = options.puts.fillna(0) current_price = yfinance_model.get_price(ticker) min_strike2 = np.percentile(calls["strike"], 1) max_strike2 = np.percentile(calls["strike"], 100) min_strike = 0.75 * current_price max_strike = 1.95 * current_price if len(calls) > 40: min_strike = 0.75 * current_price max_strike = 1.25 * current_price if min_sp: min_strike = min_sp min_strike2 = min_sp if max_sp: max_strike = max_sp max_strike2 = max_sp if min_sp > max_sp: # type: ignore min_sp, max_sp = max_strike2, min_strike2 call_oi = calls.set_index("strike")["openInterest"] / 1000 put_oi = puts.set_index("strike")["openInterest"] / 1000 df_opt = pd.merge(call_oi, put_oi, left_index=True, right_index=True) df_opt = df_opt.rename( columns={"openInterest_x": "OI_call", "openInterest_y": "OI_put"} ) max_pain = op_helpers.calculate_max_pain(df_opt) fig = go.Figure() dmax = df_opt[["OI_call", "OI_put"]].values.max() dmin = df_opt[["OI_call", "OI_put"]].values.min() fig.add_trace( go.Scatter( x=df_opt.index, y=df_opt["OI_call"], name="Calls", mode="lines+markers", line=dict(color="green", width=3), ) ) fig.add_trace( go.Scatter( x=df_opt.index, y=df_opt["OI_put"], name="Puts", mode="lines+markers", line=dict(color="red", width=3), ) ) fig.add_trace( go.Scatter( x=[current_price, current_price], y=[dmin, dmax], mode="lines", line=dict(color="gold", width=2), name="Current Price", ) ) fig.add_trace( go.Scatter( x=[max_pain, max_pain], y=[dmin, dmax], mode="lines", line=dict(color="grey", width=3, dash="dash"), name=f"Max Pain: {max_pain}", ) ) fig.update_xaxes( range=[min_strike, max_strike], constrain="domain", ) fig.update_layout( margin=dict(l=0, r=0, t=60, b=20), template=cfg.PLT_SCAT_STYLE_TEMPLATE, title=f"Open Interest for {ticker.upper()} expiring {expiry}", title_x=0.5, legend_title="", xaxis_title="Strike", yaxis_title="Open Interest (1k)", xaxis=dict( rangeslider=dict(visible=False), ), legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), dragmode="pan", ) config = dict({"scrollZoom": True}) imagefile = "opt_oi.png" plt_link = "" if cfg.INTERACTIVE: html_ran = helpers.uuid_get() fig.write_html(f"in/oi_{html_ran}.html", config=config) plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/oi_{html_ran}.html)" fig.update_layout( width=800, height=500, ) imagefile = helpers.image_border(imagefile, fig=fig) uploaded_image_oi = gst_imgur.upload_image(imagefile, title="something") image_link_oi = uploaded_image_oi.link os.remove(imagefile) column_map = {"openInterest": "oi", "volume": "vol", "impliedVolatility": "iv"} columns = [ "strike", "bid", "ask", "volume", "openInterest", "impliedVolatility", ] calls_df = calls[columns].rename(columns=column_map) puts_df = puts[columns].rename(columns=column_map) calls_df = calls_df[calls_df["strike"] >= min_strike2] calls_df = calls_df[calls_df["strike"] <= max_strike2] puts_df = puts_df[puts_df["strike"] >= min_strike2] puts_df = puts_df[puts_df["strike"] <= max_strike2] calls_df["iv"] = pd.to_numeric(calls_df["iv"].astype(float)) puts_df["iv"] = pd.to_numeric(puts_df["iv"].astype(float)) formats = {"iv": "{:.2f}"} for col, f in formats.items(): calls_df[col] = calls_df[col].map( lambda x: f.format(x) # pylint: disable=W0640 ) puts_df[col] = puts_df[col].map(lambda x: f.format(x)) # pylint: disable=W0640 calls_df.set_index("strike", inplace=True) puts_df.set_index("strike", inplace=True) if "-" in df.iloc[0, 1]: iv = f"```diff\n- {df.iloc[0, 1]}\n```" else: iv = f"```yaml\n {df.iloc[0, 1]}\n```" pfix, sfix = f"{ticker.upper()} ", f" expiring {expiry}" if expiry == dates[0]: pfix = f"{ticker.upper()} Weekly " sfix = "" titles = [f"{ticker.upper()} Overview", f"{pfix}Open Interest{sfix}"] embeds = [ disnake.Embed( title=f"{ticker.upper()} Overview", color=cfg.COLOR, ), disnake.Embed( title=f"{pfix}Open Interest{sfix}", description=plt_link, colour=cfg.COLOR, ), ] choices = [ disnake.SelectOption(label=f"{ticker.upper()} Overview", value="0", emoji="🟢"), disnake.SelectOption(label=f"{pfix}Open Interest{sfix}", value="1", emoji="🟢"), ] embeds_img = [] i, i2, end = 0, 0, 20 df_calls = [] dindex = len(calls_df.index) while i <= dindex: df_calls = calls_df.iloc[i:end] df_calls.append(df_calls) figc = df2img.plot_dataframe( df_calls, fig_size=(1000, (40 + (40 * 20))), col_width=[3, 3, 3, 3], tbl_cells=cfg.PLT_TBL_CELLS, font=cfg.PLT_TBL_FONT, template=cfg.PLT_TBL_STYLE_TEMPLATE, paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = helpers.save_image("opt-calls.png", figc) uploaded_image = gst_imgur.upload_image(imagefile, title="something") image_link = uploaded_image.link embeds_img.append( f"{image_link}", ) titles.append(f"{pfix}Calls{sfix}") embeds.append( disnake.Embed( title=f"{pfix}Calls{sfix}", colour=cfg.COLOR, ), ) i2 += 1 i += 20 end += 20 os.remove(imagefile) # Add Calls page field i, page, puts_page = 2, 0, 3 i3 = i2 + 2 choices.append( disnake.SelectOption(label="Calls Page 1", value="2", emoji="🟢"), ) for i in range(2, i3): page += 1 puts_page += 1 embeds[i].add_field(name=f"Calls Page {page}", value="_ _", inline=True) # Puts Pages i, end = 0, 20 df_puts = [] dindex = len(puts_df.index) while i <= dindex: df_puts = puts_df.iloc[i:end] df_puts.append(df_puts) figp = df2img.plot_dataframe( df_puts, fig_size=(1000, (40 + (40 * 20))), col_width=[3, 3, 3, 3], tbl_cells=cfg.PLT_TBL_CELLS, font=cfg.PLT_TBL_FONT, template=cfg.PLT_TBL_STYLE_TEMPLATE, paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = helpers.save_image("opt-puts.png", figp) uploaded_image = gst_imgur.upload_image(imagefile, title="something") image_link = uploaded_image.link embeds_img.append( f"{image_link}", ) titles.append(f"{pfix}Puts{sfix}") embeds.append( disnake.Embed( title=f"{pfix}Puts{sfix}", colour=cfg.COLOR, ), ) i2 += 1 i += 20 end += 20 os.remove(imagefile) # Add Puts page field i, page = 0, 0 puts_page -= 1 i2 += 2 choices.append( disnake.SelectOption(label="Puts Page 1", value=f"{puts_page}", emoji="🟢"), ) for i in range(puts_page, i2): page += 1 embeds[i].add_field(name=f"Puts Page {page}", value="_ _", inline=True) # Author/Footer for i in range(0, i2): embeds[i].set_author( name=cfg.AUTHOR_NAME, url=cfg.AUTHOR_URL, icon_url=cfg.AUTHOR_ICON_URL, ) embeds[i].set_footer( text=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) # Set images to Pages i = 0 img_i = 0 embeds[1].set_image(url=image_link_oi) for i in range(2, i2): embeds[i].set_image(url=embeds_img[img_i]) img_i += 1 i += 1 if url: embeds[0].set_thumbnail(url=f"{url}") else: embeds[0].set_thumbnail(url=cfg.AUTHOR_ICON_URL) # Overview Section embeds[0].add_field(name=f"{df.iloc[0, 0]}", value=iv, inline=False) embeds[0].add_field( name=f"•{df.iloc[1, 0]}", value=f"```css\n{df.iloc[1, 1]}\n```", inline=True ) for N in range(2, 6): embeds[0].add_field( name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}", value=f"```css\n{df.iloc[N, 1]}\n```", inline=True, ) embeds[0].add_field(name="_ _", value="_ _", inline=False) for N in range(6, 8): embeds[0].add_field( name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}", value=f"```css\n{df.iloc[N, 1]}\n```", inline=True, ) embeds[0].add_field(name="_ _", value="_ _", inline=False) for N in range(8, 10): embeds[0].add_field( name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}", value=f"```css\n{df.iloc[N, 1]}\n```", inline=True, ) embeds[0].add_field(name="_ _", value="_ _", inline=False) for N in range(10, 12): embeds[0].add_field( name=f"_ _ _ _ _ _ _ _ _ _ •{df.iloc[N, 0]}", value=f"```css\n{df.iloc[N, 1]}\n```", inline=True, ) embeds[0].set_footer(text=f"Page 1 of {len(embeds)}") os.remove(imagefile) return { "view": Menu, "titles": titles, "embed": embeds, "choices": choices, "embeds_img": embeds_img, }