async def view_command(ctx, ticker=""): """Displays image from Finviz [Finviz]""" try: # Debug if cfg.DEBUG: print(f"!stocks.ta.view {ticker}") # Check for argument if ticker == "": raise Exception("Stock ticker is required") image_data = finviz_model.get_finviz_image(ticker) dataBytesIO = io.BytesIO(image_data) im = Image.open(dataBytesIO) fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.set_axis_off() fig.subplots_adjust(left=0, right=1, top=1, bottom=0) plt.imshow(im) plt.savefig("ta_view.png") uploaded_image = gst_imgur.upload_image("ta_view.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: [Finviz] Trendlines & Data " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_view.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: [Finviz] Trendlines & Data", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def cci_command(ctx, ticker="", length="14", scalar="0.015", start="", end=""): """Displays chart with commodity channel index [Yahoo Finance]""" try: # Debug if cfg.DEBUG: logger.debug( "!stocks.ta.cci %s %s %s %s %s", ticker, length, scalar, start, end, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) # 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 ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = momentum_model.cci(df_stock["High"], df_stock["Low"], df_stock["Adj Close"], length, scalar) fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax = axes[0] ax.set_title(f"{ticker} CCI") ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2) ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Share Price ($)") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax2 = axes[1] ax2.plot(df_ta.index, df_ta.values, "b", lw=2) ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.axhspan(100, plt.gca().get_ylim()[1], facecolor="r", alpha=0.2) ax2.axhspan(plt.gca().get_ylim()[0], -100, facecolor="g", alpha=0.2) ax2.axhline(100, linewidth=3, color="r", ls="--") ax2.axhline(-100, linewidth=3, color="g", ls="--") ax2.grid(b=True, which="major", color="#666666", linestyle="-") ax3 = ax2.twinx() ax3.set_ylim(ax2.get_ylim()) ax3.set_yticks([-100, 100]) ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"]) plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_cci.png") uploaded_image = gst_imgur.upload_image("ta_cci.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Commodity-Channel-Index " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_cci.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Commodity-Channel-Index", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def adx_command(ctx, ticker="", length="14", scalar="100", drift="1", start="", end=""): """Displays chart with average directional movement index [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print( f"!stocks.ta.adx {ticker} {length} {scalar} {drift} {start} {end}" ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) 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) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = trend_indicators_model.adx("1440min", df_stock, length, scalar, drift) # Output Data fig, ax = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax0 = ax[0] ax0.plot(df_stock.index, df_stock["Close"].values, "k", lw=2) ax0.set_title(f"Average Directional Movement Index (ADX) on {ticker}") ax0.set_xlim(df_stock.index[0], df_stock.index[-1]) ax0.set_ylabel("Share Price ($)") ax0.grid(b=True, which="major", color="#666666", linestyle="-") ax1 = ax[1] ax1.plot(df_ta.index, df_ta.iloc[:, 0].values, "b", lw=2) ax1.plot(df_ta.index, df_ta.iloc[:, 1].values, "g", lw=1) ax1.plot(df_ta.index, df_ta.iloc[:, 2].values, "r", lw=1) ax1.set_xlim(df_stock.index[0], df_stock.index[-1]) ax1.axhline(25, linewidth=3, color="k", ls="--") ax1.legend( [ f"ADX ({df_ta.columns[0]})", f"+DI ({df_ta.columns[1]})", f"- DI ({df_ta.columns[2]})", ], loc="upper left", ) ax1.set_xlabel("Time") ax1.grid(b=True, which="major", color="#666666", linestyle="-") ax1.set_ylim([0, 100]) fig.tight_layout() plt.gcf().autofmt_xdate() plt.savefig("ta_adx.png") uploaded_image = gst_imgur.upload_image("ta_adx.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Average-Directional-Movement-Index " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_adx.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Average-Directional-Movement-Index", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def historical_command(ctx, signal="", start=""): """Displays historical price comparison between similar companies [Yahoo Finance]""" try: # Debug user input if cfg.DEBUG: logger.debug("!stocks.scr.historical %s %s", signal, start) # Check for argument if signal == "" or signal not in list(so.d_signals_desc.keys): raise Exception("Invalid preset selected!") register_matplotlib_converters() screen = ticker.Ticker() if signal in finviz_model.d_signals: screen.set_filter(signal=finviz_model.d_signals[signal]) else: preset_filter = configparser.RawConfigParser() preset_filter.optionxform = str # type: ignore preset_filter.read(so.presets_path + signal + ".ini") d_general = preset_filter["General"] d_filters = { **preset_filter["Descriptive"], **preset_filter["Fundamental"], **preset_filter["Technical"], } d_filters = {k: v for k, v in d_filters.items() if v} if d_general["Signal"]: screen.set_filter(filters_dict=d_filters, signal=d_general["Signal"]) else: screen.set_filter(filters_dict=d_filters) if start == "": start = datetime.now() - timedelta(days=365) else: start = datetime.strptime(start, cfg.DATE_FORMAT) # Output Data l_min = [] l_leg = [] l_stocks = screen.ScreenerView(verbose=0) if len(l_stocks) > 10: description = ( "\nThe limit of stocks to compare with are 10. Hence, 10 random similar stocks will be displayed." "\nThe selected list will be: ") random.shuffle(l_stocks) l_stocks = sorted(l_stocks[:10]) description = description + (", ".join(l_stocks)) logger.debug(description) plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) while l_stocks: l_parsed_stocks = [] for symbol in l_stocks: try: df_similar_stock = yf.download( symbol, start=datetime.strftime(start, "%Y-%m-%d"), progress=False, threads=False, ) if not df_similar_stock.empty: plt.plot( df_similar_stock.index, df_similar_stock["Adj Close"].values, ) l_min.append(df_similar_stock.index[0]) l_leg.append(symbol) l_parsed_stocks.append(symbol) except Exception as e: error = ( f"{e}\nDisregard previous error, which is due to API Rate limits from Yahoo Finance. " f"Because we like '{symbol}', and we won't leave without getting data from it." ) embed = discord.Embed( title= "ERROR Stocks: [Yahoo Finance] Historical Screener", colour=cfg.COLOR, description=error, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed) for parsed_stock in l_parsed_stocks: l_stocks.remove(parsed_stock) if signal: plt.title( f"Screener Historical Price using {finviz_model.d_signals[signal]} signal" ) else: plt.title(f"Screener Historical Price using {signal} preset") plt.xlabel("Time") plt.ylabel("Share Price ($)") plt.legend(l_leg) plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) # ensures that the historical data starts from same datapoint plt.xlim([max(l_min), df_similar_stock.index[-1]]) plt.savefig("scr_historical.png") uploaded_image = gst_imgur.upload_image("scr_historical.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: [Yahoo Finance] Historical Screener" embed = discord.Embed(title=title, description=description, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("scr_historical.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: [Yahoo Finance] Historical Screener", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def qtrcontracts_command(ctx, num="", analysis=""): """Displays a look at government contracts [quiverquant.com]""" try: # Debug user input if cfg.DEBUG: print(f"!stocks.gov.qtrcontracts {num} {analysis}") if num == "": num = 20 else: if not num.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") num = int(num) possible_args = ["total", "upmom", "downmom"] if analysis == "": analysis = "total" elif analysis not in possible_args: raise Exception( "Enter a valid analysis argument, options are: total, upmom and downmom" ) # Retrieve Data df_contracts = quiverquant_model.get_government_trading( "quarter-contracts") if df_contracts.empty: raise Exception("No quarterly government contracts found") tickers = quiverquant_model.analyze_qtr_contracts(analysis, num) # Output Data if analysis in {"upmom", "downmom"}: description = tickers.to_string() fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) max_amount = 0 quarter_ticks = [] for symbol in tickers: amounts = ( df_contracts[df_contracts["Ticker"] == symbol].sort_values( by=["Year", "Qtr"])["Amount"].values) qtr = ( df_contracts[df_contracts["Ticker"] == symbol].sort_values( by=["Year", "Qtr"])["Qtr"].values) year = ( df_contracts[df_contracts["Ticker"] == symbol].sort_values( by=["Year", "Qtr"])["Year"].values) ax.plot(np.arange(0, len(amounts)), amounts / 1_000_000, "-*", lw=2, ms=15) if len(amounts) > max_amount: max_amount = len(amounts) quarter_ticks = [ f"{quarter[0]} - Q{quarter[1]} " for quarter in zip(year, qtr) ] ax.set_xlim([-0.5, max_amount - 0.5]) ax.set_xticks(np.arange(0, max_amount)) ax.set_xticklabels(quarter_ticks) ax.grid() ax.legend(tickers) titles = { "upmom": "Highest increasing quarterly Government Contracts", "downmom": "Highest decreasing quarterly Government Contracts", } ax.set_title(titles[analysis]) ax.set_xlabel("Date") ax.set_ylabel("Amount ($1M)") fig.tight_layout() plt.savefig("gov_qtrcontracts.png") uploaded_image = gst_imgur.upload_image("gov_qtrcontracts.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: [quiverquant.com] Government contracts" embed = discord.Embed(title=title, description=description, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("gov_qtrcontracts.png") await ctx.send(embed=embed) elif analysis == "total": tickers.index = [ ind + " " * (7 - len(ind)) for ind in tickers.index ] tickers[:] = [ str(round(val[0] / 1e9, 2)) for val in tickers.values ] tickers.columns = ["Amount [M]"] tickers_str = tabulate( tickers, headers=tickers.columns, showindex=True, numalign="right", stralign="center", ) embed = discord.Embed( title="Stocks: [quiverquant.com] Government contracts", description=tickers_str, colour=cfg.COLOR, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: [quiverquant.com] Government contracts", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def obv_command(ctx, ticker="", start="", end=""): """Displays chart with on balance volume [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print(f"!stocks.ta.obv {ticker} {start} {end}") # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] # Output Data bar_colors = [ "r" if x[1].Open < x[1].Close else "g" for x in df_stock.iterrows() ] bar_width = timedelta(days=1) divisor = 1_000_000 df_vol = df_stock["Volume"].dropna() df_vol = df_vol.values / divisor df_ta = volume_model.obv("1440min", df_stock) df_cal = df_ta.values df_cal = df_cal / divisor fig, axes = plt.subplots( 3, 1, gridspec_kw={"height_ratios": [2, 1, 1]}, figsize=plot_autoscale(), dpi=PLOT_DPI, ) ax = axes[0] ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2) ax.set_title(f"{ticker} OBV") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Price") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax.minorticks_on() ax.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) ax2 = axes[1] ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.set_ylabel("Volume [M]") ax2.bar( df_stock.index, df_vol, color=bar_colors, alpha=0.8, width=bar_width, ) ax3 = axes[2] ax3.set_ylabel("OBV [M]") ax3.set_xlabel("Time") ax3.plot(df_ta.index, df_cal, "b", lw=1) ax3.set_xlim(df_stock.index[0], df_stock.index[-1]) ax3.grid(b=True, which="major", color="#666666", linestyle="-") ax3.minorticks_on() ax3.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_obv.png") uploaded_image = gst_imgur.upload_image("ta_obv.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: On-Balance-Volume " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_obv.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: On-Balance-Volume", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def stoch_command(ctx, ticker="", fast_k="14", slow_d="3", slow_k="3", start="", end=""): """Displays chart with stochastic relative strength average [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print( f"!stocks.ta.stoch {ticker} {fast_k} {slow_k} {slow_d} {start} {end}" ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) if not fast_k.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") fast_k = float(fast_k) if not slow_k.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") slow_k = float(slow_k) if not slow_d.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") slow_d = float(slow_d) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = momentum_model.stoch("1440min", df_stock, fast_k, slow_d, slow_k) # Output Data fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax = axes[0] ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2) ax.set_title( f"Stochastic Relative Strength Index (STOCH RSI) on {ticker}") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_xticklabels([]) ax.set_ylabel("Share Price ($)") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax2 = axes[1] ax2.plot(df_ta.index, df_ta.iloc[:, 0].values, "k", lw=2) ax2.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=2, ls="--") ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.axhspan(80, 100, facecolor="r", alpha=0.2) ax2.axhspan(0, 20, facecolor="g", alpha=0.2) ax2.axhline(80, linewidth=3, color="r", ls="--") ax2.axhline(20, linewidth=3, color="g", ls="--") ax2.grid(b=True, which="major", color="#666666", linestyle="-") ax2.set_ylim([0, 100]) ax3 = ax2.twinx() ax3.set_ylim(ax2.get_ylim()) ax3.set_yticks([20, 80]) ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"]) ax2.legend([f"%K {df_ta.columns[0]}", f"%D {df_ta.columns[1]}"], loc="lower left") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_stoch.png") uploaded_image = gst_imgur.upload_image("ta_stoch.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Stochastic-Relative-Strength-Index " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_stoch.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Stochastic-Relative-Strength-Index", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def fisher_command(ctx, ticker="", length="14", start="", end=""): """Displays chart with fisher transformation [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print(f"!stocks.ta.fisher {ticker} {length} {start} {end}") # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") length = float(length) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = momentum_model.fisher("1440min", df_stock, length) # Output Data fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax = axes[0] ax.set_title(f"{ticker} Fisher Transform") ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=1) ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Price") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax2 = axes[1] ax2.plot( df_ta.index, df_ta.iloc[:, 0].values, "b", lw=2, label="Fisher", ) ax2.plot( df_ta.index, df_ta.iloc[:, 1].values, "fuchsia", lw=2, label="Signal", ) ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.axhspan(2, plt.gca().get_ylim()[1], facecolor="r", alpha=0.2) ax2.axhspan(plt.gca().get_ylim()[0], -2, facecolor="g", alpha=0.2) ax2.axhline(2, linewidth=3, color="r", ls="--") ax2.axhline(-2, linewidth=3, color="g", ls="--") ax2.grid(b=True, which="major", color="#666666", linestyle="-") ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.axhspan(2, plt.gca().get_ylim()[1], facecolor="r", alpha=0.2) ax2.axhspan(plt.gca().get_ylim()[0], -2, facecolor="g", alpha=0.2) ax2.axhline(2, linewidth=3, color="r", ls="--") ax2.axhline(-2, linewidth=3, color="g", ls="--") ax2.grid(b=True, which="major", color="#666666", linestyle="-") ax2.set_yticks([-2, 0, 2]) ax2.set_yticklabels(["-2 STDEV", "0", "+2 STDEV"]) plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.legend() plt.savefig("ta_fisher.png") uploaded_image = gst_imgur.upload_image("ta_fisher.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Fisher-Transform " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_fisher.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Fisher-Transform", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def aroon_command(ctx, ticker="", length="25", scalar="100", start="", end=""): """Displays chart with aroon indicator [Yahoo Finance]""" try: # Debug if cfg.DEBUG: logger.debug( "!stocks.ta.aroon %s %s %s %s %s", ticker, length, scalar, start, end, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) 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) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = trend_indicators_model.aroon(df_stock["High"], df_stock["Low"], length, scalar) fig, ax = plt.subplots(3, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax0 = ax[0] ax0.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2) ax0.set_title(f"Aroon on {ticker}") ax0.set_xlim(df_stock.index[0], df_stock.index[-1]) ax0.set_ylabel("Share Price ($)") ax0.grid(b=True, which="major", color="#666666", linestyle="-") ax1 = ax[1] ax1.plot(df_ta.index, df_ta.iloc[:, 0].values, "r", lw=2) ax1.plot(df_ta.index, df_ta.iloc[:, 1].values, "g", lw=2) ax1.set_xlim(df_stock.index[0], df_stock.index[-1]) ax1.axhline(50, linewidth=1, color="k", ls="--") ax1.legend( [ f"Aroon DOWN ({df_ta.columns[0]})", f"Aroon UP ({df_ta.columns[1]})" ], loc="upper left", ) ax1.grid(b=True, which="major", color="#666666", linestyle="-") ax1.set_ylim([0, 100]) ax2 = ax[2] ax2.plot(df_ta.index, df_ta.iloc[:, 2].values, "b", lw=2) ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.set_xlabel("Time") ax2.legend([f"Aroon OSC ({df_ta.columns[2]})"], loc="upper left") ax2.grid(b=True, which="major", color="#666666", linestyle="-") ax2.set_ylim([-100, 100]) fig.tight_layout(pad=1) plt.gcf().autofmt_xdate() plt.savefig("ta_aroon.png") uploaded_image = gst_imgur.upload_image("ta_aroon.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Aroon-Indicator " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_aroon.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Aroon-Indicator", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def ftd_command(ctx, ticker="", start="", end=""): """Fails-to-deliver data [SEC]""" try: # Debug user input if cfg.DEBUG: logger.debug("!stocks.dps.ftd %s %s %s", ticker, start, end) # 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") 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) # Retrieve data ftds_data = sec_model.get_fails_to_deliver(ticker, start, end, 0) # Debug user output if cfg.DEBUG: logger.debug(ftds_data.to_string()) plt.figure(dpi=PLOT_DPI) # Output data plt.bar( ftds_data["SETTLEMENT DATE"], ftds_data["QUANTITY (FAILS)"] / 1000, ) plt.ylabel("Shares [K]") plt.title(f"Fails-to-deliver Data for {ticker}") plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2) plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d")) plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=7)) plt.gcf().autofmt_xdate() plt.xlabel("Days") _ = plt.gca().twinx() stock = discordbot.helpers.load(ticker, start) stock_ftd = stock[stock.index > start] stock_ftd = stock_ftd[stock_ftd.index < end] plt.plot(stock_ftd.index, stock_ftd["Adj Close"], color="tab:orange") plt.ylabel("Share Price [$]") plt.savefig("dps_ftd.png") plt.close("all") uploaded_image = gst_imgur.upload_image("dps_ftd.png", title="something") image_link = uploaded_image.link title = "Stocks: [SEC] Failure-to-deliver " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("dps_ftd.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title=f"ERROR Stocks: [SEC] Failure-to-deliver {ticker}", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def feargreed_command(ctx, indicator=""): """CNN Fear and Greed Index [CNN]""" try: # Debug user input if cfg.DEBUG: print(f"\n!economy.feargreed {indicator}") # Check for argument possible_indicators = ("", "jbd", "mv", "pco", "mm", "sps", "spb", "shd") if indicator not in possible_indicators: raise Exception( f"Select a valid indicator from {', '.join(possible_indicators)}" ) # Retrieve data fig = plt.figure(figsize=[1, 1], dpi=10) report, _ = cnn_model.get_feargreed_report(indicator, fig) cnn_view.fear_and_greed_index(indicator=indicator, export="png") plt.close("all") # Output data now = datetime.datetime.now() image_path = os.path.join( cfg.GST_PATH, "exports", "economy", f"feargreed_{now.strftime('%Y%m%d_%H%M%S')}.png", ) i = 0 while not os.path.exists(image_path) and i < 10: now -= datetime.timedelta(seconds=1) image_path = os.path.join( cfg.GST_PATH, "exports", "economy", f"feargreed_{now.strftime('%Y%m%d_%H%M%S')}.png", ) i += 1 embed = discord.Embed( title="Economy: [CNN] Fear Geed Index", description=report, colour=cfg.COLOR, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) if os.path.exists(image_path): uploaded_image = gst_imgur.upload_image( image_path, title="FearGreed Charts" ) embed.set_image(url=uploaded_image.link) else: if cfg.DEBUG: print("Error with uploading the the image to Imgur.") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Economy: [CNN] Feargreed", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def bbands_command(ctx, ticker="", length="5", n_std="2", mamode="sma", start="", end=""): """Displays chart with bollinger bands [Yahoo Finance]""" try: # Debug if cfg.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "!stocks.ta.bbands %s %s %s %s %s %s", ticker, length, n_std, mamode, start, end, ) # 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 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) if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") length = float(length) if not n_std.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") n_std = float(n_std) if mamode not in possible_ma: raise Exception("Invalid ma entered") ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = volatility_model.bbands(df_stock["Adj Close"], length, n_std, mamode) # Output Data fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.plot(df_stock.index, df_stock["Adj Close"].values, color="k", lw=3) ax.plot(df_ta.index, df_ta.iloc[:, 0].values, "r", lw=2) ax.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=1.5, ls="--") ax.plot(df_ta.index, df_ta.iloc[:, 2].values, "g", lw=2) ax.set_title(f"{ticker} Bollinger Bands") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_xlabel("Time") ax.set_ylabel("Share Price ($)") ax.legend( [ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]]) ax.fill_between( df_ta.index, df_ta.iloc[:, 0].values, df_ta.iloc[:, 2].values, alpha=0.1, color="b", ) ax.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_bbands.png") uploaded_image = gst_imgur.upload_image("ta_bbands.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Bollinger-Bands " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_bbands.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Bollinger-Bands", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def kc_command(ctx, ticker="", length="20", scalar="2", mamode="sma", offset="0", start="", end=""): """Displays chart with keltner channel [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print( f"!stocks.ta.kc {ticker} {length} {scalar} {mamode} {offset} {start} {end}" ) # Check for argument possible_ma = ["sma", "ema", "wma", "hma", "zlma"] if ticker == "": raise Exception("Stock ticker is required") 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) 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 offset.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") offset = float(offset) if mamode not in possible_ma: raise Exception("Invalid ma entered") ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = volatility_model.kc("1440min", df_stock, length, scalar, mamode, offset) # Output Data fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.plot(df_stock.index, df_stock["Adj Close"].values, color="fuchsia") ax.plot(df_ta.index, df_ta.iloc[:, 0].values, "b", lw=1.5, label="upper") ax.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=1.5, ls="--") ax.plot(df_ta.index, df_ta.iloc[:, 2].values, "b", lw=1.5, label="lower") ax.set_title(f"{ticker} Keltner Channels") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_xlabel("Time") ax.set_ylabel("Price") ax.legend( [ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]]) ax.fill_between( df_ta.index, df_ta.iloc[:, 0].values, df_ta.iloc[:, 2].values, alpha=0.1, color="b", ) ax.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.legend() plt.savefig("ta_kc.png") uploaded_image = gst_imgur.upload_image("ta_kc.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Keltner-Channel " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_kc.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Keltner-Channel", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def toplobbying_command(ctx, num="", raw=""): """Displays top lobbying firms [quiverquant.com]""" try: # Debug user input if cfg.DEBUG: logger.debug("!stocks.gov.toplobbying %s %s", num, raw) if num == "": num = 10 else: if not num.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") num = int(num) if raw in ["false", "False", "FALSE", ""]: raw = False if raw in ["true", "True", "TRUE"]: raw = True if raw not in [True, False]: raise Exception("raw argument has to be true or false") # Retrieve Data df_lobbying = quiverquant_model.get_government_trading( "corporate-lobbying") if df_lobbying.empty: raise Exception("No corporate lobbying found") df_lobbying["Amount"] = df_lobbying.Amount.astype(float).fillna( 0) / 100_000 lobbying_by_ticker = pd.DataFrame( df_lobbying.groupby("Ticker")["Amount"].agg("sum")).sort_values( by="Amount", ascending=False) fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) lobbying_by_ticker.head(num).plot(kind="bar", ax=ax) ax.set_xlabel("Ticker") ax.set_ylabel("Total Amount ($100k)") ax.set_title( f"Corporate Lobbying Spent since {df_lobbying['Date'].min()}") fig.tight_layout() plt.savefig("ta_toplobbying.png") uploaded_image = gst_imgur.upload_image("ta_toplobbying.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: [quiverquant.com] Top Lobbying Firms" if raw: description = lobbying_by_ticker.head(num).to_string() embed = discord.Embed(title=title, description=description, colour=cfg.COLOR) else: embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_toplobbying.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: [quiverquant.com] Top Lobbying Firms", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def psi_command(ctx, ticker=""): """Price vs short interest volume [Stockgrid]""" try: # Debug user input if cfg.DEBUG: logger.debug("!stocks.dps.psi %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, prices = stockgrid_model.get_short_interest_volume(ticker) # Debug user output if cfg.DEBUG: logger.debug(df.to_string()) # Output data title = f"Stocks: [Stockgrid] Price vs Short Interest Volume {ticker}" embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) _, axes = plt.subplots( 2, 1, dpi=PLOT_DPI, gridspec_kw={"height_ratios": [2, 1]}, ) axes[0].bar( df["date"], df["total_volume"] / 1_000_000, width=timedelta(days=1), color="b", alpha=0.4, label="Total Volume", ) axes[0].bar( df["date"], df["short_volume"] / 1_000_000, width=timedelta(days=1), color="r", alpha=0.4, label="Short Volume", ) axes[0].set_ylabel("Volume (1M)") ax2 = axes[0].twinx() ax2.plot( df["date"].values, prices[len(prices) - len(df):], # noqa: E203 c="k", label="Price", ) ax2.set_ylabel("Price ($)") lines, labels = axes[0].get_legend_handles_labels() lines2, labels2 = ax2.get_legend_handles_labels() ax2.legend(lines + lines2, labels + labels2, loc="upper left") axes[0].grid() axes[0].ticklabel_format(style="plain", axis="y") plt.title(f"Price vs Short Volume Interest for {ticker}") plt.gcf().autofmt_xdate() axes[1].plot( df["date"].values, 100 * df["short_volume%"], c="green", label="Short Vol. %", ) axes[1].set_ylabel("Short Vol. %") axes[1].grid(axis="y") lines, labels = axes[1].get_legend_handles_labels() axes[1].legend(lines, labels, loc="upper left") axes[1].set_ylim([0, 100]) file_name = ticker + "_psi.png" plt.savefig(file_name) plt.close("all") uploaded_image = gst_imgur.upload_image(file_name, title="something") image_link = uploaded_image.link embed.set_image(url=image_link) os.remove(file_name) await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title= f"ERROR Stocks: [Stockgrid] Price vs Short Interest Volume {ticker}", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def topbuys_command(ctx, gov_type="", past_transactions_months="", num="", raw=""): """Displays most purchased stocks by the congress/senate/house [quiverquant.com]""" try: # Debug user input if cfg.DEBUG: logger.debug( "!stocks.gov.topbuys %s %s %s %s", gov_type, past_transactions_months, num, raw, ) if past_transactions_months == "": past_transactions_months = 5 else: if not past_transactions_months.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") past_transactions_months = int(past_transactions_months) if num == "": num = 10 else: if not num.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") num = int(num) if raw in ["false", "False", "FALSE", ""]: raw = False if raw in ["true", "True", "TRUE"]: raw = True if raw not in [True, False]: raise Exception("raw argument has to be true or false") possible_args = ["congress", "senate", "house"] if gov_type == "": gov_type = "congress" elif gov_type not in possible_args: raise Exception( "Enter a valid government argument, options are: congress, senate and house" ) # Retrieve Data df_gov = quiverquant_model.get_government_trading(gov_type) if df_gov.empty: logger.debug("No %s trading data found", gov_type) return df_gov = df_gov.sort_values("TransactionDate", ascending=False) start_date = datetime.now() - timedelta(days=past_transactions_months * 30) df_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"]) df_gov = df_gov[df_gov["TransactionDate"] > start_date].dropna() # Catch bug where error shown for purchase of >5,000,000 df_gov["Range"] = df_gov["Range"].apply( lambda x: "$5,000,001-$5,000,001" if x == ">$5,000,000" else x) df_gov["min"] = df_gov["Range"].apply( lambda x: x.split("-")[0].strip("$").replace(",", "").strip()) df_gov["max"] = df_gov["Range"].apply( lambda x: x.split("-")[1].replace(",", "").strip().strip("$") if "-" in x else x.strip("$").replace(",", "")) df_gov["lower"] = df_gov[["min", "max", "Transaction"]].apply( lambda x: float(x["min"]) if x["Transaction"] == "Purchase" else -float(x["max"]), axis=1, ) df_gov["upper"] = df_gov[["min", "max", "Transaction"]].apply( lambda x: float(x["max"]) if x["Transaction"] == "Purchase" else -float(x["min"]), axis=1, ) df_gov = df_gov.sort_values("TransactionDate", ascending=True) if raw: df = pd.DataFrame( df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values( ascending=False).head(n=num)) description = "```" + df.to_string() + "```" fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values( ascending=False).head(n=num).plot(kind="bar", rot=0, ax=ax) ax.set_ylabel("Amount [1k $]") ax.set_title( f"Top {num} purchased stocks over last {past_transactions_months} " f"months (upper bound) for {gov_type.upper()}") plt.gcf().axes[0].yaxis.get_major_formatter().set_scientific(False) fig.tight_layout() plt.savefig("gov_topbuys.png") uploaded_image = gst_imgur.upload_image("gov_topbuys.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = f"Stocks: [quiverquant.com] Top purchases for {gov_type.upper()}" if raw: embed = discord.Embed(title=title, description=description, colour=cfg.COLOR) else: embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("gov_topbuys.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title= f"ERROR Stocks: [quiverquant.com] Top purchases for {gov_type.upper()}", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def macd_command(ctx, ticker="", fast="12", slow="26", signal="9", start="", end=""): """Displays chart with moving average convergence/divergence [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print( f"!stocks.ta.macd {ticker} {fast} {slow} {signal} {start} {end}" ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) if not fast.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") fast = float(fast) if not slow.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") slow = float(slow) if not signal.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") signal = float(signal) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = momentum_model.macd("1440min", df_stock, fast, slow, signal) # Output Data fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax = axes[0] ax.set_title(f"{ticker} MACD") ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2) ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Share Price ($)") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax2 = axes[1] ax2.plot(df_ta.index, df_ta.iloc[:, 0].values, "b", lw=2) ax2.plot(df_ta.index, df_ta.iloc[:, 2].values, "r", lw=2) ax2.bar(df_ta.index, df_ta.iloc[:, 1].values, color="g") ax2.legend( [ f"MACD Line {df_ta.columns[0]}", f"Signal Line {df_ta.columns[2]}", f"Histogram {df_ta.columns[1]}", ], loc="upper left", ) ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_macd.png") uploaded_image = gst_imgur.upload_image("ta_cci.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Moving-Average-Convergence-Divergence " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_macd.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Moving-Average-Convergence-Divergence", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def pt_command(ctx, ticker="", raw="", start=""): """Displays price targets [Business Insider]""" try: # Debug if cfg.DEBUG: logger.debug("!stocks.dd.pt %s", ticker) # Check for argument if ticker == "": raise Exception("Stock ticker is required") if start == "": start = datetime.now() - timedelta(days=365) else: start = datetime.strptime(start, cfg.DATE_FORMAT) if raw in ["false", "False", "FALSE", ""]: raw = False if raw in ["true", "True", "TRUE"]: raw = True if raw not in [True, False]: raise Exception("raw argument has to be true or false") df_analyst_data = business_insider_model.get_price_target_from_analysts( ticker) stock = discordbot.helpers.load(ticker, start) if df_analyst_data.empty or stock.empty: raise Exception("Enter valid ticker") # Output Data if raw: df_analyst_data.sort_index(ascending=False) report = "´´´" + df_analyst_data.to_string() + "´´´" embed = discord.Embed( title="Stocks: [Business Insider] Price Targets", description=report, colour=cfg.COLOR, ).set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) ctx.send(embed=embed) else: plt.figure(dpi=PLOT_DPI) if start: df_analyst_data = df_analyst_data[start:] plt.plot(stock.index, stock["Adj Close"].values, lw=3) plt.plot(df_analyst_data.groupby(by=["Date"]).mean()) plt.scatter(df_analyst_data.index, df_analyst_data["Price Target"], c="r", s=40) plt.legend( ["Closing Price", "Average Price Target", "Price Target"]) plt.title(f"{ticker} (Time Series) and Price Target") plt.xlim(stock.index[0], stock.index[-1]) plt.xlabel("Time") plt.ylabel("Share Price") plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() plt.savefig("ta_pt.png") uploaded_image = gst_imgur.upload_image("ta_pt.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: [Business Insider] Price Targets " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_pt.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: [Business Insider] Price Targets", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def gtrades_command(ctx, ticker="", gov_type="", past_transactions_months="", raw=""): """Displays government trades [quiverquant.com]""" try: # Debug user input if cfg.DEBUG: print( f"!stocks.gov.gtrades {ticker} {gov_type} {past_transactions_months} {raw}" ) if past_transactions_months == "": past_transactions_months = 10 else: if not past_transactions_months.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") past_transactions_months = float(past_transactions_months) if raw in ["false", "False", "FALSE", ""]: raw = False if raw in ["true", "True", "TRUE"]: raw = True if raw not in [True, False]: raise Exception("raw argument has to be true or false") if ticker == "": raise Exception("A ticker is required") possible_args = ["congress", "senate", "house"] if gov_type == "": gov_type = "congress" elif gov_type not in possible_args: raise Exception( "Enter a valid government argument, options are: congress, senate and house" ) # Retrieve Data df_gov = quiverquant_model.get_government_trading(gov_type, ticker) if df_gov.empty: raise Exception(f"No {gov_type} trading data found") # Output Data df_gov = df_gov.sort_values("TransactionDate", ascending=False) start_date = datetime.now() - timedelta(days=past_transactions_months * 30) df_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"]) df_gov = df_gov[df_gov["TransactionDate"] > start_date] if df_gov.empty: print(f"No recent {gov_type} trading data found\n") return df_gov["min"] = df_gov["Range"].apply( lambda x: x.split("-")[0].strip("$").replace(",", "").strip()) df_gov["max"] = df_gov["Range"].apply( lambda x: x.split("-")[1].replace(",", "").strip().strip("$") if "-" in x else x.strip("$").replace(",", "").split("\n")[0]) df_gov["lower"] = df_gov[["min", "max", "Transaction"]].apply( lambda x: int(float(x["min"])) if x["Transaction"] == "Purchase" else -int(float(x["max"])), axis=1, ) df_gov["upper"] = df_gov[["min", "max", "Transaction"]].apply( lambda x: int(float(x["max"])) if x["Transaction"] == "Purchase" else -1 * int(float(x["min"])), axis=1, ) df_gov = df_gov.sort_values("TransactionDate", ascending=True) fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.fill_between( df_gov["TransactionDate"].unique(), df_gov.groupby("TransactionDate")["lower"].sum().values / 1000, df_gov.groupby("TransactionDate")["upper"].sum().values / 1000, ) ax.set_xlim([ df_gov["TransactionDate"].values[0], df_gov["TransactionDate"].values[-1], ]) ax.grid() ax.set_title(f"{gov_type.capitalize()} trading on {ticker}") ax.set_xlabel("Date") ax.set_ylabel("Amount ($1k)") plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d")) plt.gcf().autofmt_xdate() fig.tight_layout() plt.savefig("gov_gtrades.png") uploaded_image = gst_imgur.upload_image("gov_gtrades.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: [quiverquant.com] Government Trades" if raw: description = df_gov.to_string() embed = discord.Embed(title=title, description=description, colour=cfg.COLOR) else: embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("gov_gtrades.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: [quiverquant.com] Government Trades", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def contracts_command(ctx, ticker="", past_transaction_days="", raw=""): """Displays contracts associated with tickers [quiverquant.com]""" try: # Debug user input if cfg.DEBUG: logger.debug( "!stocks.gov.contracts %s %s %s", ticker, past_transaction_days, raw ) if past_transaction_days == "": past_transaction_days = 10 else: if not past_transaction_days.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") past_transaction_days = int(past_transaction_days) if raw in ["false", "False", "FALSE", ""]: raw = False if raw in ["true", "True", "TRUE"]: raw = True if raw not in [True, False]: raise Exception("raw argument has to be true or false") if ticker == "": raise Exception("A ticker is required") # Retrieve Data df_contracts = quiverquant_model.get_government_trading("contracts", ticker) if df_contracts.empty: raise Exception("No government contracts found") # Output Data df_contracts["Date"] = pd.to_datetime(df_contracts["Date"]).dt.date df_contracts = df_contracts[ df_contracts["Date"].isin( df_contracts["Date"].unique()[:past_transaction_days] ) ] df_contracts.drop_duplicates(inplace=True) fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) df_contracts.groupby("Date").sum().div(1000).plot(kind="bar", rot=0, ax=ax) ax.set_ylabel("Amount ($1k)") ax.set_title(f"Sum of latest government contracts to {ticker}") fig.tight_layout() plt.savefig("gov_contracts.png") uploaded_image = gst_imgur.upload_image("gov_contracts.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = f"Stocks: [quiverquant.com] Contracts by {ticker}" if raw: description = df_contracts.to_string() embed = discord.Embed( title=title, description=description, colour=cfg.COLOR ) else: embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("gov_contracts.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title=f"ERROR Stocks: [quiverquant.com] Contracts by {ticker}", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def donchian_command(ctx, ticker="", upper_length="25", lower_length="100", start="", end=""): """Displays chart with donchian channel [Yahoo Finance]""" try: # Debug if cfg.DEBUG: logger.debug( "!stocks.ta.donchian %s %s %s %s %s", ticker, upper_length, lower_length, start, end, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) if not upper_length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") upper_length = float(upper_length) if not lower_length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") lower_length = float(lower_length) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = volatility_model.donchian(df_stock["High"], df_stock["Low"], upper_length, lower_length) # Output Data fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.plot(df_stock.index, df_stock["Adj Close"].values, color="k", lw=3) ax.plot(df_ta.index, df_ta.iloc[:, 0].values, "b", lw=1.5, label="upper") ax.plot(df_ta.index, df_ta.iloc[:, 1].values, "b", lw=1.5, ls="--") ax.plot(df_ta.index, df_ta.iloc[:, 2].values, "b", lw=1.5, label="lower") ax.set_title(f"{ticker} donchian") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_xlabel("Time") ax.set_ylabel("Price ($)") ax.legend( [ticker, df_ta.columns[0], df_ta.columns[1], df_ta.columns[2]]) ax.fill_between( df_ta.index, df_ta.iloc[:, 0].values, df_ta.iloc[:, 2].values, alpha=0.1, color="b", ) ax.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.legend() plt.savefig("ta_donchian.png") uploaded_image = gst_imgur.upload_image("ta_donchian.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Donchian-Channels " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_donchian.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Donchian-Channels", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def cg_command(ctx, ticker="", length="14", start="", end=""): """Displays chart with centre of gravity [Yahoo Finance]""" try: # Debug if cfg.DEBUG: logger.debug( "!stocks.ta.cg %s %s %s %s", ticker, length, start, end, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) if not length.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") length = float(length) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_close = df_stock["Adj Close"] df_close.columns = ["values"] df_ta = momentum_model.cg(df_close, length) # Output Data fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax = axes[0] ax.set_title(f"{ticker} Centre of Gravity") ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=1) ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Share Price ($)") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax2 = axes[1] ax2.plot(df_ta.index, df_ta.values, "b", lw=2, label="CG") # shift cg 1 bar forward for signal signal = df_ta.values signal = np.roll(signal, 1) ax2.plot(df_ta.index, signal, "g", lw=1, label="Signal") ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.legend() plt.savefig("ta_cg.png") uploaded_image = gst_imgur.upload_image("ta_cg.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Center-of-Gravity " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_cg.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Center-of-Gravity", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def ad_command(ctx, ticker="", is_open="False", start="", end=""): """Displays chart with accumulation/distribution line [Yahoo Finance]""" try: # Debug if cfg.DEBUG: logger.debug("!stocks.ta.ad %s %s %s %s", ticker, is_open, start, end) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) if is_open in ["false", "False", "FALSE", ""]: is_open = False if is_open in ["true", "True", "TRUE"]: is_open = True if is_open not in [True, False]: raise Exception("is_open argument has to be true or false") ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] bar_colors = [ "r" if x[1].Open < x[1].Close else "g" for x in df_stock.iterrows() ] divisor = 1_000_000 df_vol = df_stock["Volume"].dropna() df_vol = df_vol.values / divisor df_ta = volume_model.ad(df_stock, is_open) df_cal = df_ta.values df_cal = df_cal / divisor fig, axes = plt.subplots( 3, 1, gridspec_kw={"height_ratios": [2, 1, 1]}, figsize=plot_autoscale(), dpi=PLOT_DPI, ) ax = axes[0] ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2) ax.set_title(f"{ticker} AD") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Price") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax2 = axes[1] ax2.set_ylabel("Volume [M]") ax2.bar( df_stock.index, df_vol, color=bar_colors, alpha=0.8, width=0.3, ) ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax3 = axes[2] ax3.set_ylabel("A/D [M]") ax3.set_xlabel("Time") ax3.plot(df_ta.index, df_cal, "b", lw=1) ax3.set_xlim(df_stock.index[0], df_stock.index[-1]) ax3.axhline(0, linewidth=2, color="k", ls="--") ax3.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_ad.png") uploaded_image = gst_imgur.upload_image("ta_ad.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Accumulation/Distribution Line " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_ad.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Accumulation/Distribution Line", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def histcont_command(ctx, ticker=""): """Displays historical quarterly-contracts [quiverquant.com]""" try: # Debug user input if cfg.DEBUG: logger.debug("!stocks.gov.histcont %s", ticker) if ticker == "": raise Exception("A ticker is required") # Retrieve Data df_contracts = quiverquant_model.get_government_trading( "quarter-contracts", ticker=ticker) if df_contracts.empty: logger.debug("No quarterly government contracts found") return # Output Data amounts = df_contracts.sort_values(by=["Year", "Qtr"])["Amount"].values qtr = df_contracts.sort_values(by=["Year", "Qtr"])["Qtr"].values year = df_contracts.sort_values(by=["Year", "Qtr"])["Year"].values quarter_ticks = [ f"{quarter[0]}" if quarter[1] == 1 else "" for quarter in zip(year, qtr) ] fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.plot(np.arange(0, len(amounts)), amounts / 1000, "-*", lw=2, ms=15) ax.set_xlim([-0.5, len(amounts) - 0.5]) ax.set_xticks(np.arange(0, len(amounts))) ax.set_xticklabels(quarter_ticks) ax.grid() ax.set_title( f"Historical Quarterly Government Contracts for {ticker.upper()}") ax.set_xlabel("Date") ax.set_ylabel("Amount ($1k)") fig.tight_layout() plt.savefig("gov_histcont.png") uploaded_image = gst_imgur.upload_image("gov_histcont.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Historical Quarterly Government Contract " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("gov_histcont.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Historical Quarterly Government Contract", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def sma_command(ctx, ticker="", window="", offset="", start="", end=""): """Displays chart with simple moving average [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print(f"!stocks.ta.sma {ticker} {window} {offset} {start} {end}") # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) l_legend = [ticker] if window == "": window = [20, 50] else: window_temp = list() for wind in window.split(","): try: window_temp.append(float(wind)) except Exception as e: raise Exception("Window needs to be a float") from e window = window_temp if offset == "": offset = 0 else: if not offset.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") offset = float(offset) ticker = ticker.upper() stock = discordbot.helpers.load(ticker, start) if stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data price_df = pd.DataFrame(stock["Adj Close"].values, columns=["Price"], index=stock.index) i = 1 for win in window: sma_data = overlap_model.sma(s_interval="1440min", df_stock=stock, length=win, offset=offset) price_df = price_df.join(sma_data) l_legend.append(f"SMA {win}") i += 1 # Output Data start = start.strftime("%Y-%m-%d") end = end.strftime("%Y-%m-%d") price_df = price_df.loc[(price_df.index >= start) & (price_df.index < end)] fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ax.set_title(f"{ticker} SMA") ax.plot(price_df.index, price_df["Price"], lw=3, c="k") ax.set_xlabel("Time") ax.set_xlim([price_df.index[0], price_df.index[-1]]) ax.set_ylabel(f"{ticker} Price") for idx in range(1, price_df.shape[1]): ax.plot(price_df.iloc[:, idx]) ax.legend(l_legend) ax.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_sma.png") uploaded_image = gst_imgur.upload_image("ta_sma.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Simple-Moving-Average " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_sma.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Simple-Moving-Average", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def spos_command(ctx, ticker=""): """Net short vs position [Stockgrid]""" try: # Debug user input if cfg.DEBUG: logger.debug("!stocks.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 cfg.DEBUG: logger.debug(df.to_string()) # Output data title = f"Stocks: [Stockgrid] Net Short vs Position {ticker}" embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) fig = plt.figure(dpi=PLOT_DPI) ax = fig.add_subplot(111) ax.bar( df["dates"], df["dollar_net_volume"] / 1_000, color="r", alpha=0.4, label="Net Short Vol. (1k $)", ) ax.set_ylabel("Net Short Vol. (1k $)") ax2 = ax.twinx() ax2.plot( df["dates"].values, df["dollar_dp_position"], c="tab:blue", label="Position (1M $)", ) ax2.set_ylabel("Position (1M $)") lines, labels = ax.get_legend_handles_labels() lines2, labels2 = ax2.get_legend_handles_labels() ax2.legend(lines + lines2, labels + labels2, loc="upper left") ax.grid() plt.title(f"Net Short Vol. vs Position for {ticker}") plt.gcf().autofmt_xdate() file_name = ticker + "_spos.png" plt.savefig(file_name) plt.close("all") uploaded_image = gst_imgur.upload_image(file_name, title="something") image_link = uploaded_image.link embed.set_image(url=image_link) os.remove(file_name) await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title=f"ERROR Stocks: [Stockgrid] Net Short vs Position {ticker}", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def adosc_command( ctx, ticker="", is_open="False", fast="3", slow="10", start="", end="" ): """Displays chart with chaikin oscillator [Yahoo Finance]""" try: # Debug if cfg.DEBUG: # pylint: disable=logging-too-many-args logger.debug( "!stocks.ta.adosc %s %s %s %s %s", ticker, is_open, fast, slow, start, end, ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) if not fast.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") fast = float(fast) if not slow.lstrip("-").isnumeric(): raise Exception("Number has to be an integer") slow = float(slow) if is_open in ["false", "False", "FALSE", ""]: is_open = False if is_open in ["true", "True", "TRUE"]: is_open = True if is_open not in [True, False]: raise Exception("raw argument has to be true or false") ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] # Output Data bar_colors = [ "r" if x[1].Open < x[1].Close else "g" for x in df_stock.iterrows() ] divisor = 1_000_000 df_vol = df_stock["Volume"].dropna() df_vol = df_vol.values / divisor df_ta = volume_model.adosc(df_stock, is_open, fast, slow) df_cal = df_ta.values df_cal = df_cal / divisor fig, axes = plt.subplots( 3, 1, figsize=plot_autoscale(), dpi=PLOT_DPI, ) ax = axes[0] ax.set_title(f"{ticker} AD Oscillator") ax.plot(df_stock.index, df_stock["Adj Close"].values, "fuchsia", lw=1) ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Price") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax1 = axes[1] ax1.set_ylabel("Volume [M]") ax1.bar( df_stock.index, df_vol, color=bar_colors, alpha=0.8, width=0.3, ) ax1.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2 = axes[2] ax2.set_ylabel("AD Osc [M]") ax2.set_xlabel("Time") ax2.plot(df_ta.index, df_cal, "b", lw=2, label="AD Osc") ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.grid(b=True, which="major", color="#666666", linestyle="-") plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.legend() plt.savefig("ta_adosc.png") uploaded_image = gst_imgur.upload_image("ta_adosc.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: logger.debug("Image URL: %s", image_link) title = "Stocks: Accumulation/Distribution Oscillator " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_adosc.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Accumulation/Distribution Oscillator", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def rsi_command(ctx, ticker="", length="14", scalar="100", drift="1", start="", end=""): """Displays chart with relative strength index [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print( f"!stocks.ta.rsi {ticker} {length} {scalar} {drift} {start} {end}" ) # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) 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) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] df_ta = momentum_model.rsi("1440min", df_stock, length, scalar, drift) # Output Data fig, axes = plt.subplots(2, 1, figsize=plot_autoscale(), dpi=PLOT_DPI) ax = axes[0] ax.plot(df_stock.index, df_stock["Adj Close"].values, "k", lw=2) ax.set_title(f" {ticker} RSI{length} ") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax.set_ylabel("Share Price ($)") ax.grid(b=True, which="major", color="#666666", linestyle="-") ax2 = axes[1] ax2.plot(df_ta.index, df_ta.values, "b", lw=2) ax2.set_xlim(df_stock.index[0], df_stock.index[-1]) ax2.axhspan(70, 100, facecolor="r", alpha=0.2) ax2.axhspan(0, 30, facecolor="g", alpha=0.2) ax2.axhline(70, linewidth=3, color="r", ls="--") ax2.axhline(30, linewidth=3, color="g", ls="--") ax2.grid(b=True, which="major", color="#666666", linestyle="-") ax2.set_ylim([0, 100]) ax3 = ax2.twinx() ax3.set_ylim(ax2.get_ylim()) ax3.set_yticks([30, 70]) ax3.set_yticklabels(["OVERSOLD", "OVERBOUGHT"]) plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_rsi.png") uploaded_image = gst_imgur.upload_image("ta_rsi.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Relative-Strength-Index " + ticker embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_rsi.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Relative-Strength-Index", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def fib_command(ctx, ticker="", start="", end=""): """Displays chart with fibonacci retracement [Yahoo Finance]""" try: # Debug if cfg.DEBUG: print(f"!stocks.ta.fib {ticker} {start} {end}") # Check for argument if ticker == "": raise Exception("Stock ticker is required") 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) ticker = ticker.upper() df_stock = discordbot.helpers.load(ticker, start) if df_stock.empty: raise Exception("Stock ticker is invalid") # Retrieve Data df_stock = df_stock.loc[(df_stock.index >= start) & (df_stock.index < end)] start = start.strftime("%Y-%m-%d") end = end.strftime("%Y-%m-%d") ( df_fib, min_date, max_date, min_pr, max_pr, ) = custom_indicators_model.calculate_fib_levels(df_stock, 120, start, end) levels = df_fib.Price fig, ax = plt.subplots(figsize=(plot_autoscale()), dpi=cfp.PLOT_DPI) ax.plot(df_stock["Adj Close"], "b") ax.plot([min_date, max_date], [min_pr, max_pr], c="k") for i in levels: ax.axhline(y=i, c="g", alpha=0.5) for i in range(5): ax.fill_between(df_stock.index, levels[i], levels[i + 1], alpha=0.6) ax.set_ylabel("Price") ax.set_title(f"Fibonacci Support for {ticker.upper()}") ax.set_xlim(df_stock.index[0], df_stock.index[-1]) ax1 = ax.twinx() ax1.set_ylim(ax.get_ylim()) ax1.set_yticks(levels) ax1.set_yticklabels([0, 0.235, 0.382, 0.5, 0.618, 1]) plt.gcf().autofmt_xdate() fig.tight_layout(pad=1) plt.savefig("ta_fib.png") uploaded_image = gst_imgur.upload_image("ta_fib.png", title="something") image_link = uploaded_image.link if cfg.DEBUG: print(f"Image URL: {image_link}") title = "Stocks: Fibonacci-Retracement-Levels " + ticker str_df_fib = "```" + df_fib.to_string(index=False) + "```" embed = discord.Embed(title=title, colour=cfg.COLOR, description=str_df_fib) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) embed.set_image(url=image_link) os.remove("ta_fib.png") await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title="ERROR Stocks: Fibonacci-Retracement-Levels", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)
async def dpotc_command(ctx, ticker=""): """Dark pools (ATS) vs OTC data [FINRA]""" try: # Debug user input if cfg.DEBUG: print(f"\n!stocks.dps.dpotc {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 cfg.DEBUG: print(ats.to_string()) print(otc.to_string()) # Output data title = f"Stocks: [FINRA] Dark Pools (ATS) vs OTC {ticker}" embed = discord.Embed(title=title, colour=cfg.COLOR) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) if ats.empty and otc.empty: embed = embed.set_description("No data found.") # pylint: disable=no-member _, _ = plt.subplots(dpi=PLOT_DPI) plt.subplot(3, 1, (1, 2)) if not ats.empty and not otc.empty: plt.bar( ats.index, (ats["totalWeeklyShareQuantity"] + otc["totalWeeklyShareQuantity"]) / 1_000_000, color="tab:orange", ) plt.bar( otc.index, otc["totalWeeklyShareQuantity"] / 1_000_000, color="tab:blue", ) plt.legend(["ATS", "OTC"]) elif not ats.empty: plt.bar( ats.index, ats["totalWeeklyShareQuantity"] / 1_000_000, color="tab:orange", ) plt.legend(["ATS"]) elif not otc.empty: plt.bar( otc.index, otc["totalWeeklyShareQuantity"] / 1_000_000, color="tab:blue", ) plt.legend(["OTC"]) plt.ylabel("Total Weekly Shares [Million]") plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2) plt.title(f"Dark Pools (ATS) vs OTC (Non-ATS) Data for {ticker}") plt.subplot(313) if not ats.empty: plt.plot( ats.index, ats["totalWeeklyShareQuantity"] / ats["totalWeeklyTradeCount"], color="tab:orange", ) plt.legend(["ATS"]) if not otc.empty: plt.plot( otc.index, otc["totalWeeklyShareQuantity"] / otc["totalWeeklyTradeCount"], color="tab:blue", ) plt.legend(["ATS", "OTC"]) else: plt.plot( otc.index, otc["totalWeeklyShareQuantity"] / otc["totalWeeklyTradeCount"], color="tab:blue", ) plt.legend(["OTC"]) plt.ylabel("Shares per Trade") plt.grid(b=True, which="major", color="#666666", linestyle="-", alpha=0.2) plt.gcf().autofmt_xdate() plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%m/%d")) plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=4)) plt.xlabel("Weeks") file_name = ticker + "_dpotc.png" plt.savefig(file_name) plt.close("all") uploaded_image = gst_imgur.upload_image(file_name, title="something") image_link = uploaded_image.link embed.set_image(url=image_link) os.remove(file_name) await ctx.send(embed=embed) except Exception as e: embed = discord.Embed( title=f"ERROR Stocks: [FINRA] Dark Pools (ATS) vs OTC {ticker}", colour=cfg.COLOR, description=e, ) embed.set_author( name=cfg.AUTHOR_NAME, icon_url=cfg.AUTHOR_ICON_URL, ) await ctx.send(embed=embed)