def aroon_command( ticker="", interval: int = 15, past_days: int = 0, length="25", scalar="100", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with aroon indicator [Yahoo Finance]""" # Debug if imps.DEBUG: logger.debug( "ta aroon %s %s %s %s %s, %s, %s, %s, %s, %s", ticker, interval, past_days, length, scalar, start, end, extended_hours, heikin_candles, news, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") length = int(length) if not scalar.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") scalar = float(scalar) # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = df_ta.join( trend_indicators_model.aroon(df_ta["High"], df_ta["Low"], length, scalar)) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, rows=3, cols=1, shared_xaxes=True, vertical_spacing=0.02, row_width=[0.2, 0.2, 0.3], specs=[ [{ "secondary_y": True }], [{ "secondary_y": False }], [{ "secondary_y": False }], ], ) title = f"<b>{plot['plt_title']} Aroon ({length})</b>" fig = plot["fig"] idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name="Aroon DOWN", x=df_ta.index, y=df_ta.iloc[:, idx].values, opacity=1, ), row=2, col=1, secondary_y=False, ) fig.add_trace( go.Scatter( name="Aroon UP", x=df_ta.index, y=df_ta.iloc[:, (idx + 1)].values, opacity=1, ), row=2, col=1, secondary_y=False, ) fig.add_trace( go.Scatter( name="Aroon OSC", x=df_ta.index, y=df_ta.iloc[:, (idx + 2)].values, opacity=1, ), row=3, col=1, secondary_y=False, ) fig.add_hline( y=50, fillcolor="grey", opacity=1, layer="below", line_width=3, line=dict(color="grey", dash="dash"), row=2, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.1, title_font_size=14, dragmode="pan", yaxis=dict(nticks=10), yaxis2=dict(nticks=10), ) imagefile = "ta_aroon.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Aroon-Indicator {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def candle_command( ticker: str = "", interval: int = 15, past_days: int = 0, extended_hours: bool = False, start="", end="", news: bool = False, heikin_candles: bool = False, vwap: bool = False, ): """Shows candle plot of loaded ticker or crypto. [Source: Yahoo Finance or Binance API] Parameters ---------- ticker : Stock Ticker interval : Chart Minute Interval, 1440 for Daily past_days: Past Days to Display. Default: 0(Not for Daily) extended_hours: Display Pre/After Market Hours. Default: False start: YYYY-MM-DD format end: YYYY-MM-DD format news: Display clickable news markers on interactive chart. Default: False heikin_candles: Heikin Ashi candles. Default: False """ logger.info( "candle %s %s %s %s %s %s %s %s", ticker, interval, past_days, extended_hours, start, end, news, heikin_candles, ) # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, news=news, heikin_candles=heikin_candles, ) df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_stock = df_stock.join(overlap_model.vwap(df_stock, 0)) # Check that loading a stock was not successful if df_stock.empty: raise Exception(f"No data found for {ticker.upper()}.") # Output Data if interval != 1440: df_stock = df_stock.loc[(df_stock.index >= bar_start) & (df_stock.index < end)] plot = load_candle.candle_fig( df_stock, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, ) title = f"{plot['plt_title']} Chart" fig = plot["fig"] if interval != 1440 and vwap: fig.add_trace( go.Scatter( name="VWAP", x=df_stock.index, y=df_stock["VWAP_D"], opacity=0.65, line=dict(color="#00e6c3", width=2), showlegend=True, ), secondary_y=True, ) fig.update_layout( margin=dict(l=0, r=0, t=40, b=20), template=imps.PLT_CANDLE_STYLE_TEMPLATE, title=title, title_x=0.5, title_font_size=14, ) imagefile = "candle.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=True) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": title, "description": plt_link, "imagefile": imagefile, }
def adx_command( ticker="", interval: int = 15, past_days: int = 0, length="14", scalar="100", drift="1", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with average directional movement index [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta adx %s %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, length, scalar, drift, start, end, extended_hours, heikin_candles, news, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") length = float(length) if not scalar.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") scalar = float(scalar) if not drift.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") drift = float(drift) df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] if df_ta.empty: raise Exception("No Data Found") ta_data = trend_indicators_model.adx( df_stock["High"], df_stock["Low"], df_stock["Adj Close"], length, scalar, drift, ) df_ta = df_ta.join(ta_data) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.07, row_width=[0.4, 0.6], specs=[[{ "secondary_y": True }], [{ "secondary_y": False }]], ) title = f"<b>{plot['plt_title']} Average Directional Movement Index</b>" fig = plot["fig"] idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name=f"ADX ({length})", mode="lines", x=df_ta.index, y=df_ta.iloc[:, idx].values, opacity=1, line=dict(width=2), ), secondary_y=False, row=2, col=1, ) fig.add_trace( go.Scatter( name=f"+DI ({length})", mode="lines", x=df_ta.index, y=df_ta.iloc[:, (idx + 1)].values, opacity=1, line=dict(width=1), ), secondary_y=False, row=2, col=1, ) fig.add_trace( go.Scatter( name=f"-DI ({length})", mode="lines", x=df_ta.index, y=df_ta.iloc[:, (idx + 2)].values, opacity=1, line=dict(width=1), ), secondary_y=False, row=2, col=1, ) fig.add_hline( y=25, fillcolor="grey", opacity=1, layer="below", line_width=3, line=dict(color="grey", dash="dash"), row=2, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.01, title_font_size=12, dragmode="pan", ) imagefile = "ta_adx.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Average-Directional-Movement-Index {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def hist_command( ticker: str = "", expiry: str = "", strike: float = 10, opt_type: str = "", greek: str = "", ): """Plot historical option prices Parameters ---------- ticker: str Stock ticker expiry: str expiration date strike: float Option strike price put: bool Calls for call Puts for put """ # Debug if imps.DEBUG: logger.info("opt grhist %s %s %s %s %s", ticker, strike, opt_type, expiry, greek) # Check for argument if ticker is None: raise Exception("Stock ticker is required") if opt_type == "Puts": put = bool(True) if opt_type == "Calls": put = bool(False) chain_id = "" df_hist = syncretism_model.get_historical_greeks(ticker, expiry, chain_id, strike, put) title = f"\n{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical {greek.upper()}" # Output data fig = make_subplots(shared_xaxes=True, specs=[[{"secondary_y": True}]]) fig.add_trace( go.Scatter( name=ticker.upper(), x=df_hist.index, y=df_hist.price, line=dict(color="#fdc708", width=2), opacity=1, ), ) fig.add_trace( go.Scatter( name="Premium", x=df_hist.index, y=df_hist["premium"], opacity=1, yaxis="y2", ), ) if greek: fig.add_trace( go.Scatter( name=f"{greek.upper()}", x=df_hist.index, y=df_hist[greek], opacity=1, yaxis="y3", ), ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_layout( margin=dict(l=10, r=10, t=30, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.03, title_font_size=14, yaxis_title="<b>Stock Price</b>", font=imps.PLT_FONT, yaxis=dict( side="right", fixedrange=False, titlefont=dict(color="#fdc708"), tickfont=dict(color="#fdc708"), showgrid=False, position=0.02, nticks=20, ), xaxis=dict( rangeslider=dict(visible=False), type="date", fixedrange=False, domain=[0.037, 1], ), xaxis2=dict( rangeslider=dict(visible=False), type="date", fixedrange=False, ), xaxis3=dict( rangeslider=dict(visible=False), type="date", fixedrange=False, ), dragmode="pan", legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), yaxis2=dict( side="left", fixedrange=False, anchor="x", overlaying="y", titlefont=dict(color="#d81aea"), tickfont=dict(color="#d81aea"), nticks=20, ), yaxis3=dict( side="left", position=0, fixedrange=False, showgrid=False, overlaying="y", titlefont=dict(color="#00e6c3"), tickfont=dict(color="#00e6c3"), nticks=20, ), hovermode="x unified", ) imagefile = "opt_hist.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical", "description": plt_link, "imagefile": imagefile, }
def cpi_command(start=""): """Displays Consumer Prices Index (CPI)""" # Debug if imps.DEBUG: logger.debug( "econ cpi %s", start, ) if start == "": start = datetime.now() - timedelta(days=900) else: start = datetime.strptime(start, imps.DATE_FORMAT) # Retrieve data df_d = ("date", "CPI") series_ids = list(df_d) data = pd.DataFrame() for s_id in series_ids: data = pd.concat( [ data, pd.DataFrame(fred_model.get_series_data("CPIAUCSL", start), columns=[s_id]), ], axis=1, ) df = data.dropna() # Check for argument if df.empty: raise Exception("No available data found") data["date"] = pd.to_datetime(data["date"]) data["CPI"] = data["CPI"].astype(float) data = data.drop(columns=["CPI"]) end = datetime.now() + timedelta(days=30) # Debug user output if imps.DEBUG: logger.debug(df.to_string()) fig = go.Figure() fig.add_trace(go.Scatter( x=df.index, y=df["CPI"], )) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_xaxes(dtick="M2", tickformat="%b\n%Y") fig.update_layout( xaxis_range=[df.index[0], end], margin=dict(l=0, r=0, t=40, b=50), template=imps.PLT_SCAT_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title="CPI Monthly", title_x=0.5, yaxis_title="Consumer Prices", legend_title="", font=imps.PLT_FONT, yaxis=dict( fixedrange=False, nticks=20, ), xaxis=dict( rangeslider=dict(visible=False), type="date", ), legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), dragmode="pan", ) imagefile = "econ-cpi.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": "Consumer Prices Index", "description": plt_link, "imagefile": imagefile, }
def macd_command( ticker="", interval: int = 15, past_days: int = 0, fast="12", slow="26", signal="9", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with moving average convergence/divergence [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta macd %s %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, fast, slow, signal, start, end, extended_hours, heikin_candles, news, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") if not fast.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") fast = int(fast) if not slow.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") slow = int(slow) if not signal.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") signal = int(signal) df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] if df_ta.empty: raise Exception("No Data Found") ta_data = momentum_model.macd(df_stock["Adj Close"], fast, slow, signal) df_ta = df_ta.join(ta_data) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.07, row_width=[0.4, 0.6], specs=[[{"secondary_y": True}], [{"secondary_y": False}]], ) title = f"<b>{plot['plt_title']} MACD {fast} {slow} {signal}</b>" fig = plot["fig"] idx = 6 if interval != 1440 else 11 fig.add_trace( go.Bar( name="MACD Histogram", x=df_ta.index, y=df_ta.iloc[:, (idx + 1)].values, opacity=(plot["bar_opacity"] + 0.3), marker_color="#d81aea", ), row=2, col=1, secondary_y=False, ) fig.add_trace( go.Scatter( name="MACD Line", mode="lines", x=df_ta.index, y=df_ta.iloc[:, idx].values, opacity=0.8, line=dict(color="#00e6c3"), ), row=2, col=1, secondary_y=False, ) fig.add_trace( go.Scatter( name="Signal Line", mode="lines", x=df_ta.index, y=df_ta.iloc[:, (idx + 2)].values, opacity=1, line=dict(color="#9467bd"), ), row=2, col=1, secondary_y=False, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.02, title_font_size=14, dragmode="pan", ) imagefile = "ta_macd.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Moving-Average-Convergence-Divergence {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def fib_command( ticker="", interval: int = 15, past_days: int = 0, start: str = "", end: str = "", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with fibonacci retracement [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta fib %s %s %s %s %s %s %s %s", ticker, interval, past_days, start, end, extended_hours, heikin_candles, news, ) past_days = (past_days + 1) if (interval != 1440) or (start != "") else 365 # Retrieve Data ( df_stock, start, end, bar_start, ) = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception(f"No data found for {ticker.upper()}.") df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] ( df_fib, min_date, max_date, min_pr, max_pr, ) = custom_indicators_model.calculate_fib_levels(df_ta, 12, bar_start, None) levels = df_fib.Price # Output Data fibs = [ "<b>0</b>", "<b>0.235</b>", "<b>0.382</b>", "<b>0.5</b>", "<b>0.618</b>", "<b>0.65</b>", "<b>1</b>", ] plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, shared_xaxes=True, vertical_spacing=0.07, ) title = f"<b>{plot['plt_title']} Fibonacci-Retracement-Levels</b>" lvl_text: str = "right" if min_date > max_date else "left" fig = plot["fig"] fig.add_trace( go.Scatter( x=[min_date, max_date], y=[min_pr, max_pr], opacity=1, mode="lines", line=imps.PLT_FIB_COLORWAY[8], showlegend=False, ), row=1, col=1, secondary_y=True, ) for i in range(6): fig.add_trace( go.Scatter( name=fibs[i], x=[min_date, max_date], y=[levels[i], levels[i]], opacity=0.2, mode="lines", line_color=imps.PLT_FIB_COLORWAY[i], showlegend=False, ), row=1, col=1, secondary_y=True, ) fig.add_trace( go.Scatter( name=fibs[i + 1], x=[min_date, max_date], y=[levels[i + 1], levels[i + 1]], opacity=0.2, mode="lines", fill="tonexty", line_color=imps.PLT_FIB_COLORWAY[i + 1], showlegend=False, ), row=1, col=1, secondary_y=True, ) for i in range(7): fig.add_trace( go.Scatter( name=fibs[i], x=[min_date], y=[levels[i]], opacity=0.9, mode="text", text=fibs[i], textposition=f"middle {lvl_text}" if i != 5 else f"bottom {lvl_text}", textfont=dict(imps.PLT_FIB_COLORWAY[7], color=imps.PLT_FIB_COLORWAY[i]), showlegend=False, ), row=1, col=1, secondary_y=True, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, title=title, title_x=0.02, title_font_size=14, dragmode="pan", ) imagefile = "ta_fib.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Fibonacci-Retracement-Levels {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def cc_hist_command(ticker: str = None, expiry: str = "", strike: float = 10, opt_type: str = ""): """Plot historical option prices Parameters ---------- ticker: str Stock ticker expiry: str expiration date strike: float Option strike price put: bool Calls for call Puts for put """ # Debug if imps.DEBUG: logger.info("opt hist %s, %s, %s, %s", ticker, strike, opt_type, expiry) # Check for argument if ticker is None: raise Exception("Stock ticker is required") yf_ticker = yf.Ticker(ticker) dates = list(yf_ticker.options) if not dates: raise Exception("Stock ticker is invalid") options = yf.Ticker(ticker).option_chain(expiry) if opt_type == "Calls": options = options.calls if opt_type == "Puts": options = options.puts chain_id = options.loc[options.strike == strike, "contractSymbol"].values[0] df_hist = yf.download(chain_id) df_hist.index.name = "date" title = f"{ticker.upper()} {strike} {opt_type} expiring {expiry} Historical" fig = make_subplots( shared_xaxes=True, specs=[[{ "secondary_y": True }]], ) fig.add_trace( go.Candlestick( x=df_hist.index, open=df_hist.Open, high=df_hist.High, low=df_hist.Low, close=df_hist.Close, name="OHLC", increasing_line_color="#00ACFF", decreasing_line_color="#e4003a", showlegend=False, ), secondary_y=True, ) fig.add_trace( go.Bar( x=df_hist.index, y=df_hist.Volume, name="Volume", yaxis="y2", marker_color="#fdc708", opacity=0.3, showlegend=False, ), secondary_y=False, ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_layout( margin=dict(l=0, r=0, t=25, b=5), template=imps.PLT_CANDLE_STYLE_TEMPLATE, showlegend=False, title=title, title_x=0.1, title_font_size=14, yaxis2_title="Premium", yaxis_title="Volume", font=imps.PLT_FONT, yaxis=dict( showgrid=False, fixedrange=False, side="left", titlefont=dict(color="#fdc708", size=12), tickfont=dict( color="#fdc708", size=14, ), nticks=20, ), yaxis2=dict( side="right", fixedrange=False, anchor="x", layer="above traces", overlaying="y", nticks=20, tickfont=dict(size=14, ), showline=False, ), xaxis=dict( rangeslider=dict(visible=False), type="date", ), dragmode="pan", ) fig.update_xaxes(rangebreaks=[ dict(bounds=["sat", "mon"]), ], ) imagefile = "opt_hist.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": title, "description": plt_link, "imagefile": imagefile, }
def ad_command( ticker="", interval: int = 15, past_days: int = 0, is_open: bool = False, start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with accumulation/distribution line [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta ad %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, is_open, start, end, extended_hours, heikin_candles, news, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = df_ta.join(volume_model.ad(df_stock, is_open)) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.07, row_width=[0.4, 0.6], specs=[ [{ "secondary_y": True }], [{ "secondary_y": False }], ], ) title = f"<b>{plot['plt_title']} A/D</b>" fig = plot["fig"] fig.add_trace( go.Scatter( name="A/D", x=df_ta.index, y=df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values, mode="lines", line=dict(width=2), opacity=1, ), row=2, col=1, ) fig.add_hline( y=0, fillcolor="grey", opacity=1, layer="below", line_width=3, line=dict(color="grey", dash="dash"), row=2, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.1, title_font_size=14, dragmode="pan", ) imagefile = "ta_ad.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Accumulation/Distribution Line {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def spos_command(ticker: str = ""): """Net short vs position [Stockgrid]""" # Debug user input if imps.DEBUG: logger.debug("dps-spos %s", ticker) # Check for argument if ticker == "": raise Exception("Stock ticker is required") ticker = ticker.upper() stock = yf.download(ticker, progress=False) if stock.empty: raise Exception("Stock ticker is invalid") # Retrieve data df = stockgrid_model.get_net_short_position(ticker) # Debug user output if imps.DEBUG: logger.debug(df.to_string()) # Output data title = f"Stocks: [Stockgrid] Net Short vs Position {ticker}" fig = make_subplots(shared_xaxes=True, specs=[[{"secondary_y": True}]]) fig.add_trace( go.Scatter( name="Position ($)", x=df["dates"].values, y=df["dollar_dp_position"] * 1_000, line=dict(color="#fdc708", width=2), opacity=1, showlegend=False, ), secondary_y=True, ) fig.add_trace( go.Bar( name="Net Short Vol. ($)", x=df["dates"], y=df["dollar_net_volume"], opacity=1, showlegend=False, ), secondary_y=False, ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) # Set y-axes titles fig.update_xaxes(dtick="M1", tickformat="%b %d\n%Y") fig.update_yaxes(title_text="<b>Position</b> ($)", secondary_y=True) fig.update_traces(hovertemplate="%{y:.2s}") fig.update_layout( margin=dict(l=0, r=10, t=40, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=f"Net Short Vol. vs Position for {ticker}", title_x=0.5, yaxis_title="<b>Net Short Vol.</b> ($)", font=imps.PLT_FONT, yaxis=dict( side="left", showgrid=False, fixedrange=False, layer="above traces", titlefont=dict(color="#d81aea"), tickfont=dict(color="#d81aea"), nticks=10, ), xaxis=dict( rangeslider=dict(visible=False), type="date", fixedrange=False, ), xaxis2=dict( rangeslider=dict(visible=False), type="date", fixedrange=False, ), dragmode="pan", legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), yaxis2=dict( side="right", position=0.15, fixedrange=False, titlefont=dict(color="#fdc708"), tickfont=dict(color="#fdc708"), nticks=10, ), hovermode="x unified", ) imagefile = "dps_spos.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": title, "description": plt_link, "imagefile": imagefile, }
def vsurf_command( ticker: str = "", z: str = "IV", ): """Display vol surface Parameters ---------- ticker: Stock Ticker z : The variable for the Z axis """ # Debug if imps.DEBUG: logger.debug("opt vsurf %s %s", ticker, z) # Check for argument if ticker == "": raise Exception("Stock ticker is required") data = yfinance_model.get_iv_surface(ticker) if data.empty: raise Exception(f"No options data found for {ticker}.\n") Y = data.dte X = data.strike if z == "IV": Z = data.impliedVolatility label = "Volatility" elif z == "OI": Z = data.openInterest label = "Open Interest" elif z == "LP": Z = data.lastPrice label = "Last Price" points3D = np.vstack((X, Y, Z)).T points2D = points3D[:, :2] tri = Delaunay(points2D) I, J, K = tri.simplices.T lighting_effects = dict( ambient=0.5, diffuse=0.5, roughness=0.5, specular=0.4, fresnel=0.4 ) fig = go.Figure( data=[ go.Mesh3d( z=Z, x=X, y=Y, i=I, j=J, k=K, intensity=Z, colorscale=imps.PLT_3DMESH_COLORSCALE, hovertemplate="<b>DTE</b>: %{y} <br><b>Strike</b>: %{x} <br><b>" + z + "</b>: %{z}<extra></extra>", showscale=False, flatshading=True, lighting=lighting_effects, ) ] ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_layout( scene=dict( xaxis=dict( title="Strike", tickfont=dict(size=11), titlefont=dict(size=12), ), yaxis=dict( title="DTE", ), zaxis=dict( title=z, ), ), ) fig.update_layout( margin=dict(l=0, r=0, t=40, b=20), template=imps.PLT_3DMESH_STYLE_TEMPLATE, title=f"{label} Surface for {ticker.upper()}", title_x=0.5, hoverlabel=imps.PLT_3DMESH_HOVERLABEL, scene_camera=dict( up=dict(x=0, y=0, z=2), center=dict(x=0, y=0, z=-0.3), eye=dict(x=1.25, y=1.25, z=0.69), ), scene=imps.PLT_3DMESH_SCENE, ) imagefile = "opt-vsurf.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"{label} Surface for {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def metric_command( finance_key: str, finance_metric: str, ticker: str = "", ): """Display financials bars comparing sectors, industry, analysis, countries, market cap and excluding exchanges. Parameters ---------- finance_key: str Select finance key from Yahoo Finance(e.g. financialData, defaultKeyStatistics, summaryProfile) finance_metric: str Select finance metric from Yahoo Finance (e.g. operatingCashflow, revenueGrowth, ebitda, freeCashflow) ticker: str Company ticker to use as the basis. """ logger.info("metrics") exclude_exchanges: bool = True limit: int = 10 ticker = ticker.lower() if ticker: data = yfinance.utils.get_json(f"https://finance.yahoo.com/quote/{ticker}") if "summaryProfile" in data: country = data["summaryProfile"]["country"] if country not in financedatabase_model.get_countries(): similar_cmd = difflib.get_close_matches( country, financedatabase_model.get_countries(), n=1, cutoff=0.7, ) if similar_cmd: country = similar_cmd[0] sector = data["summaryProfile"]["sector"] if sector not in financedatabase_model.get_sectors(): similar_cmd = difflib.get_close_matches( sector, financedatabase_model.get_sectors(), n=1, cutoff=0.7, ) if similar_cmd: sector = similar_cmd[0] industry = data["summaryProfile"]["industry"] if industry not in financedatabase_model.get_industries(): similar_cmd = difflib.get_close_matches( industry, financedatabase_model.get_industries(), n=1, cutoff=0.7, ) if similar_cmd: industry = similar_cmd[0] if "price" in data: mktcap = data["price"]["marketCap"] if mktcap < 2_000_000_000: mktcap = "Small" elif mktcap > 10_000_000_000: mktcap = "Large" else: mktcap = "Mid" stocks_data = financedatabase_model.get_stocks_data( country, sector, industry, mktcap, exclude_exchanges ) metric_data = {} for symbol in list(stocks_data.keys()): if finance_key in stocks_data[symbol] and "quoteType" in stocks_data[symbol]: stock_name = stocks_data[symbol]["quoteType"]["longName"] metric = ( stocks_data[symbol][finance_key][finance_metric] if stocks_data[symbol][finance_key] is not None and finance_metric in stocks_data[symbol][finance_key] else None ) if metric and stock_name: metric_data[stock_name] = (metric, symbol) if len(metric_data) > 1: metric_data = dict( OrderedDict( sorted(metric_data.items(), key=lambda t: t[1][0], reverse=True) ) ) company_names = list() company_metrics = list() company_tickers = list() for name, metric in metric_data.items(): company_names.append(name) company_metrics.append(metric[0]) company_tickers.append(metric[1]) company_name = np.array(company_names)[:limit] company_metric = np.array(company_metrics)[:limit] company_ticker = np.array(company_tickers)[:limit] magnitude = 0 while max(company_metric) > 1_000 or abs(min(company_metric)) > 1_000: company_metric = np.divide(company_metric, 1_000) magnitude += 1 # check if the value is a percentage if (magnitude == 0) and all(company_metric >= 0) and all(company_metric <= 1): unit = "%" company_metric = company_metric * 100 else: unit = " KMBTP"[magnitude] colors = [ "#ffed00", "#ef7d00", "#e4003a", "#c13246", "#822661", "#48277c", "#005ca9", "#00aaff", "#9b30d9", "#af005f", "#5f00af", "#af87ff", ] fig = go.Figure() i = 0 for name, metric, tickers in zip( company_name[::-1], company_metric[::-1], company_ticker[::-1] ): if len(name.split(" ")) > 6 and len(name) > 40: name = ( f'{" ".join(name.split(" ")[:4])}\n{" ".join(name.split(" ")[4:])}' ) df_name = [] df_metric = [] df_tickers = [] df_name.append(name) df_metric.append(metric) df_tickers.append(tickers) fig.add_trace( go.Bar( name=tickers, y=[name], x=[metric], orientation="h", marker=dict( color=colors[i], line=dict(color="rgb(248, 248, 249)", width=1), ), ), ) i += 1 metric_title = ( "".join( " " + char if char.isupper() else char.strip() for char in finance_metric ) .strip() .capitalize() ) benchmark = np.median(company_metric) if unit != " ": units = f" [{unit}] " else: units = " " title = f"{metric_title.capitalize()}{units}with benchmark of {benchmark:.2f} {unit}<br>" title += mktcap + " cap companies " if mktcap else "Companies " if industry: title += f"in {industry} industry<br>" elif sector: title += f"in {sector} sector<br>" if country: title += f"in {country}" title += " " if (industry or sector) else "<br>" title += ( "(excl. data from international exchanges)" if exclude_exchanges else "(incl. data from international exchanges)" ) fig.add_vline( x=benchmark, fillcolor="grey", opacity=1, layer="below", line_width=3, line=dict(color="grey", dash="dash"), ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_layout( margin=dict(l=40, r=0, t=100, b=20), template=imps.PLT_CANDLE_STYLE_TEMPLATE, title=title, colorway=colors, font=imps.PLT_FONT, legend={"traceorder": "reversed"}, ) imagefile = "sia_metrics.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": "Stocks - Sector and Industry Analysis", "description": plt_link, "imagefile": imagefile, }
def smile_command( ticker: str = None, expiry: str = "", min_sp: float = None, max_sp: float = None, ): """Options Smile""" # Debug if imps.DEBUG: logger.debug("opt smile %s %s %s %s", ticker, expiry, min_sp, max_sp) # Check for argument if ticker is None: 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, expiry) calls = options.calls.fillna(0.0) puts = options.puts.fillna(0.0) current_price = yfinance_model.get_price(ticker) min_strike = 0.60 * current_price max_strike = 1.95 * current_price if len(calls) > 40: min_strike = 0.60 * current_price max_strike = 1.50 * current_price if min_sp: min_strike = min_sp if max_sp: max_strike = max_sp fig = go.Figure() fig.add_trace( go.Scatter( x=calls["strike"], y=calls["impliedVolatility"].interpolate(method="nearest"), name="Calls", mode="lines+markers", marker=dict( color="#00ACFF", size=4.5, ), line=dict(color="#00ACFF", width=2, dash="dash"), )) fig.add_trace( go.Scatter( x=puts["strike"], y=puts["impliedVolatility"].interpolate(method="nearest"), name="Puts", mode="lines+markers", marker=dict( color="#e4003a", size=4.5, ), line=dict(color="#e4003a", width=2, dash="dash"), )) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_xaxes( range=[min_strike, max_strike], constrain="domain", ) fig.update_layout( margin=dict(l=20, r=0, t=60, b=20), template=imps.PLT_SCAT_STYLE_TEMPLATE, font=imps.PLT_FONT, title= f"<b>Implied Volatility vs. Strike for {ticker.upper()} expiring {expiry}</b>", title_x=0.5, legend_title="", xaxis_title="Strike", yaxis_title="Implied Volatility", yaxis=dict( side="right", fixedrange=False, nticks=20, ), xaxis=dict( rangeslider=dict(visible=False), nticks=20, ), legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), dragmode="pan", ) imagefile = "opt_smile.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Implied Volatility vs. Stirke for {ticker.upper()} expiring {expiry}", "description": plt_link, "imagefile": imagefile, }
def ma_command( ticker="", interval: int = 15, past_days: int = 0, ma_mode="ema", window="", offset: int = 0, start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with selected Moving Average [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta ma %s %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, ma_mode, window, offset, start, end, extended_hours, heikin_candles, news, ) # Check for argument overlap_ma = { "ema": overlap_model.ema, "hma": overlap_model.hma, "sma": overlap_model.sma, "wma": overlap_model.wma, "zlma": overlap_model.zlma, } if ticker == "": raise Exception("Stock ticker is required") # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") if window == "": window = [20, 50] else: window_temp = list() for wind in window.split(","): try: window_temp.append(int(wind)) except Exception as e: raise Exception("Window needs to be a float") from e window = window_temp df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] if df_ta.empty: raise Exception("No Data Found") for win in window: ema_data = overlap_ma[ma_mode](values=df_ta["Adj Close"], length=win, offset=offset) df_ta = df_ta.join(ema_data) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, ) title = f"<b>{plot['plt_title']} Moving Average ({ma_mode.upper()})</b>" fig = plot["fig"] i2 = 6 if interval != 1440 else 11 for i in range(i2, df_ta.shape[1]): fig.add_trace( go.Scatter( name=f"{df_ta.iloc[:, i].name}", mode="lines", x=df_ta.index, y=df_ta.iloc[:, i].values, opacity=1, ), secondary_y=True, row=1, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.1, title_font_size=14, dragmode="pan", ) imagefile = "ta_ma.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Moving Average {ma_mode.upper()}", "description": plt_link, "imagefile": imagefile, }
def vol_command( ticker: str = None, expiry: str = "", min_sp: float = None, max_sp: float = None, ): """Options VOL""" # Debug if imps.DEBUG: logger.debug("opt-vol %s %s %s %s", ticker, expiry, min_sp, max_sp) # Check for argument if ticker is None: 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, expiry) current_price = yfinance_model.get_price(ticker) if min_sp is None: min_strike = 0.75 * current_price else: min_strike = min_sp if max_sp is None: max_strike = 1.25 * current_price else: max_strike = max_sp calls = options.calls puts = options.puts call_v = calls.set_index("strike")["volume"] / 1000 put_v = puts.set_index("strike")["volume"] / 1000 call_v = call_v.fillna(0.0) put_v = put_v.fillna(0.0) df_opt = pd.merge(put_v, call_v, left_index=True, right_index=True) dmax = df_opt.values.max() fig = go.Figure() fig.add_trace( go.Scatter( x=call_v.index, y=call_v.values, name="Calls", mode="lines+markers", line=dict(color="#00ACFF", width=3), ) ) fig.add_trace( go.Scatter( x=put_v.index, y=put_v.values, name="Puts", mode="lines+markers", line=dict(color="#e4003a", width=3), ) ) fig.add_trace( go.Scatter( x=[current_price, current_price], y=[0, dmax], mode="lines", line=dict(color="gold", width=2), name="Current Price", ) ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_xaxes( range=[min_strike, max_strike], constrain="domain", ) fig.update_layout( margin=dict(l=0, r=0, t=60, b=20), template=imps.PLT_SCAT_STYLE_TEMPLATE, title=f"Volume for {ticker.upper()} expiring {expiry}", title_x=0.5, legend_title="", xaxis_title="Strike", yaxis_title="Volume (1k)", yaxis=dict( fixedrange=False, nticks=20, ), xaxis=dict( rangeslider=dict(visible=False), ), legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), dragmode="pan", ) imagefile = "opt_vol.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Volume for {ticker.upper()} expiring {expiry}", "description": plt_link, "imagefile": imagefile, }
def bbands_command( ticker="", interval: int = 15, past_days: int = 0, length="20", n_std: float = 2.0, ma_mode="sma", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with bollinger bands [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta bbands %s %s %s %s %s %s %s %s %s %s", ticker, past_days, length, n_std, ma_mode, start, end, extended_hours, heikin_candles, news, ) # Check for argument possible_ma = [ "dema", "ema", "fwma", "hma", "linreg", "midpoint", "pwma", "rma", "sinwma", "sma", "swma", "t3", "tema", "trima", "vidya", "wma", "zlma", ] if ticker == "": raise Exception("Stock ticker is required") if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") ta_length = float(length) n_std = float(n_std) if ma_mode not in possible_ma: raise Exception("Invalid ma entered") # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = df_ta.join( volatility_model.bbands(df_ta["Adj Close"], ta_length, n_std, ma_mode)) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig(df_ta, ticker, interval, extended_hours, news) title = f"<b>{plot['plt_title']} Bollinger Bands ({ma_mode.upper()})</b>" fig = plot["fig"] idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name=f"BBU_{length}_{n_std}", x=df_ta.index, y=df_ta.iloc[:, (idx + 2)].values, opacity=1, mode="lines", line_color="indigo", ), secondary_y=True, row=1, col=1, ) fig.add_trace( go.Scatter( name=f"BBL_{length}_{n_std}", x=df_ta.index, y=df_ta.iloc[:, idx].values, opacity=1, mode="lines", line_color="indigo", fill="tonexty", fillcolor="rgba(74, 0, 128, 0.2)", ), secondary_y=True, row=1, col=1, ) fig.add_trace( go.Scatter( name=f"BBM_{length}_{n_std}", x=df_ta.index, y=df_ta.iloc[:, (idx + 1)].values, opacity=1, line=dict( width=1.5, dash="dash", ), ), secondary_y=True, row=1, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.1, title_font_size=14, dragmode="pan", ) imagefile = "ta_bbands.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Bollinger-Bands {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def ftd_command(ticker: str = "", start="", end=""): """Fails-to-deliver data [SEC]""" # Debug user input if imps.DEBUG: logger.debug("dps ftd %s %s %s", ticker, start, end) # Check for argument if ticker == "": raise Exception("Stock ticker is required") ticker = ticker.upper() if start == "": start = datetime.now() - timedelta(days=365) else: start = datetime.strptime(start, imps.DATE_FORMAT) if end == "": end = datetime.now() else: end = datetime.strptime(end, imps.DATE_FORMAT) # Retrieve data ftds_data = sec_model.get_fails_to_deliver(ticker, start, end, 0) # Debug user output if imps.DEBUG: logger.debug(ftds_data.to_string()) stock = imps.load(ticker, start) stock_ftd = stock[stock.index > start] stock_ftd = stock_ftd[stock_ftd.index < end] ftd_opacity = 0.4 if (start > (datetime.now() - timedelta(days=30))) else 0.6 ftd_opacity = ( ftd_opacity if (start > (datetime.now() - timedelta(days=120))) else 0.9 ) # Output data fig = make_subplots(shared_xaxes=True, specs=[[{"secondary_y": True}]]) fig.add_trace( go.Scatter( name=ticker, x=stock_ftd.index, y=stock_ftd["Adj Close"], line=dict(color="#fdc708", width=2), opacity=1, showlegend=False, ), secondary_y=True, ) fig.add_trace( go.Bar( name="FTDs", x=ftds_data["SETTLEMENT DATE"], y=ftds_data["QUANTITY (FAILS)"], yaxis="y2", opacity=ftd_opacity, ), secondary_y=False, ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_layout( margin=dict(l=0, r=20, t=30, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=f"{ticker} Failed-to-deliver", title_x=0.5, yaxis2_title="<b>Stock Price</b>", font=imps.PLT_FONT, yaxis2=dict( side="left", fixedrange=False, showgrid=False, layer="above traces", overlaying="y", titlefont=dict(color="#fdc708"), tickfont=dict( color="#fdc708", size=13, ), nticks=20, ), yaxis=dict( side="right", position=0.15, fixedrange=False, title_text="<b>Shares</b>", titlefont=dict(color="#d81aea"), tickfont=dict( color="#d81aea", size=13, ), nticks=20, ), xaxis=dict( rangeslider=dict(visible=False), type="date", fixedrange=False, ), xaxis2=dict( rangeslider=dict(visible=False), type="date", fixedrange=False, ), dragmode="pan", legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), hovermode="x unified", ) imagefile = "dps_ftd.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: [SEC] Failure-to-deliver {ticker}", "description": plt_link, "imagefile": imagefile, }
def rsi_command( ticker="", interval: int = 15, past_days: int = 0, length="14", scalar="100", drift="1", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with relative strength index [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta rsi %s %s %s %s %s %s", ticker, interval, past_days, length, scalar, drift, start, end, extended_hours, heikin_candles, news, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") length = int(length) if not scalar.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") scalar = float(scalar) if not drift.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") drift = int(drift) df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = df_ta.join(momentum_model.rsi(df_ta["Adj Close"], length, scalar, drift)) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.07, row_width=[0.5, 0.6], specs=[ [{"secondary_y": True}], [{"secondary_y": False}], ], ) title = f"<b>{plot['plt_title']} RSI</b>" fig = plot["fig"] fig.add_trace( go.Scatter( name=f"RSI {length}", mode="lines", x=df_ta.index, y=df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values, opacity=1, ), row=2, col=1, secondary_y=False, ) fig.add_hrect( y0=70, y1=100, fillcolor="red", opacity=0.2, layer="below", line_width=0, row=2, col=1, ) fig.add_hrect( y0=0, y1=30, fillcolor="green", opacity=0.2, layer="below", line_width=0, row=2, col=1, ) fig.add_hline( y=70, fillcolor="green", opacity=1, layer="below", line_width=3, line=dict(color="red", dash="dash"), row=2, col=1, ) fig.add_hline( y=30, fillcolor="green", opacity=1, layer="below", line_width=3, line=dict(color="green", dash="dash"), row=2, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.1, title_font_size=14, dragmode="pan", yaxis=dict(nticks=15), yaxis2=dict(nticks=10), ) imagefile = "ta_rsi.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Relative-Strength-Index {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def stoch_command( ticker: str = "", interval: int = 15, past_days: int = 0, fast_k="14", slow_d="3", slow_k="4", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with stochastic relative strength average [Yahoo Finance]""" # Debug if imps.DEBUG: logger.debug( "ta stoch %s %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, fast_k, slow_k, slow_d, start, end, extended_hours, heikin_candles, news, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") if not fast_k.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") fast_k = int(fast_k) if not slow_k.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") slow_k = int(slow_k) if not slow_d.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") slow_d = int(slow_d) # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] if df_ta.empty: raise Exception("No Data Found") df_ta = df_ta.join( momentum_model.stoch( df_stock["High"], df_stock["Low"], df_stock["Adj Close"], fast_k, slow_d, slow_k, )) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.07, row_width=[0.4, 0.6], specs=[[{ "secondary_y": True }], [{ "secondary_y": False }]], ) title = f"<b>{plot['plt_title']} STOCH RSI</b>" fig = plot["fig"] idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name=f"%K {fast_k}, {slow_d}, {slow_k}", x=df_ta.index, y=df_ta.iloc[:, idx].values, line=dict(width=1.8), mode="lines", opacity=1, ), row=2, col=1, ) fig.add_trace( go.Scatter( name=f"%D {fast_k}, {slow_d}, {slow_k}", x=df_ta.index, y=df_ta.iloc[:, (idx + 1)].values, line=dict(width=1.8, dash="dash"), opacity=1, ), row=2, col=1, ) fig.add_hrect( y0=80, y1=100, fillcolor="red", opacity=0.2, layer="below", line_width=0, row=2, col=1, ) fig.add_hrect( y0=0, y1=20, fillcolor="green", opacity=0.2, layer="below", line_width=0, row=2, col=1, ) fig.add_hline( y=80, fillcolor="green", opacity=1, layer="below", line_width=3, line=dict(color="red", dash="dash"), row=2, col=1, ) fig.add_hline( y=20, fillcolor="green", opacity=1, layer="below", line_width=3, line=dict(color="green", dash="dash"), row=2, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.01, title_font_size=14, dragmode="pan", ) imagefile = "ta_stoch.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Stochastic-Relative-Strength-Index {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def kc_command( ticker="", interval: int = 15, past_days: int = 0, length="20", scalar="2", ma_mode="sma", offset="0", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with keltner channel [Yahoo Finance]""" # Debug if imps.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "ta kc %s %s %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, length, scalar, ma_mode, offset, start, end, extended_hours, heikin_candles, news, ) # Check for argument if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") length = int(length) if not scalar.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") scalar = float(scalar) if not offset.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") offset = float(offset) # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] if df_ta.empty: raise Exception("No Data Found") ta_data = volatility_model.kc( df_stock["High"], df_stock["Low"], df_stock["Adj Close"], length, scalar, ma_mode, offset, ) df_ta = df_ta.join(ta_data) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, shared_xaxes=True, vertical_spacing=0.07, ) title = f"<b>{plot['plt_title']} Keltner Channels ({ma_mode.upper()})</b>" fig = plot["fig"] idx = 6 if interval != 1440 else 11 fig.add_trace( go.Scatter( name="upper", x=df_ta.index, y=df_ta.iloc[:, (idx + 2)].values, opacity=1, mode="lines", line_color="indigo", showlegend=False, ), row=1, col=1, secondary_y=True, ) fig.add_trace( go.Scatter( name="lower", x=df_ta.index, y=df_ta.iloc[:, idx].values, opacity=1, mode="lines", line_color="indigo", fill="tonexty", fillcolor="rgba(74, 0, 128, 0.2)", showlegend=False, ), row=1, col=1, secondary_y=True, ) fig.add_trace( go.Scatter( name="mid", x=df_ta.index, y=df_ta.iloc[:, (idx + 1)].values, opacity=1, line=dict( width=1.5, dash="dash", ), showlegend=False, ), row=1, col=1, secondary_y=True, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.02, title_font_size=14, dragmode="pan", ) imagefile = "ta_kc.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Keltner-Channel {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }
def cps_command( country: str, mktcap: str = "", exclude_exchanges: bool = True, raw: bool = False, max_sectors_to_display: int = 15, min_pct_to_display_sector: float = 0.015, ): """Display number of companies per sector in a specific country (and market cap). [Source: Finance Database] Parameters ---------- country: str Select country to get number of companies by each sector mktcap: str Select market cap of companies to consider from Small, Mid and Large exclude_exchanges : bool Exclude international exchanges raw: bool Output all raw data max_sectors_to_display: int Maximum number of sectors to display min_pct_to_display_sector: float Minimum percentage to display sector external_axes : Optional[List[plt.Axes]], optional External axes (1 axis is expected in the list), by default None """ companies_per_sector = financedatabase_model.get_companies_per_sector_in_country( country, mktcap, exclude_exchanges ) companies_per_sector = dict( OrderedDict( sorted(companies_per_sector.items(), key=lambda t: t[1], reverse=True) ) ) for key, value in companies_per_sector.copy().items(): if value == 0: del companies_per_sector[key] if not companies_per_sector: raise Exception("No companies found with these parameters!\n") df = pd.DataFrame.from_dict(companies_per_sector, orient="index") df.index.name = "Sector" df.columns = ["Number of companies"] df["Number of companies"] = df["Number of companies"].astype(int) title = mktcap + " Cap Companies " if mktcap else "Companies " title += f"in {country}" title += " Excl. Exchanges" if exclude_exchanges else " incl. Exchanges" title = textwrap.fill(title, 40) title_plot = textwrap.indent(text=title, prefix="<br>") if raw: output = { "title": "Stocks - Sector and Industry Analysis", "description": f"{df}", } else: if len(companies_per_sector) > 1: total_num_companies = sum(companies_per_sector.values()) min_companies_to_represent = round( min_pct_to_display_sector * total_num_companies ) filter_sectors_to_display = ( np.array(list(companies_per_sector.values())) > min_companies_to_represent ) if any(filter_sectors_to_display): if not all(filter_sectors_to_display): num_sectors_to_display = np.where(~filter_sectors_to_display)[0][0] if num_sectors_to_display < max_sectors_to_display: max_sectors_to_display = num_sectors_to_display else: raise Exception( "The minimum threshold percentage specified is too high, thus it will be ignored." ) if len(companies_per_sector) > max_sectors_to_display: companies_per_sector_sliced = dict( list(companies_per_sector.items())[: max_sectors_to_display - 1] ) companies_per_sector_sliced["Others"] = sum( dict( list(companies_per_sector.items())[max_sectors_to_display - 1 :] ).values() ) legend, values = zip(*companies_per_sector_sliced.items()) else: legend, values = zip(*companies_per_sector.items()) fig = go.Figure() colors = [ "#ffed00", "#ef7d00", "#e4003a", "#c13246", "#822661", "#48277c", "#005ca9", "#00aaff", "#9b30d9", "#af005f", "#5f00af", "#af87ff", ] fig.add_trace( go.Pie( labels=legend, values=values, textinfo="label+percent", showlegend=False, ) ) fig.update_traces( textposition="outside", textfont_size=15, marker=dict( colors=colors, line=dict(color="#F5EFF3", width=0.8), ), ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_layout( margin=dict(l=40, r=0, t=80, b=40), title=dict( text=title_plot, y=1, x=0.5, xanchor="center", yanchor="top", ), template=imps.PLT_CANDLE_STYLE_TEMPLATE, colorway=colors, font=imps.PLT_FONT, ) elif len(companies_per_sector) == 1: raise Exception( f"Only 1 sector found '{list(companies_per_sector.keys())[0]}'. No pie chart will be depicted." ) else: raise Exception("No sector found. No pie chart will be depicted.") imagefile = "sia_cps.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) output = { "title": "Stocks - Sector and Industry Analysis", "description": plt_link, "imagefile": imagefile, } return output
def dpotc_command(ticker: str = ""): """Dark pools (ATS) vs OTC data [FINRA]""" # Debug user input if imps.DEBUG: logger.debug("dps dpotc %s", ticker) # Check for argument if ticker == "": raise Exception("Stock ticker is required") ticker = ticker.upper() stock = yf.download(ticker, progress=False) if stock.empty: raise Exception("Stock ticker is invalid") # Retrieve data ats, otc = finra_model.getTickerFINRAdata(ticker) # Debug user output if imps.DEBUG: logger.debug(ats.to_string()) logger.debug(otc.to_string()) # Output data title = f"Stocks: [FINRA] Dark Pools (ATS) vs OTC {ticker}" if ats.empty and otc.empty: raise Exception("Stock ticker is invalid") fig = make_subplots( rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.07, row_width=[0.4, 0.6], specs=[[{ "secondary_y": True }], [{ "secondary_y": False }]], ) if not ats.empty and not otc.empty: fig.add_trace( go.Bar( x=ats.index, y=(ats["totalWeeklyShareQuantity"] + otc["totalWeeklyShareQuantity"]), name="ATS", opacity=0.8, ), row=1, col=1, secondary_y=False, ) fig.add_trace( go.Bar( x=otc.index, y=otc["totalWeeklyShareQuantity"], name="OTC", opacity=0.8, yaxis="y2", offset=0.0001, ), row=1, col=1, ) elif not ats.empty: fig.add_trace( go.Bar( x=ats.index, y=(ats["totalWeeklyShareQuantity"] + otc["totalWeeklyShareQuantity"]), name="ATS", opacity=0.8, ), row=1, col=1, secondary_y=False, ) elif not otc.empty: fig.add_trace( go.Bar( x=otc.index, y=otc["totalWeeklyShareQuantity"], name="OTC", opacity=0.8, yaxis="y2", secondary_y=False, ), row=1, col=1, ) if not ats.empty: fig.add_trace( go.Scatter( name="ATS", x=ats.index, y=ats["totalWeeklyShareQuantity"] / ats["totalWeeklyTradeCount"], line=dict(color="#fdc708", width=2), opacity=1, showlegend=False, yaxis="y2", ), row=2, col=1, ) if not otc.empty: fig.add_trace( go.Scatter( name="OTC", x=otc.index, y=otc["totalWeeklyShareQuantity"] / otc["totalWeeklyTradeCount"], line=dict(color="#d81aea", width=2), opacity=1, showlegend=False, ), row=2, col=1, ) else: fig.add_trace( go.Scatter( name="OTC", x=otc.index, y=otc["totalWeeklyShareQuantity"] / otc["totalWeeklyTradeCount"], line=dict(color="#d81aea", width=2), opacity=1, showlegend=False, ), row=2, col=1, ) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_layout( margin=dict(l=20, r=0, t=10, b=20), template=imps.PLT_CANDLE_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=f"Dark Pools (ATS) vs OTC (Non-ATS) Data for {ticker}", title_x=0.5, yaxis3_title="Shares per Trade", yaxis_title="Total Weekly Shares", xaxis2_title="Weeks", font=imps.PLT_FONT, yaxis=dict( fixedrange=False, side="left", nticks=20, ), yaxis2=dict( fixedrange=False, showgrid=False, overlaying="y", anchor="x", layer="above traces", ), yaxis3=dict( fixedrange=False, nticks=10, ), xaxis=dict( rangeslider=dict(visible=False), type="date", showspikes=True, nticks=20, ), legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), barmode="group", bargap=0.5, bargroupgap=0, dragmode="pan", hovermode="x unified", spikedistance=1, hoverdistance=1, ) imagefile = "dps_dpotc.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": title, "description": plt_link, "imagefile": imagefile, }
def options_run( ticker, url, expiry, dates, df_bcinfo, calls, puts, df_opt, current_price, min_strike, max_strike, min_strike2, max_strike2, max_pain, ): """Options Overview""" titles, reports, embeds, embeds_img, choices, images_list = [], [], [], [], [], [] 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="#00ACFF", width=3), )) fig.add_trace( go.Scatter( x=df_opt.index, y=df_opt["OI_put"], name="Puts", mode="lines+markers", line=dict(color="#e4003a", 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}", )) if imps.PLT_WATERMARK: fig.add_layout_image(imps.PLT_WATERMARK) fig.update_xaxes( range=[min_strike, max_strike], constrain="domain", ) fig.update_layout( margin=dict(l=0, r=0, t=60, b=20), template=imps.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), ), font=imps.PLT_FONT, legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), dragmode="pan", ) imagefile = "opt-oi.png" plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) reports.append(plt_link) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: image_link_oi = imps.multi_image(imagefile) images_list.append(imagefile) else: image_link_oi = imps.multi_image(imagefile) calls_df = calls[columns].rename(columns=column_map) calls_df = calls_df[calls_df["strike"] >= min_strike2] calls_df = calls_df[calls_df["strike"] <= max_strike2] calls_df["iv"] = pd.to_numeric(calls_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)) calls_df = calls_df.fillna("") calls_df.set_index("strike", inplace=True) if "^" not in ticker: if "-" in df_bcinfo.iloc[0, 1]: iv = f"```diff\n- {df_bcinfo.iloc[0, 1]}\n```" else: iv = f"```yaml\n {df_bcinfo.iloc[0, 1]}\n```" pfix, sfix = f"{ticker.upper()} ", f" expiring {expiry}" if expiry == dates[0]: pfix = f"{ticker.upper()} Weekly " sfix = "" titles.append(f"{ticker.upper()} Overview", ) titles.append(f"{pfix}Open Interest{sfix}", ) embeds.append( disnake.Embed( title=f"{ticker.upper()} Overview", color=imps.COLOR, ), ) embeds.append( disnake.Embed( title=f"{pfix}Open Interest{sfix}", description=plt_link, colour=imps.COLOR, ), ) choices.append( disnake.SelectOption(label=f"{ticker.upper()} Overview", value="0", emoji="🟢"), ) choices.append( disnake.SelectOption(label=f"{pfix}Open Interest{sfix}", value="1", emoji="🟢"), ) 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 = imps.plot_df( df_calls, fig_size=(1000, (40 + (40 * 20))), col_width=[3, 3, 3, 3], tbl_header=imps.PLT_TBL_HEADER, tbl_cells=imps.PLT_TBL_CELLS, font=imps.PLT_TBL_FONT, row_fill_color=imps.PLT_TBL_ROW_COLORS, paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = "opt-calls.png" imagefile = imps.save_image(imagefile, figc) if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: image_link = imps.multi_image(imagefile) embeds_img.append(f"{image_link}", ) titles.append(f"{pfix}Calls{sfix}", ) embeds.append( disnake.Embed( title=f"{pfix}Calls{sfix}", colour=imps.COLOR, ), ) i2 += 1 i += 20 end += 20 # 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_df = puts[columns].rename(columns=column_map) puts_df = puts_df[puts_df["strike"] >= min_strike2] puts_df = puts_df[puts_df["strike"] <= max_strike2] puts_df["iv"] = pd.to_numeric(puts_df["iv"].astype(float)) formats = {"iv": "{:.2f}"} for col, f in formats.items(): puts_df[col] = puts_df[col].map(lambda x: f.format(x)) # pylint: disable=W0640 puts_df = puts_df.fillna("") puts_df.set_index("strike", inplace=True) pfix, sfix = f"{ticker.upper()} ", f" expiring {expiry}" if expiry == dates[0]: pfix = f"{ticker.upper()} Weekly " sfix = "" # 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 = imps.plot_df( df_puts, fig_size=(1000, (40 + (40 * 20))), col_width=[3, 3, 3, 3], tbl_header=imps.PLT_TBL_HEADER, tbl_cells=imps.PLT_TBL_CELLS, font=imps.PLT_TBL_FONT, row_fill_color=imps.PLT_TBL_ROW_COLORS, paper_bgcolor="rgba(0, 0, 0, 0)", ) imagefile = "opt-puts.png" imagefile = imps.save_image(imagefile, figp) if imps.IMAGES_URL or not imps.IMG_HOST_ACTIVE: image_link = imps.multi_image(imagefile) images_list.append(imagefile) else: image_link = imps.multi_image(imagefile) embeds_img.append(f"{image_link}", ) titles.append(f"{pfix}Puts{sfix}", ) embeds.append( disnake.Embed( title=f"{pfix}Puts{sfix}", colour=imps.COLOR, ), ) i2 += 1 i += 20 end += 20 # 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=imps.AUTHOR_NAME, url=imps.AUTHOR_URL, icon_url=imps.AUTHOR_ICON_URL, ) embeds[i].set_footer( text=imps.AUTHOR_NAME, icon_url=imps.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=imps.AUTHOR_ICON_URL) # Overview Section if "^" not in ticker: reports.append( f"{'':^5}*{df_bcinfo.iloc[0, 0]:^25}*{'':^5}*{df_bcinfo.iloc[1, 0]:^25}*{'':^5}\n" ) reports.append( f"{'':^8}{df_bcinfo.iloc[0, 1]:^25}{'':^5}{df_bcinfo.iloc[1, 1]:^25}\n" ) i, i2 = 2, 3 while i < 11: text = ( f"{'':^5}*{df_bcinfo.iloc[i, 0]:^25}*{'':^5}*{df_bcinfo.iloc[i2, 0]:^25}*{'':^5}\n" f"{'':^5}{df_bcinfo.iloc[i, 1]:^30}{'':^5}{df_bcinfo.iloc[i2, 1]:^25}{'':^10}\n" ) reports.append(text) i += 1 i2 += 1 embeds[0].add_field(name=f"{df_bcinfo.iloc[0, 0]}", value=iv, inline=False) embeds[0].add_field( name=f"•{df_bcinfo.iloc[1, 0]}", value=f"```css\n{df_bcinfo.iloc[1, 1]}\n```", inline=True, ) for N in range(2, 6): embeds[0].add_field( name=f"_ _ _ _ _ _ _ _ _ _ •{df_bcinfo.iloc[N, 0]}", value=f"```css\n{df_bcinfo.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_bcinfo.iloc[N, 0]}", value=f"```css\n{df_bcinfo.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_bcinfo.iloc[N, 0]}", value=f"```css\n{df_bcinfo.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_bcinfo.iloc[N, 0]}", value=f"```css\n{df_bcinfo.iloc[N, 1]}\n```", inline=True, ) embeds[0].set_footer(text=f"Page 1 of {len(embeds)}") return titles, reports, embeds, choices, embeds_img, images_list
def cci_command( ticker: str = "", interval: int = 15, past_days: int = 0, length="14", scalar="0.015", start="", end="", extended_hours: bool = False, heikin_candles: bool = False, news: bool = False, ): """Displays chart with commodity channel index [Yahoo Finance]""" # Debug if imps.DEBUG: logger.debug( "ta cci %s %s %s %s %s %s %s %s %s %s", ticker, interval, past_days, length, scalar, start, end, extended_hours, heikin_candles, news, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") # Retrieve Data df_stock, start, end, bar_start = load_candle.stock_data( ticker=ticker, interval=interval, past_days=past_days, extended_hours=extended_hours, start=start, end=end, heikin_candles=heikin_candles, ) if df_stock.empty: raise Exception("No Data Found") # pylint try: length = int(length) except ValueError as e: raise Exception("Length has to be an integer") from e try: scalar = float(scalar) except ValueError as e: raise Exception("Scalar has to be an integer") from e df_ta = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] if df_ta.empty: raise Exception("No Data Found") ta_data = momentum_model.cci( df_ta["High"], df_ta["Low"], df_ta["Adj Close"], length, scalar ) df_ta = df_ta.join(ta_data) # Output Data if interval != 1440: df_ta = df_ta.loc[(df_ta.index >= bar_start) & (df_ta.index < end)] df_ta = df_ta.fillna(0.0) plot = load_candle.candle_fig( df_ta, ticker, interval, extended_hours, news, bar=bar_start, int_bar=interval, rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.07, row_width=[0.4, 0.6], specs=[[{"secondary_y": True}], [{"secondary_y": False}]], ) title = f"<b>{plot['plt_title']} Commodity-Channel-Index</b>" fig = plot["fig"] ta_values = ( df_ta.iloc[:, 6].values if interval != 1440 else df_ta.iloc[:, 11].values ) dmin = ta_values.min() dmax = ta_values.max() fig.add_trace( go.Scatter( name=f"CCI ({length}) ({scalar})", mode="lines", x=df_ta.index, y=ta_values, opacity=1, ), row=2, col=1, ) fig.add_hrect( y0=100, y1=dmax, fillcolor="red", opacity=0.2, layer="below", line_width=0, row=2, col=1, ) fig.add_hrect( y0=-100, y1=dmin, fillcolor="green", opacity=0.2, layer="below", line_width=0, row=2, col=1, ) fig.add_hline( y=-100, fillcolor="green", opacity=1, layer="below", line_width=3, line=dict(color="green", dash="dash"), row=2, col=1, ) fig.add_hline( y=100, fillcolor="red", opacity=1, layer="below", line_width=3, line=dict(color="red", dash="dash"), row=2, col=1, ) fig.update_layout( margin=dict(l=0, r=0, t=50, b=20), template=imps.PLT_TA_STYLE_TEMPLATE, colorway=imps.PLT_TA_COLORWAY, title=title, title_x=0.02, title_font_size=14, dragmode="pan", ) imagefile = "ta_cci.png" # Check if interactive settings are enabled plt_link = "" if imps.INTERACTIVE: plt_link = imps.inter_chart(fig, imagefile, callback=False) fig.update_layout( width=800, height=500, ) imagefile = imps.image_border(imagefile, fig=fig) return { "title": f"Stocks: Commodity-Channel-Index {ticker.upper()}", "description": plt_link, "imagefile": imagefile, }