from datetime import datetime, timedelta import plotly.graph_objects as go import yfinance as yf from plotly.subplots import make_subplots import bots.config_discordbot as cfg from bots.config_discordbot import logger from bots import helpers from gamestonk_terminal.common.technical_analysis import overlap_model def candle_command( ticker: str = "", interval: int = 15, past_days: int = 1, start="", end="", ): """Shows candle plot of loaded ticker. [Source: Yahoo Finance, IEX Cloud or Alpha Vantage] Parameters ---------- ticker: str Ticker name interval: int chart mins or daily past_days: int Display the past * days. Default: 1(Not for Daily) start: str start date format YYYY-MM-DD end: str end date format YYYY-MM-DD """ logger.info("candle %s %s %s %s", ticker, interval, start, end) if start == "": start = datetime.now() - timedelta(days=365) else: start = datetime.strptime(start, cfg.DATE_FORMAT) if end == "": end = datetime.now() else: end = datetime.strptime(end, cfg.DATE_FORMAT) futures = "=F" or "^" crypto = "-USD" if interval == 1440: df_stock_candidate = yf.download( ticker, start=start, end=end, progress=False, ) # Check that loading a stock was not successful if df_stock_candidate.empty: raise Exception(f"No data found for {ticker.upper()}") df_stock_candidate.index.name = "date" else: s_int = str(interval) + "m" d_granularity = { "1m": past_days, "5m": past_days, "15m": past_days, "30m": past_days, "60m": past_days, } s_start_dt = datetime.utcnow() - timedelta(days=d_granularity[s_int]) s_date_start = s_start_dt.strftime("%Y-%m-%d") df_stock_candidate = yf.download( ticker, start=s_date_start if s_start_dt > start else start.strftime("%Y-%m-%d"), progress=False, interval=s_int, prepost=True, ) # Check that loading a stock was not successful if df_stock_candidate.empty: raise Exception(f"No data found for {ticker.upper()}.") df_stock_candidate.index = df_stock_candidate.index.tz_localize(None) df_stock_candidate.index.name = "date" df_stock = df_stock_candidate price_df = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_vwap = overlap_model.vwap(price_df, 0) plt_title = [f"{ticker.upper()} Intraday {interval}min", "Volume"] title = f"Intraday {interval}min Chart for {ticker.upper()}" if interval == 1440: plt_title = [f"{ticker.upper()} Daily", "Volume"] title = f"Daily Chart for {ticker.upper()}" fig = make_subplots( shared_xaxes=True, vertical_spacing=0.09, subplot_titles=plt_title, specs=[[{"secondary_y": True}]], ) fig.add_trace( go.Candlestick( x=df_stock.index, open=df_stock.Open, high=df_stock.High, low=df_stock.Low, close=df_stock.Close, name="OHLC", showlegend=False, ), secondary_y=True, ) fig.add_trace( go.Bar( x=df_stock.index, y=df_stock.Volume, name="Volume", yaxis="y2", marker_color="#d81aea", opacity=0.4, showlegend=False, ), secondary_y=False, ) if interval != 1440: fig.add_trace( go.Scatter( name="VWAP", x=df_stock.index, y=df_vwap["VWAP_D"], opacity=0.65, line=dict(color="#fdc708", width=2), showlegend=True, ), secondary_y=True, ) fig.update_xaxes(showspikes=True, spikesnap="cursor", spikemode="across") fig.update_yaxes(showspikes=True, spikethickness=2) fig.update_layout( margin=dict(l=0, r=0, t=40, b=20), template=cfg.PLT_CANDLE_STYLE_TEMPLATE, yaxis2_title="Price ($)", yaxis_title="Volume", yaxis=dict( showgrid=False, fixedrange=False, side="left", titlefont=dict(color="#d81aea"), tickfont=dict(color="#d81aea"), nticks=20, ), yaxis2=dict( side="right", fixedrange=False, anchor="x", layer="above traces", overlaying="y", nticks=20, ), xaxis=dict( rangeslider=dict(visible=False), type="date", showspikes=True, ), legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), dragmode="pan", hovermode="x unified", spikedistance=1000, hoverdistance=100, ) if futures in ticker.upper(): fig.update_xaxes( rangebreaks=[ dict(bounds=["sat", "sun"]), dict(bounds=[17, 17.50], pattern="hour"), ], ) elif crypto not in ticker.upper() and interval != 1440: fig.update_xaxes( rangebreaks=[ dict(bounds=["sat", "mon"]), dict(bounds=[20, 9.50], pattern="hour"), ], ) config = dict({"scrollZoom": True}) imagefile = "candle.png" # Check if interactive settings are enabled plt_link = "" if cfg.INTERACTIVE: html_ran = helpers.uuid_get() fig.write_html(f"in/candle_{html_ran}.html", config=config) plt_link = f"[Interactive]({cfg.INTERACTIVE_URL}/candle_{html_ran}.html)" fig.update_layout( width=800, height=500, ) imagefile = helpers.image_border(imagefile, fig=fig) return { "title": title, "description": plt_link, "imagefile": imagefile, }