From c5c3b8eee9d0641987c5fd8e7f3f9f794cb344f9 Mon Sep 17 00:00:00 2001 From: DidierRLopes Date: Mon, 1 Nov 2021 01:43:02 +0000 Subject: [PATCH] Major improvements to discord architecture (#887) * fix circular-imports on discordbot * Add pip install package to discord readme * improve valuation and performance commands * fix GST_PATH of config_discord * fix feargreed discordbot * Improve economy commands * add data output to bot * improve shorted command * fix shorted command * fix hsi discord command * improve dps.pos command * fix sidtc discord cmd * fix discord ftd command * fix dps.dpotc command * improve dps spos * check for ticker validity * Improve psi discord command * improve discord cmds * refactor economy discord cmds --- discordbot/README.md | 11 +- discordbot/config_discordbot.py | 64 ++-- discordbot/economy/currencies.py | 124 +++---- discordbot/economy/economy_menu.py | 70 ++-- discordbot/economy/feargreed.py | 200 +++++------ discordbot/economy/futures.py | 124 +++---- discordbot/economy/glbonds.py | 123 +++---- discordbot/economy/indices.py | 124 +++---- discordbot/economy/overview.py | 124 +++---- discordbot/economy/performance.py | 244 ++++++------- discordbot/economy/usbonds.py | 126 +++---- discordbot/economy/valuation.py | 245 ++++++------- discordbot/stocks/dark_pool_shorts/dpotc.py | 327 ++++++++---------- .../stocks/dark_pool_shorts/dps_menu.py | 152 ++++++-- discordbot/stocks/dark_pool_shorts/ftd.py | 275 +++++---------- discordbot/stocks/dark_pool_shorts/hsi.py | 198 +++++------ discordbot/stocks/dark_pool_shorts/pos.py | 282 ++++++--------- discordbot/stocks/dark_pool_shorts/psi.py | 291 +++++++--------- discordbot/stocks/dark_pool_shorts/shorted.py | 204 +++++------ discordbot/stocks/dark_pool_shorts/sidtc.py | 260 +++++--------- discordbot/stocks/dark_pool_shorts/spos.py | 237 +++++-------- 21 files changed, 1608 insertions(+), 2197 deletions(-) diff --git a/discordbot/README.md b/discordbot/README.md index b087bb9fa94..822a40d7ca3 100644 --- a/discordbot/README.md +++ b/discordbot/README.md @@ -25,30 +25,31 @@ Next, go into the discordbot folder with `cd discordbot` and install the followi pip install discord pip install discord_components pip install pyimgur +pip install python-dotenv ``` ## Registering Applications ### DISCORD -1. Login into your discord account in https://discord.com/developers/applications +1. Login into your discord account in https://discord.com/developers/applications 2. On the "Applications" tab, select "New Application" and name it something like "GST Bot". This will create a new application. 3. For creating a bot, we need to go into the "GST Bot" application previously created, and on the "Bot" tab select "Add Bot". Note: On this same page you can manage the bot permissions with regards to the server it will be added. 4. Next we need to obtain the "Client ID". For that we choose the "OAuth2" tab and copy our "Client ID" under "Client". 5. At this stage the bot is created and we are ready to invite it to one of our servers. To do so we need to access: -https://discord.com/oauth2/authorize?client_id=CLIENTID&scope=bot, where **CLIENTID** is replaced by the value copied above. +https://discord.com/oauth2/authorize?client_id=CLIENTID&scope=bot, where **CLIENTID** is replaced by the value copied above. 6. If everything went well, you should see a window popup where the Bot that was just created asks to which of your own servers do you want to add it to. -**NOTE:** If you haven't managed the bot permissions on the Bot tab previously you can do it via this link generator https://discordapi.com/permissions.html +**NOTE:** If you haven't managed the bot permissions on the Bot tab previously you can do it via this link generator https://discordapi.com/permissions.html ### IMGUR 1. Login into your https://imgur.com account. Create one if you don't have it. 2. Access https://api.imgur.com/oauth2/addclient to create your application. 3. Select "OAuth 2 authorization without a callback URL" when creating such. -4. You will receive a client ID and client secret once you submit the form. +4. You will receive a client ID and client secret once you submit the form. -**NOTE:** Registering is free for all open source projects and if your discord bot uses fewer than 1250 uploads per day. +**NOTE:** Registering is free for all open source projects and if your discord bot uses fewer than 1250 uploads per day. ## Discord Configs diff --git a/discordbot/config_discordbot.py b/discordbot/config_discordbot.py index 4b0809e0cba..97baf61e937 100644 --- a/discordbot/config_discordbot.py +++ b/discordbot/config_discordbot.py @@ -1,31 +1,33 @@ -import os -import sys -import discord - -from dotenv import load_dotenv - -env_files = [f for f in os.listdir() if f.endswith(".env")] -if env_files: - load_dotenv(env_files[0]) - -# Relative path to the terminal -sys.path.append("..") - -# https://discord.com/developers/applications/ -DISCORD_BOT_TOKEN = os.getenv("GT_DISCORD_BOT_TOKEN") or "REPLACE_ME" - -# https://apidocs.imgur.com -IMGUR_CLIENT_ID = os.getenv("GT_IMGUR_CLIENT_ID") or "REPLACE_ME" - -# Settings -COMMAND_PREFIX = "!" -DATE_FORMAT = "%Y-%m-%d" -COLOR = discord.Color.from_rgb(0, 206, 154) -MENU_TIMEOUT = 30 -DEBUG = True - -AUTHOR_NAME = "Gamestonk Terminal" -AUTHOR_ICON_URL = ( - "https://github.com/GamestonkTerminal/GamestonkTerminal/" - "blob/main/images/gst_logo_green_white_background.png?raw=true" -) +import os +import sys +import discord + +from dotenv import load_dotenv + +env_files = [f for f in os.listdir() if f.endswith(".env")] +if env_files: + load_dotenv(env_files[0]) + +# Relative path to the terminal +sys.path.append("..") + +# https://discord.com/developers/applications/ +DISCORD_BOT_TOKEN = os.getenv("GT_DISCORD_BOT_TOKEN") or "REPLACE_ME" + +# https://apidocs.imgur.com +IMGUR_CLIENT_ID = os.getenv("GT_IMGUR_CLIENT_ID") or "REPLACE_ME" + +# Settings +COMMAND_PREFIX = "!" +DATE_FORMAT = "%Y-%m-%d" +COLOR = discord.Color.from_rgb(0, 206, 154) +MENU_TIMEOUT = 30 +DEBUG = True + +GST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + +AUTHOR_NAME = "Gamestonk Terminal" +AUTHOR_ICON_URL = ( + "https://github.com/GamestonkTerminal/GamestonkTerminal/" + "blob/main/images/gst_logo_green_white_background.png?raw=true" +) diff --git a/discordbot/economy/currencies.py b/discordbot/economy/currencies.py index b534ff4b797..8a118dde808 100644 --- a/discordbot/economy/currencies.py +++ b/discordbot/economy/currencies.py @@ -1,73 +1,51 @@ -import discord -import config_discordbot as cfg - -from gamestonk_terminal.economy import wsj_model - - -async def currencies_command(ctx, arg=""): - """Gets the currencies data from GST and sends it - - Parameters - ----------- - arg: str - -h or help - - Returns - ------- - discord message - Sends a message containing an embed of currencies data to the users - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.currencies {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Currencies [Source: Wall St. Journal]\n" - embed = discord.Embed( - title="Economy: [WSJ] Currencies HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - df_data = wsj_model.global_currencies() - if df_data.empty: - df_data_str = "No currencies data available" - else: - df_data_str = "```" + df_data.to_string(index=False) + "```" - - embed = discord.Embed( - title="Economy: [WSJ] Currencies", - description=df_data_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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg + +from gamestonk_terminal.economy import wsj_model + + +async def currencies_command(ctx): + """Currencies overview [Wall St. Journal]""" + + try: + # Debug user input + if cfg.DEBUG: + print("\n!economy.currencies") + + # Retrieve data + df_data = wsj_model.global_currencies() + + # Debug user output + if cfg.DEBUG: + print(df_data.to_string()) + + # Output data + if df_data.empty: + df_data_str = "No currencies data available" + else: + df_data_str = "```" + df_data.to_string(index=False) + "```" + + embed = discord.Embed( + title="Economy: [WSJ] Currencies", + description=df_data_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 Economy: [WSJ] Currencies", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/economy/economy_menu.py b/discordbot/economy/economy_menu.py index e9b0fc4c28a..e5bea051119 100644 --- a/discordbot/economy/economy_menu.py +++ b/discordbot/economy/economy_menu.py @@ -2,6 +2,9 @@ import asyncio import discord import config_discordbot as cfg +# pylint: disable=wrong-import-order +from discordbot import gst_bot + from economy.feargreed import feargreed_command from economy.overview import overview_command from economy.indices import indices_command @@ -11,7 +14,6 @@ from economy.glbonds import glbonds_command from economy.currencies import currencies_command from economy.valuation import valuation_command from economy.performance import performance_command -from discordbot import gst_bot class EconomyCommands(discord.ext.commands.Cog): @@ -21,49 +23,73 @@ class EconomyCommands(discord.ext.commands.Cog): self.bot = bot @discord.ext.commands.command(name="economy.feargreed") - async def feargreed(self, ctx: discord.ext.commands.Context, arg=""): - """CNN Fear and Greed Index [CNN]""" - await feargreed_command(ctx, arg) + async def feargreed(self, ctx: discord.ext.commands.Context, indicator=""): + """CNN Fear and Greed Index [CNN] + + Parameters + ----------- + indicator: str + Possible indicatores are: jbd, mv, pco, mm, sps, spb, shd. Which stand for + Junk Bond Demand, Market Volatility, Put and Call Options, Market Momentum, + Stock Price Strength, Stock Price Breadth, Safe Heaven Demand. + """ + await feargreed_command(ctx, indicator) @discord.ext.commands.command(name="economy.overview") - async def overview(self, ctx: discord.ext.commands.Context, arg=""): + async def overview(self, ctx: discord.ext.commands.Context): """Market data overview [Wall St. Journal]""" - await overview_command(ctx, arg) + await overview_command(ctx) @discord.ext.commands.command(name="economy.indices") - async def indices(self, ctx: discord.ext.commands.Context, arg=""): + async def indices(self, ctx: discord.ext.commands.Context): """US indices overview [Wall St. Journal]""" - await indices_command(ctx, arg) + await indices_command(ctx) @discord.ext.commands.command(name="economy.futures") - async def futures(self, ctx: discord.ext.commands.Context, arg=""): + async def futures(self, ctx: discord.ext.commands.Context): """Futures and commodities overview [Wall St. Journal]""" - await futures_command(ctx, arg) + await futures_command(ctx) @discord.ext.commands.command(name="economy.usbonds") - async def usbonds(self, ctx: discord.ext.commands.Context, arg=""): + async def usbonds(self, ctx: discord.ext.commands.Context): """US bonds overview [Wall St. Journal]""" - await usbonds_command(ctx, arg) + await usbonds_command(ctx) @discord.ext.commands.command(name="economy.glbonds") - async def glbonds(self, ctx: discord.ext.commands.Context, arg=""): + async def glbonds(self, ctx: discord.ext.commands.Context): """Global bonds overview [Wall St. Journal]""" - await glbonds_command(ctx, arg) + await glbonds_command(ctx) @discord.ext.commands.command(name="economy.currencies") - async def currencies(self, ctx: discord.ext.commands.Context, arg=""): + async def currencies(self, ctx: discord.ext.commands.Context): """Currencies overview [Wall St. Journal]""" - await currencies_command(ctx, arg) + await currencies_command(ctx) @discord.ext.commands.command(name="economy.valuation") - async def valuation(self, ctx: discord.ext.commands.Context, arg=""): - """Valuation of sectors, industry, country [Finviz]""" - await valuation_command(ctx, arg) + async def valuation(self, ctx: discord.ext.commands.Context, economy_group=""): + """Valuation of sectors, industry, country [Finviz] + + Parameters + ----------- + economy_group: str + Possible groups are: sector, industry, basic_materials, communication_services, + consumer_cyclical, consumer_defensive, energy, financial, healthcare, industrials, + real_estate, technology, utilities, country, capitalization. + """ + await valuation_command(ctx, economy_group) @discord.ext.commands.command(name="economy.performance") - async def performance(self, ctx: discord.ext.commands.Context, arg=""): - """Performance of sectors, industry, country [Finviz]""" - await performance_command(ctx, arg) + async def performance(self, ctx: discord.ext.commands.Context, economy_group=""): + """Performance of sectors, industry, country [Finviz] + + Parameters + ----------- + economy_group: str + Possible groups are: sector, industry, basic_materials, communication_services, + consumer_cyclical, consumer_defensive, energy, financial, healthcare, industrials, + real_estate, technology, utilities, country, capitalization. + """ + await performance_command(ctx, economy_group) @discord.ext.commands.command(name="economy") async def economy(self, ctx: discord.ext.commands.Context): diff --git a/discordbot/economy/feargreed.py b/discordbot/economy/feargreed.py index c4569b2e7fe..ca418d2214e 100644 --- a/discordbot/economy/feargreed.py +++ b/discordbot/economy/feargreed.py @@ -1,113 +1,87 @@ -import discord -import matplotlib.pyplot as plt -import os -import datetime -import config_discordbot as cfg -from discordbot import gst_imgur - -from gamestonk_terminal.economy import cnn_view, cnn_model - - -async def feargreed_command(ctx, arg=""): - """Gets the fear greed data from GST and sends it - - Parameters - ----------- - arg: str - -h or help - - Returns - ------- - discord message - Sends a message containing an image of the fear & greed indicator to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.feargreed {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = """CNN Fear And Greed indicator or index. From Junk Bond Demand, Market Volatility, - Put and Call Options, Market Momentum Stock Price Strength, Stock Price Breadth, - Safe Heaven Demand, and Index. [Source: CNN Business]\n""" - - embed = discord.Embed( - title="Economy: [CNN] Fear Geed Index HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - plt.ion() - fig = plt.figure(figsize=[1, 1], dpi=10) - - report, _ = cnn_model.get_feargreed_report("", fig) - cnn_view.fear_and_greed_index(indicator="", export="png") - - plt.close("all") - - 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: - # report = "Error: The image could not be found" - print("Error with uploading the the image to Imgur.") - - plt.close("all") - - await ctx.send(embed=embed) - - except Exception as e: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import os +import datetime +import matplotlib.pyplot as plt +import discord +import config_discordbot as cfg +from discordbot import gst_imgur + +from gamestonk_terminal.economy import cnn_view, cnn_model + + +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) diff --git a/discordbot/economy/futures.py b/discordbot/economy/futures.py index f551584d8f0..a2159b11a0a 100644 --- a/discordbot/economy/futures.py +++ b/discordbot/economy/futures.py @@ -1,73 +1,51 @@ -import discord -import config_discordbot as cfg - -from gamestonk_terminal.economy import wsj_model - - -async def futures_command(ctx, arg=""): - """Gets the futures data from GST and sends it - - Parameters - ----------- - arg: str - -h or help - - Returns - ------- - discord message - Sends a message containing an embed of futures data to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.futures {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Futures/Commodities [Source: Wall St. Journal]\n" - embed = discord.Embed( - title="Economy: [WSJ] Futures/Commodities HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - df_data = wsj_model.top_commodities() - if df_data.empty: - df_data_str = "No futures/commodities data available" - else: - df_data_str = "```" + df_data.to_string(index=False) + "```" - - embed = discord.Embed( - title="Economy: [WSJ] Futures/Commodities", - description=df_data_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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg + +from gamestonk_terminal.economy import wsj_model + + +async def futures_command(ctx): + """Futures and commodities overview [Wall St. Journal]""" + + try: + # Debug user input + if cfg.DEBUG: + print("\n!economy.futures") + + # Retrieve data + df_data = wsj_model.top_commodities() + + # Debug user output + if cfg.DEBUG: + print(df_data.to_string()) + + # Output data + if df_data.empty: + df_data_str = "No futures/commodities data available" + else: + df_data_str = "```" + df_data.to_string(index=False) + "```" + + embed = discord.Embed( + title="Economy: [WSJ] Futures/Commodities", + description=df_data_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 Economy: [WSJ] Futures/Commodities", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/economy/glbonds.py b/discordbot/economy/glbonds.py index 9d4362881d5..6a170b55922 100644 --- a/discordbot/economy/glbonds.py +++ b/discordbot/economy/glbonds.py @@ -1,72 +1,51 @@ -import discord -import config_discordbot as cfg - -from gamestonk_terminal.economy import wsj_model - - -async def glbonds_command(ctx, arg=""): - """Gets the global bonds data from GST and sends it - - Parameters - ----------- - arg: str - -h or help - - Returns - ------- - discord message - Sends a message containing an embed of global bonds data to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.glbonds {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Global Bonds [Source: Wall St. Journal]\n" - embed = discord.Embed( - title="Economy: [WSJ] Global Bonds HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - df_data = wsj_model.global_bonds() - if df_data.empty: - df_data_str = "No global bonds data available" - else: - df_data_str = "```" + df_data.to_string(index=False) + "```" - - embed = discord.Embed( - title="Economy: [WSJ] Global Bonds", - description=df_data_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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg + +from gamestonk_terminal.economy import wsj_model + + +async def glbonds_command(ctx): + """Global bonds overview [Wall St. Journal]""" + + try: + # Debug user input + if cfg.DEBUG: + print("\n!economy.glbonds") + + # Retrieve data + df_data = wsj_model.global_bonds() + + # Debug user output + if cfg.DEBUG: + print(df_data.to_string()) + + # Output data + if df_data.empty: + df_data_str = "No global bonds data available" + else: + df_data_str = "```" + df_data.to_string(index=False) + "```" + + embed = discord.Embed( + title="Economy: [WSJ] Global Bonds", + description=df_data_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 Economy: [WSJ] Global Bonds", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/economy/indices.py b/discordbot/economy/indices.py index 099678020f3..661718449bf 100644 --- a/discordbot/economy/indices.py +++ b/discordbot/economy/indices.py @@ -1,73 +1,51 @@ -import discord -import config_discordbot as cfg - -from gamestonk_terminal.economy import wsj_model - - -async def indices_command(ctx, arg=""): - """Gets the indices data from GST and sends it - - Parameters - ----------- - arg: str - -h or help - - Returns - ------- - discord message - Sends a message containing an embed of indices data to the user - """ - - try: - # Debug - if cfg.DEBUG: - print("!stocks.economy.indices {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "US Indices [Source: Wall St. Journal]\n" - embed = discord.Embed( - title="Economy: [WSJ] US Indices HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - df_data = wsj_model.us_indices() - if df_data.empty: - df_data_str = "No indices data available" - else: - df_data_str = "```" + df_data.to_string(index=False) + "```" - - embed = discord.Embed( - title="Economy: [WSJ] US Indices", - description=df_data_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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg + +from gamestonk_terminal.economy import wsj_model + + +async def indices_command(ctx): + """US indices overview [Wall St. Journal]""" + + try: + # Debug user input + if cfg.DEBUG: + print("\n!economy.indices") + + # Retrieve data + df_data = wsj_model.us_indices() + + # Debug user output + if cfg.DEBUG: + print(df_data.to_string()) + + # Output data + if df_data.empty: + df_data_str = "No indices data available" + else: + df_data_str = "```" + df_data.to_string(index=False) + "```" + + embed = discord.Embed( + title="Economy: [WSJ] US Indices", + description=df_data_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 Economy: [WSJ] US Indices", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/economy/overview.py b/discordbot/economy/overview.py index 692c68358d7..7b5fcee83c4 100644 --- a/discordbot/economy/overview.py +++ b/discordbot/economy/overview.py @@ -1,73 +1,51 @@ -import discord -import config_discordbot as cfg - -from gamestonk_terminal.economy import wsj_model - - -async def overview_command(ctx, arg=""): - """Gets the market overview data from GST and sends it - - Parameters - ----------- - arg: str - -h or help - - Returns - ------- - discord message - Sends a message containing an embed of market overview data to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.overview {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Market Overview [Source: Wall St. Journal]\n" - embed = discord.Embed( - title="Economy: [WSJ] Market Overview HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - df_data = wsj_model.market_overview() - if df_data.empty: - df_data_str = "No overview data available" - else: - df_data_str = "```" + df_data.to_string(index=False) + "```" - - embed = discord.Embed( - title="Economy: [WSJ] Market Overview", - description=df_data_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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg + +from gamestonk_terminal.economy import wsj_model + + +async def overview_command(ctx): + """Market data overview [Wall St. Journal]""" + + try: + # Debug user input + if cfg.DEBUG: + print("\n!economy.overview") + + # Retrieve data + df_data = wsj_model.market_overview() + + # Debug user output + if cfg.DEBUG: + print(df_data.to_string()) + + # Output data + if df_data.empty: + df_data_str = "No overview data available" + else: + df_data_str = "```" + df_data.to_string(index=False) + "```" + + embed = discord.Embed( + title="Economy: [WSJ] Market Overview", + description=df_data_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 Economy: [WSK] Market Overview", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/economy/performance.py b/discordbot/economy/performance.py index 3111985ec81..b9e4f07fe52 100644 --- a/discordbot/economy/performance.py +++ b/discordbot/economy/performance.py @@ -1,143 +1,101 @@ -import discord -import config_discordbot as cfg -from helpers import pagination - -from gamestonk_terminal.economy import finviz_model - - -async def performance_command(ctx, arg="sector"): - """Gets the performance data of a entered sector from GST and sends it - - Parameters - ----------- - arg: str - sector (or any other input in the economy_group), -h or help - - Returns - ------- - discord message - Sends a message containing an embed of the performance data of the given arg - with pagination to the user - """ - - economy_group = { - "sector": "Sector", - "industry": "Industry", - "basic_materials": "Industry (Basic Materials)", - "communication services": "Industry (Communication Services)", - "consumer_cyclical": "Industry (Consumer Cyclical)", - "consumer_defensive": "Industry (Consumer Defensive)", - "energy": "Industry (Energy)", - "financial": "Industry (Financial)", - "healthcare": "Industry (Healthcare)", - "industrials": "Industry (Industrials)", - "real_estate": "Industry (Real Estate)", - "technology": "Industry (Technology)", - "utilities": "Industry (Utilities)", - "country": "Country (U.S. listed stocks only)", - "capitalization": "Capitalization", - } - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.performance {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Group performance [Source: Finviz]\n" - - possible_args = "" - for k, v in economy_group.items(): - possible_args += f"\n{k}: {v}" - - help_txt += "\nPossible arguments:\n" - help_txt += " Groups to get data from. Default: sector\n" - help_txt += f"The choices are:{possible_args}" - embed = discord.Embed( - title="Economy: [Finviz] Performance HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - # Parse argument - try: - group = economy_group[arg] - except KeyError: - title = "ERROR Economy: [Finviz] Performance" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"Entered group argument: {arg}" - "\nEnter a valid group argument, example: sector" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: Bad group argument entered") - return - - df_group = finviz_model.get_valuation_performance_data(group, "performance") - - future_column_name = df_group["Name"] - df_group = df_group.transpose() - df_group.columns = future_column_name - df_group.drop("Name") - columns = [] - - initial_str = "Page 0: Overview" - i = 1 - for col_name in df_group.columns.values: - initial_str += f"\nPage {i}: {col_name}" - i += 1 - - columns.append( - discord.Embed( - title=f"Economy: [Finviz] Performance {group}", - description=initial_str, - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - for column in df_group.columns.values: - columns.append( - discord.Embed( - description="```" - + df_group[column].fillna("").to_string() - + "```", - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - - await pagination(columns, ctx) - - except Exception as e: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg +from helpers import pagination + +from gamestonk_terminal.economy import finviz_model + + +async def performance_command(ctx, economy_group="sector"): + """Performance of sectors, industry, country [Finviz]""" + + d_economy_group = { + "sector": "Sector", + "industry": "Industry", + "basic_materials": "Industry (Basic Materials)", + "communication_services": "Industry (Communication Services)", + "consumer_cyclical": "Industry (Consumer Cyclical)", + "consumer_defensive": "Industry (Consumer Defensive)", + "energy": "Industry (Energy)", + "financial": "Industry (Financial)", + "healthcare": "Industry (Healthcare)", + "industrials": "Industry (Industrials)", + "real_estate": "Industry (Real Estate)", + "technology": "Industry (Technology)", + "utilities": "Industry (Utilities)", + "country": "Country (U.S. listed stocks only)", + "capitalization": "Capitalization", + } + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!economy.performance {economy_group}") + + # Select default group + if not economy_group: + if cfg.DEBUG: + print("Use default economy_group: 'sector'") + economy_group = "sector" + + # Check for argument + possible_groups = list(d_economy_group.keys()) + + if economy_group not in possible_groups: + raise Exception(f"Select a valid group from {', '.join(possible_groups)}") + + group = d_economy_group[economy_group] + + # Retrieve data + df_group = finviz_model.get_valuation_performance_data(group, "performance") + + # Debug user output + if cfg.DEBUG: + print(df_group.to_string()) + + # Output data + future_column_name = df_group["Name"] + df_group = df_group.transpose() + df_group.columns = future_column_name + df_group.drop("Name") + columns = [] + initial_str = "Page 0: Overview" + i = 1 + for col_name in df_group.columns.values: + initial_str += f"\nPage {i}: {col_name}" + i += 1 + + columns.append( + discord.Embed( + title=f"Economy: [Finviz] Performance {group}", + description=initial_str, + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + for column in df_group.columns.values: + columns.append( + discord.Embed( + description="```" + df_group[column].fillna("").to_string() + "```", + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + + await pagination(columns, ctx) + + except Exception as e: + embed = discord.Embed( + title="ERROR Economy: [Finviz] Performance", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/economy/usbonds.py b/discordbot/economy/usbonds.py index 64f13a85211..3dc3364680b 100644 --- a/discordbot/economy/usbonds.py +++ b/discordbot/economy/usbonds.py @@ -1,75 +1,51 @@ -import discord -import config_discordbot as cfg - -from gamestonk_terminal.economy import wsj_model - - -async def usbonds_command(ctx, arg=""): - """Gets the US bond data from GST and sends it - - Parameters - ----------- - arg: str - -h or help - - Returns - ------- - discord message - Sends a message containing an embed of US bond data to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.usbonds {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "US Bonds [Source: Wall St. Journal]\n" - embed = discord.Embed( - title="Economy: [WSJ] US Bonds HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - df_data = wsj_model.us_bonds() - if df_data.empty: - df_data_str = "No US bonds data available" - else: - df_data_str = "```" + df_data.to_string(index=False) + "```" - - embed = discord.Embed( - title="Economy: [WSJ] US Bonds", - description=df_data_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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg + +from gamestonk_terminal.economy import wsj_model + + +async def usbonds_command(ctx): + """US bonds overview [Wall St. Journal]""" + + try: + # Debug user input + if cfg.DEBUG: + print("\n!economy.usbonds") + + # Retrieve data + df_data = wsj_model.us_bonds() + + # Debug user output + if cfg.DEBUG: + print(df_data.to_string()) + + # Output data + if df_data.empty: + df_data_str = "No US bonds data available" + else: + df_data_str = "```" + df_data.to_string(index=False) + "```" + + embed = discord.Embed( + title="Economy: [WSJ] US Bonds", + description=df_data_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 Economy: [WSJ] US Bonds", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/economy/valuation.py b/discordbot/economy/valuation.py index a1814583d60..fb4dc4e18e7 100644 --- a/discordbot/economy/valuation.py +++ b/discordbot/economy/valuation.py @@ -1,143 +1,102 @@ -import discord -import config_discordbot as cfg -from helpers import pagination - -from gamestonk_terminal.economy import finviz_model - - -async def valuation_command(ctx, arg="sector"): - """Gets the valuation data of a entered sector from GST and sends it - - Parameters - ----------- - arg: str - sector (or any other input in the economy_group), -h or help - - Returns - ------- - discord message - Sends a message containing an embed of the valuation data of the given arg - with pagination to the user - """ - - economy_group = { - "sector": "Sector", - "industry": "Industry", - "basic_materials": "Industry (Basic Materials)", - "communication services": "Industry (Communication Services)", - "consumer_cyclical": "Industry (Consumer Cyclical)", - "consumer_defensive": "Industry (Consumer Defensive)", - "energy": "Industry (Energy)", - "financial": "Industry (Financial)", - "healthcare": "Industry (Healthcare)", - "industrials": "Industry (Industrials)", - "real_estate": "Industry (Real Estate)", - "technology": "Industry (Technology)", - "utilities": "Industry (Utilities)", - "country": "Country (U.S. listed stocks only)", - "capitalization": "Capitalization", - } - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.economy.performance {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Group valuation [Source: Finviz]\n" - - possible_args = "" - for k, v in economy_group.items(): - possible_args += f"\n{k}: {v}" - - help_txt += "\nPossible arguments:\n" - help_txt += " Groups to get data from. Default: sector\n" - help_txt += f"The choices are:{possible_args}" - embed = discord.Embed( - title="Economy: [Finviz] Valuation HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - try: - # Parse argument - group = economy_group[arg] - except KeyError: - title = "ERROR Economy: [Finviz] Performance" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"Entered group argument: {arg}" - "\nEnter a valid group argument, example: sector" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: Bad group argument entered") - return - - df_group = finviz_model.get_valuation_performance_data(group, "valuation") - - future_column_name = df_group["Name"] - df_group = df_group.transpose() - df_group.columns = future_column_name - df_group.drop("Name") - columns = [] - - initial_str = "Page 0: Overview" - i = 1 - for col_name in df_group.columns.values: - initial_str += f"\nPage {i}: {col_name}" - i += 1 - - columns.append( - discord.Embed( - title=f"Economy: [Finviz] Valuation {group}", - description=initial_str, - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - for column in df_group.columns.values: - columns.append( - discord.Embed( - description="```" - + df_group[column].fillna("").to_string() - + "```", - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - - await pagination(columns, ctx) - - except Exception as e: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg +from helpers import pagination + +from gamestonk_terminal.economy import finviz_model + + +async def valuation_command(ctx, economy_group="sector"): + """Valuation of sectors, industry, country [Finviz]""" + + d_economy_group = { + "sector": "Sector", + "industry": "Industry", + "basic_materials": "Industry (Basic Materials)", + "communication_services": "Industry (Communication Services)", + "consumer_cyclical": "Industry (Consumer Cyclical)", + "consumer_defensive": "Industry (Consumer Defensive)", + "energy": "Industry (Energy)", + "financial": "Industry (Financial)", + "healthcare": "Industry (Healthcare)", + "industrials": "Industry (Industrials)", + "real_estate": "Industry (Real Estate)", + "technology": "Industry (Technology)", + "utilities": "Industry (Utilities)", + "country": "Country (U.S. listed stocks only)", + "capitalization": "Capitalization", + } + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!economy.valuation {economy_group}") + + # Select default group + if economy_group == "": + if cfg.DEBUG: + print("Use default economy_group: 'sector'") + economy_group = "sector" + + # Check for argument + possible_groups = list(d_economy_group.keys()) + + if economy_group not in possible_groups: + raise Exception(f"Select a valid group from {', '.join(possible_groups)}") + + group = d_economy_group[economy_group] + + # Retrieve data + df_group = finviz_model.get_valuation_performance_data(group, "valuation") + + # Debug user output + if cfg.DEBUG: + print(df_group.to_string()) + + # Output data + future_column_name = df_group["Name"] + df_group = df_group.transpose() + df_group.columns = future_column_name + df_group.drop("Name") + columns = [] + + initial_str = "Page 0: Overview" + i = 1 + for col_name in df_group.columns.values: + initial_str += f"\nPage {i}: {col_name}" + i += 1 + + columns.append( + discord.Embed( + title=f"Economy: [Finviz] Valuation {group}", + description=initial_str, + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + for column in df_group.columns.values: + columns.append( + discord.Embed( + description="```" + df_group[column].fillna("").to_string() + "```", + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + + await pagination(columns, ctx) + + except Exception as e: + embed = discord.Embed( + title="ERROR Economy: [Finviz] Valuation", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/stocks/dark_pool_shorts/dpotc.py b/discordbot/stocks/dark_pool_shorts/dpotc.py index 522d143ff6b..b74c29e1a8c 100644 --- a/discordbot/stocks/dark_pool_shorts/dpotc.py +++ b/discordbot/stocks/dark_pool_shorts/dpotc.py @@ -1,189 +1,138 @@ -import discord -import config_discordbot as cfg -from discordbot import gst_imgur -from matplotlib import pyplot as plt -import matplotlib.dates as mdates -import os -from gamestonk_terminal.config_plot import PLOT_DPI - -from gamestonk_terminal.stocks.dark_pool_shorts import finra_model - - -async def dpotc_command(ctx, arg=""): - """Displays barchart of dark pool (ATS) and OTC (Non ATS) data and sends it - - Parameters - ----------- - arg: str - ticker, -h or help - - Returns - ------- - discord message - Sends a message containing an image displaying a barchart of dark pool - (ATS) and OTC (Non ATS) data to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.dpotc {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Display barchart of dark pool (ATS) and OTC (Non ATS) data. [Source: FINRA]\n" - help_txt += "\nPossible arguments:\n" - help_txt += " Stock ticker. REQUIRED!\n" - embed = discord.Embed( - title="Stocks: [FINRA] Dark Pools (ATS) vs OTC HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - if arg == "": - title = "ERROR Stocks: [FINRA] Dark Pools (ATS) vs OTC" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No ticker entered.\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No ticker entered") - return - - # Parse argument - ticker = arg.upper() - - plt.ion() - - title = "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, - ) - - try: - ats, otc = finra_model.getTickerFINRAdata(ticker) - except Exception as e: - title = "ERROR 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, - ) - embed.set_description( - f"Ticker given: {arg}\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(f"POSSIBLE ERROR: Wrong ticker parameter entered\n{e}") - return - - if ats.empty and otc.empty: - return embed.set_description("No data found.") - _, _ = 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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import os +import matplotlib.dates as mdates +import discord +import yfinance as yf +import config_discordbot as cfg +from matplotlib import pyplot as plt +from discordbot import gst_imgur +from gamestonk_terminal.config_plot import PLOT_DPI + +from gamestonk_terminal.stocks.dark_pool_shorts import finra_model + + +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.") + _, _ = 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) diff --git a/discordbot/stocks/dark_pool_shorts/dps_menu.py b/discordbot/stocks/dark_pool_shorts/dps_menu.py index 37eaa98ef25..2a7707de3af 100644 --- a/discordbot/stocks/dark_pool_shorts/dps_menu.py +++ b/discordbot/stocks/dark_pool_shorts/dps_menu.py @@ -1,6 +1,10 @@ import asyncio import discord import config_discordbot as cfg +import yfinance as yf + +# pylint: disable=wrong-import-order,too-many-branches +from discordbot import gst_bot from stocks.dark_pool_shorts.shorted import shorted_command from stocks.dark_pool_shorts.ftd import ftd_command @@ -10,7 +14,6 @@ from stocks.dark_pool_shorts.psi import psi_command from stocks.dark_pool_shorts.hsi import hsi_command from stocks.dark_pool_shorts.pos import pos_command from stocks.dark_pool_shorts.sidtc import sidtc_command -from discordbot import gst_bot class DarkPoolShortsCommands(discord.ext.commands.Cog): @@ -20,47 +23,106 @@ class DarkPoolShortsCommands(discord.ext.commands.Cog): self.bot = bot @discord.ext.commands.command(name="stocks.dps.shorted") - async def shorted(self, ctx: discord.ext.commands.Context, arg=""): - """Show most shorted stocks [Yahoo Finance]""" - await shorted_command(ctx, arg) + async def shorted(self, ctx: discord.ext.commands.Context, num="10"): + """Show most shorted stocks [Yahoo Finance] + + Parameters + ----------- + num: int + Number of the most shorted stocks to retrieve + """ + await shorted_command(ctx, num) @discord.ext.commands.command(name="stocks.dps.hsi") - async def hsi(self, ctx: discord.ext.commands.Context, arg=""): - """Show top high short interest stocks of over 20% ratio [shortinterest.com]""" - await hsi_command(ctx, arg) + async def hsi(self, ctx: discord.ext.commands.Context, num="10"): + """Show top high short interest stocks of over 20% ratio [shortinterest.com] + + Parameters + ----------- + num: int + Number of top stocks to print + """ + await hsi_command(ctx, num) @discord.ext.commands.command(name="stocks.dps.pos") - async def pos(self, ctx: discord.ext.commands.Context, arg="", arg2=""): - """Dark pool short position [Stockgrid]""" - await pos_command(ctx, arg, arg2) + async def pos(self, ctx: discord.ext.commands.Context, sort="dpp_dollar", num="10"): + """Dark pool short position [Stockgrid] + + Parameters + ----------- + sort: str + Field for which to sort. Possible are: sv, sv_pct, nsv, nsv_dollar, dpp, dpp_dollar. + These correspond to Short Vol. (1M), Short Vol. %%, Net Short Vol. (1M), + Net Short Vol. ($100M), DP Position (1M), DP Position ($1B), respectively. + num: int + Number of top tickers to show + """ + await pos_command(ctx, sort, num) @discord.ext.commands.command(name="stocks.dps.sidtc") - async def sidtc(self, ctx: discord.ext.commands.Context, arg="", arg2=""): - """Short interest and days to cover [Stockgrid]""" - await sidtc_command(ctx, arg, arg2) + async def sidtc(self, ctx: discord.ext.commands.Context, sort="float", num="10"): + """Short interest and days to cover [Stockgrid] + + Parameters + ----------- + sort: str + Field for which to sort. Possible are: float, dtc, si. + These correspond to Float Short %%, Days to Cover, Short Interest, respectively. + num: int + Number of top tickers to show + """ + await sidtc_command(ctx, sort, num) @discord.ext.commands.command(name="stocks.dps.ftd") - async def ftd(self, ctx: discord.ext.commands.Context, arg, arg2="", arg3=""): - """Fails-to-deliver data [SEC]""" - await ftd_command(ctx, arg, arg2, arg3) + async def ftd(self, ctx: discord.ext.commands.Context, ticker="", start="", end=""): + """Fails-to-deliver data [SEC] + + Parameters + ---------- + ticker: str + Stock ticker + start: datetime + Start of date + end: datetime + End of date + """ + await ftd_command(ctx, ticker, start, end) @discord.ext.commands.command(name="stocks.dps.dpotc") - async def dpotc(self, ctx: discord.ext.commands.Context, arg): - """Dark pools (ATS) vs OTC data [FINRA]""" - await dpotc_command(ctx, arg) + async def dpotc(self, ctx: discord.ext.commands.Context, ticker=""): + """Dark pools (ATS) vs OTC data [FINRA] + + Parameters + ---------- + ticker: str + Stock ticker + """ + await dpotc_command(ctx, ticker) @discord.ext.commands.command(name="stocks.dps.spos") - async def spos(self, ctx: discord.ext.commands.Context, arg): - """Net short vs position [Stockgrid]""" - await spos_command(ctx, arg) + async def spos(self, ctx: discord.ext.commands.Context, ticker=""): + """Net short vs position [Stockgrid] + + Parameters + ---------- + ticker: str + Stock ticker + """ + await spos_command(ctx, ticker) @discord.ext.commands.command(name="stocks.dps.psi") - async def psi(self, ctx: discord.ext.commands.Context, arg): - """Price vs short interest volume [Stockgrid]""" - await psi_command(ctx, arg) + async def psi(self, ctx: discord.ext.commands.Context, ticker=""): + """Price vs short interest volume [Stockgrid] + + Parameters + ---------- + ticker: str + Stock ticker + """ + await psi_command(ctx, ticker) @discord.ext.commands.command(name="stocks.dps") - async def dark_pool_shorts_menu(self, ctx: discord.ext.commands.Context, arg=""): + async def dark_pool_shorts_menu(self, ctx: discord.ext.commands.Context, ticker=""): """Stocks Context - Shows Dark Pool Shorts Menu Returns @@ -70,7 +132,23 @@ class DarkPoolShortsCommands(discord.ext.commands.Cog): """ if cfg.DEBUG: - print("!stocks.dps") + print(f"\n!stocks.dps {ticker}") + + if ticker: + stock = yf.download(ticker, progress=False) + if stock.empty: + embed = discord.Embed( + title="ERROR Stocks: Dark Pool and Short data", + colour=cfg.COLOR, + description="Stock ticker is invalid", + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) + return text = ( "0️⃣ !stocks.dps.shorted \n" @@ -78,12 +156,12 @@ class DarkPoolShortsCommands(discord.ext.commands.Cog): "2️⃣ !stocks.dps.pos \n" "3️⃣ !stocks.dps.sidtc \n" ) - if arg: + if ticker: text += ( - f"4️⃣ !stocks.dps.ftd {arg} \n" - f"5️⃣ !stocks.dps.dpotc {arg}\n" - f"6️⃣ !stocks.dps.spos {arg}\n" - f"7️⃣ !stocks.dps.psi {arg}\n" + f"4️⃣ !stocks.dps.ftd {ticker} \n" + f"5️⃣ !stocks.dps.dpotc {ticker}\n" + f"6️⃣ !stocks.dps.spos {ticker}\n" + f"7️⃣ !stocks.dps.psi {ticker}\n" ) else: text += ( @@ -101,7 +179,7 @@ class DarkPoolShortsCommands(discord.ext.commands.Cog): emoji_list = ["0️⃣", "1️⃣", "2️⃣", "3️⃣"] - if arg: + if ticker: emoji_list += ["4️⃣", "5️⃣", "6️⃣", "7️⃣"] for emoji in emoji_list: @@ -133,19 +211,19 @@ class DarkPoolShortsCommands(discord.ext.commands.Cog): elif reaction.emoji == "4️⃣": if cfg.DEBUG: print("Reaction selected: 4") - await ftd_command(ctx, arg) + await ftd_command(ctx, ticker) elif reaction.emoji == "5️⃣": if cfg.DEBUG: print("Reaction selected: 5") - await dpotc_command(ctx, arg) + await dpotc_command(ctx, ticker) elif reaction.emoji == "6️⃣": if cfg.DEBUG: print("Reaction selected: 6") - await spos_command(ctx, arg) + await spos_command(ctx, ticker) elif reaction.emoji == "7️⃣": if cfg.DEBUG: print("Reaction selected: 7") - await psi_command(ctx, arg) + await psi_command(ctx, ticker) for emoji in emoji_list: await msg.remove_reaction(emoji, ctx.bot.user) diff --git a/discordbot/stocks/dark_pool_shorts/ftd.py b/discordbot/stocks/dark_pool_shorts/ftd.py index 9037af584c6..45d9c1e6c2f 100644 --- a/discordbot/stocks/dark_pool_shorts/ftd.py +++ b/discordbot/stocks/dark_pool_shorts/ftd.py @@ -1,179 +1,96 @@ -import discord -import config_discordbot as cfg -from discordbot import gst_imgur -from datetime import datetime, timedelta -from matplotlib import pyplot as plt -import matplotlib.dates as mdates -import os -import helpers - -from gamestonk_terminal.stocks.dark_pool_shorts import sec_model - - -async def ftd_command(ctx, arg="", arg2="", arg3=""): - """Displays barchart of fail of deliver data of a given stock and sends it - - Parameters - ----------- - arg: str - ticker, -h or help - arg2: - date (in date format for start date) - arg3: - date (in date format for end date) - - Returns - ------- - discord message - Sends a message containing an image displaying a barchart fail to - deliver data to the user during a given time period - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.ftd {arg} {arg2} {arg3}") - - # Help - if arg == "-h" or arg == "help": - help_txt = ( - "Display fails-to-deliver data for a given ticker. [Source: SEC]\n" - ) - help_txt += "\nPossible arguments:\n" - help_txt += " Stock ticker. REQUIRED!\n" - help_txt += " Start of data. Default: 1 year ago\n" - help_txt += " End of data. Default: today\n" - embed = discord.Embed( - title="Stocks: [SEC] Failure-to-deliver HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - if arg == "": - title = "ERROR Stocks: [SEC] Failure-to-deliver" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No ticker entered.\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No ticker entered") - return - - # Parse argument - ticker = arg.upper() - if arg2 == "": - start = datetime.now() - timedelta(days=365) - else: - try: - start = datetime.strptime(arg2, cfg.DATE_FORMAT) - except Exception as e: - title = "ERROR Stocks: [SEC] Failure-to-deliver" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"Start Date given: {arg2}" - f"\nEnter a valid start date using the format: {cfg.DATE_FORMAT}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(f"ERROR: Wrong start date parameter entered\n{e}") - return - if arg3 == "": - end = datetime.now() - else: - try: - end = datetime.strptime(arg3, cfg.DATE_FORMAT) - except Exception as e: - title = "ERROR Stocks: [SEC] Failure-to-deliver" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"End Date given: {arg3}" - f"\nEnter a valid end date using the format: {cfg.DATE_FORMAT}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(f"ERROR: Wrong end date parameter entered\n{e}") - return - - plt.ion() - try: - ftds_data = sec_model.get_fails_to_deliver(ticker, start, end, 0) - except Exception as e: - title = f"ERROR 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_description( - f"Ticker given: {arg}" "\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(f"POSSIBLE ERROR: Wrong ticker parameter entered\n{e}") - return - 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 = 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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import os +from datetime import datetime, timedelta +import discord +import yfinance as yf +import config_discordbot as cfg +import helpers +from matplotlib import pyplot as plt +import matplotlib.dates as mdates +from discordbot import gst_imgur + + +from gamestonk_terminal.stocks.dark_pool_shorts import sec_model + + +async def ftd_command(ctx, ticker="", start="", end=""): + """Fails-to-deliver data [SEC]""" + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!stocks.dps.ftd {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: + print(ftds_data.to_string()) + + # 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 = 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) diff --git a/discordbot/stocks/dark_pool_shorts/hsi.py b/discordbot/stocks/dark_pool_shorts/hsi.py index 167068a0f67..b254331e574 100644 --- a/discordbot/stocks/dark_pool_shorts/hsi.py +++ b/discordbot/stocks/dark_pool_shorts/hsi.py @@ -1,119 +1,79 @@ -import discord -import config_discordbot as cfg -from helpers import pagination - -from gamestonk_terminal.stocks.dark_pool_shorts import shortinterest_model - - -async def hsi_command(ctx, arg="10"): - """Gets high shorted interest data from GST and sends it - - Parameters - ----------- - arg: str - number, -h or help - - Returns - ------- - discord message - Sends a message containing an embed of the stocks with the top high - shorted interest to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.hsi {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Display top high shorted interest stocks [Source: highshortinterest.com]\n" - help_txt += "\nPossible arguments:\n" - help_txt += " Number of stocks to display. Default: 10" - embed = discord.Embed( - title="Stocks: [highshortinterest.com] Top High Short Interest HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - try: - # Parse argument - num = int(arg) - if num < 0: - raise ValueError("Number has to be above 0") - except ValueError: - title = "ERROR Stocks: [SEC] Failure-to-deliver" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No number (int) entered." - "\nEnter a valid (positive) number, example: 10" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No (positive) int entered") - return - - df = shortinterest_model.get_high_short_interest() - df = df.iloc[1:].head(n=num) - - future_column_name = df["Ticker"] - df = df.transpose() - df.columns = future_column_name - df.drop("Ticker") - columns = [] - initial_str = "Page 0: Overview" - i = 1 - for column in df.columns.values: - initial_str = initial_str + "\nPage " + str(i) + ": " + column - i += 1 - columns.append( - discord.Embed( - title="Stocks: [highshortinterest.com] Top High Short Interest", - description=initial_str, - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - for column in df.columns.values: - columns.append( - discord.Embed( - title="Stocks: [highshortinterest.com] Top High Short Interest", - description="```" + df[column].fillna("").to_string() + "```", - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - - await pagination(columns, ctx) - - except Exception as e: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg +from helpers import pagination + +from gamestonk_terminal.stocks.dark_pool_shorts import shortinterest_model + + +async def hsi_command(ctx, num="10"): + """Show top high short interest stocks of over 20% ratio [shortinterest.com]""" + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!stocks.dps.hsi {num}") + + # Check for argument + if not num.lstrip("-").isnumeric(): + raise Exception("Number has to be an integer") + + num = int(num) + + if num < 0: + raise Exception("Number has to be above 0") + + # Retrieve data + df = shortinterest_model.get_high_short_interest() + df = df.iloc[1:].head(n=num) + + # Debug user output + if cfg.DEBUG: + print(df.to_string()) + + # Output data + future_column_name = df["Ticker"] + df = df.transpose() + df.columns = future_column_name + df.drop("Ticker") + columns = [] + initial_str = "Page 0: Overview" + i = 1 + for column in df.columns.values: + initial_str = initial_str + "\nPage " + str(i) + ": " + column + i += 1 + columns.append( + discord.Embed( + title="Stocks: [highshortinterest.com] Top High Short Interest", + description=initial_str, + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + for column in df.columns.values: + columns.append( + discord.Embed( + title="Stocks: [highshortinterest.com] Top High Short Interest", + description="```" + df[column].fillna("").to_string() + "```", + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + + await pagination(columns, ctx) + + except Exception as e: + embed = discord.Embed( + title="ERROR Stocks: [highshortinterest.com] Top High Short Interest", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/stocks/dark_pool_shorts/pos.py b/discordbot/stocks/dark_pool_shorts/pos.py index a599a2294e5..3fa1d92a448 100644 --- a/discordbot/stocks/dark_pool_shorts/pos.py +++ b/discordbot/stocks/dark_pool_shorts/pos.py @@ -1,177 +1,105 @@ -import discord -import config_discordbot as cfg -from helpers import pagination - -from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model - - -async def pos_command(ctx, arg="dpp_dollar", arg2="10"): - """Gets the dark pool shorts data sorted by arg from GST and sends it - - Parameters - ----------- - arg: str - sort (str in dark_pool_short), -h or help - arg2: str - number - - Returns - ------- - discord message - Sends a message containing an embed of dark pool shorts data given - the sorting arg to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.pos {arg} {arg2}") - - # Help - if arg == "-h" or arg == "help": - dark_pool_sort = { - "sv": "Short Vol. (1M)", - "sv_pct": "Short Vol. %", - "nsv": "Net Short Vol. (1M)", - "nsv_dollar": "Net Short Vol. ($100M)", - "dpp": "DP Position (1M)", - "dpp_dollar": "DP Position ($1B)", - } - - help_txt = "Get dark pool short positions. [Source: Stockgrid]\n" - - possible_args = "" - for k, v in dark_pool_sort.items(): - possible_args += f"\n{k}: {v}" - - help_txt += "\nPossible arguments:\n" - help_txt += " Field for which to sort by. Default: dpp_dollar\n" - help_txt += f"The choices are:{possible_args}\n" - help_txt += " Number of top tickers to show. Default: 10" - - embed = discord.Embed( - title="Stocks: [Stockgrid] Dark Pool Short Position HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - # Parse argument - sort = arg - - try: - num = int(arg2) - if num < 0: - raise ValueError("Number has to be above 0") - except ValueError: - title = "ERROR Stocks: [Stockgrid] Dark Pool Short Position" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No number (int) entered in the second argument." - "\nEnter a valid (positive) number, example: 10" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No (positive) int for second argument entered") - return - - try: - df = stockgrid_model.get_dark_pool_short_positions(sort, False) - except Exception as e: - title = "ERROR Stocks: [Stockgrid] Dark Pool Short Position" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"Sorting parameter given: {arg}" - "\nEnter a valid ticker, example: dpp_value" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(f"POSSIBLE ERROR: Wrong sort parameter entered\n{e}") - return - - df = df.iloc[:num] - dp_date = df["Date"].values[0] - df = df.drop(columns=["Date"]) - df["Net Short Volume $"] = df["Net Short Volume $"] / 100_000_000 - df["Short Volume"] = df["Short Volume"] / 1_000_000 - df["Net Short Volume"] = df["Net Short Volume"] / 1_000_000 - df["Short Volume %"] = df["Short Volume %"] * 100 - df["Dark Pools Position $"] = df["Dark Pools Position $"] / (1_000_000_000) - df["Dark Pools Position"] = df["Dark Pools Position"] / 1_000_000 - df.columns = [ - "Ticker", - "Short Vol. (1M)", - "Short Vol. %", - "Net Short Vol. (1M)", - "Net Short Vol. ($100M)", - "DP Position (1M)", - "DP Position ($1B)", - ] - future_column_name = df["Ticker"] - df = df.transpose() - df.columns = future_column_name - df.drop("Ticker") - columns = [] - initial_str = "Page 0: Overview" - i = 1 - for column in df.columns.values: - initial_str = initial_str + "\nPage " + str(i) + ": " + column - i += 1 - columns.append( - discord.Embed( - title="Stocks: [Stockgrid] Dark Pool Short Position", - description=initial_str, - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - for column in df.columns.values: - columns.append( - discord.Embed( - title="High Short Interest", - description="```The following data corresponds to the date: " - + dp_date - + "\n\n" - + df[column].fillna("").to_string() - + "```", - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - - await pagination(columns, ctx) - - except Exception as e: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg +from helpers import pagination + +from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model + + +async def pos_command(ctx, sort="dpp_dollar", num="10"): + """Dark pool short position [Stockgrid]""" + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!stocks.dps.pos {sort} {num}") + + # Check for argument + possible_sorts = ("sv", "sv_pct", "nsv", "nsv_dollar", "dpp", "dpp_dollar") + + if sort not in possible_sorts: + raise Exception(f"The possible sorts are: {', '.join(possible_sorts)}") + + if not num.lstrip("-").isnumeric(): + raise Exception("Number has to be an integer") + + num = int(num) + + if num < 0: + raise Exception("Number has to be above 0") + + # Retrieve data + df = stockgrid_model.get_dark_pool_short_positions(sort, False) + df = df.iloc[:num] + + # Debug user output + if cfg.DEBUG: + print(df.to_string()) + + # Output data + dp_date = df["Date"].values[0] + df = df.drop(columns=["Date"]) + df["Net Short Volume $"] = df["Net Short Volume $"] / 100_000_000 + df["Short Volume"] = df["Short Volume"] / 1_000_000 + df["Net Short Volume"] = df["Net Short Volume"] / 1_000_000 + df["Short Volume %"] = df["Short Volume %"] * 100 + df["Dark Pools Position $"] = df["Dark Pools Position $"] / (1_000_000_000) + df["Dark Pools Position"] = df["Dark Pools Position"] / 1_000_000 + df.columns = [ + "Ticker", + "Short Vol. (1M)", + "Short Vol. %", + "Net Short Vol. (1M)", + "Net Short Vol. ($100M)", + "DP Position (1M)", + "DP Position ($1B)", + ] + future_column_name = df["Ticker"] + df = df.transpose() + df.columns = future_column_name + df.drop("Ticker") + columns = [] + initial_str = "Page 0: Overview" + i = 1 + for column in df.columns.values: + initial_str = initial_str + "\nPage " + str(i) + ": " + column + i += 1 + columns.append( + discord.Embed( + title="Stocks: [Stockgrid] Dark Pool Short Position", + description=initial_str, + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + for column in df.columns.values: + columns.append( + discord.Embed( + title="High Short Interest", + description="```The following data corresponds to the date: " + + dp_date + + "\n\n" + + df[column].fillna("").to_string() + + "```", + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + + await pagination(columns, ctx) + + except Exception as e: + embed = discord.Embed( + title="ERROR Stocks: [Stockgrid] Dark Pool Short Position", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/stocks/dark_pool_shorts/psi.py b/discordbot/stocks/dark_pool_shorts/psi.py index 9fb6856be57..96cef147154 100644 --- a/discordbot/stocks/dark_pool_shorts/psi.py +++ b/discordbot/stocks/dark_pool_shorts/psi.py @@ -1,171 +1,120 @@ -import discord -import os -import config_discordbot as cfg -from discordbot import gst_imgur -from datetime import timedelta -from matplotlib import pyplot as plt -from gamestonk_terminal.config_plot import PLOT_DPI - -from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model - - -async def psi_command(ctx, arg=""): - """Gets price vs short interest volume plot from GST and sends it - - Parameters - ----------- - arg: str - ticker, -h or help - - Returns - ------- - discord message - Sends a message containing an image of price vs short interest volume of - a given ticker to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.psi {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Plot price vs short interest volume. [Source: Stockgrid]\n" - help_txt += "\nPossible arguments:\n" - help_txt += " Stock ticker. REQUIRED!\n" - embed = discord.Embed( - title="Stocks: [Stockgrid] Price vs Short Interest Volume HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - if arg == "": - title = "ERROR Stocks: [SEC] Failure-to-deliver" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No ticker entered." "\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No ticker entered") - return - - # Parse argument - ticker = arg.upper() - - plt.ion() - title = "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, - ) - - try: - df, prices = stockgrid_model.get_short_interest_volume(ticker) - except Exception as e: - title = ( - f"ERROR Stocks: [Stockgrid] Price vs Short Interest Volume {arg}" - ) - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"Ticker given: {arg}" "\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(f"POSSIBLE ERROR: Wrong ticker parameter entered\n{e}") - return - - _, 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) :], 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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import os +from datetime import timedelta +from matplotlib import pyplot as plt +import yfinance as yf +import discord +import config_discordbot as cfg +from discordbot import gst_imgur +from gamestonk_terminal.config_plot import PLOT_DPI + +from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model + + +async def psi_command(ctx, ticker=""): + """Price vs short interest volume [Stockgrid]""" + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!stocks.dps.psi {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: + print(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) :], 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) diff --git a/discordbot/stocks/dark_pool_shorts/shorted.py b/discordbot/stocks/dark_pool_shorts/shorted.py index 4bc086fb714..2c084ff4c99 100644 --- a/discordbot/stocks/dark_pool_shorts/shorted.py +++ b/discordbot/stocks/dark_pool_shorts/shorted.py @@ -1,122 +1,82 @@ -import discord -import config_discordbot as cfg -from helpers import pagination - -from gamestonk_terminal.stocks.dark_pool_shorts import yahoofinance_model - - -async def shorted_command(ctx, arg="5"): - """Gets the most shorted stocks data from GST and sends it - - Parameters - ----------- - arg: str - number, -h or help - - Returns - ------- - discord message - Sends a message containing an embed containing of the most shorted - stocks to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.shorted {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Display most shorted stocks screener. [Source: Yahoo Finance]\n" - help_txt += "\nPossible arguments:\n" - help_txt += " Number of stocks to display. Default: 5" - embed = discord.Embed( - title="Stocks: [Yahoo Finance] Most Shorted HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - try: - # Parse argument - num = int(arg) - if num < 0: - raise ValueError("Number has to be above 0") - except ValueError: - title = "ERROR Stocks: [Yahoo Finance] Most Shorted" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No number (int) entered." - "\nEnter a valid (positive) number, example: 10" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No (positive) int entered") - return - - df = yahoofinance_model.get_most_shorted().head(num) - - df.dropna(how="all", axis=1, inplace=True) - df = df.replace(float("NaN"), "") - future_column_name = df["Symbol"] - df = df.transpose() - df.columns = future_column_name - df.drop("Symbol") - columns = [] - - initial_str = "Page 0: Overview" - i = 1 - - for col_name in df.columns.values: - initial_str += f"\nPage {i}: {col_name}" - i += 1 - - columns.append( - discord.Embed( - title="Stocks: [Yahoo Finance] Most Shorted", - description=initial_str, - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - for column in df.columns.values: - columns.append( - discord.Embed( - description="```" + df[column].fillna("").to_string() + "```", - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - - await pagination(columns, ctx) - - except Exception as e: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg +from helpers import pagination + +from gamestonk_terminal.stocks.dark_pool_shorts import yahoofinance_model + + +async def shorted_command(ctx, num="10"): + """Show most shorted stocks [Yahoo Finance]""" + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!stocks.dps.shorted {num}") + + # Check for argument + if not num.lstrip("-").isnumeric(): + raise Exception("Number has to be an integer") + + num = int(num) + + if num < 0: + raise Exception("Number has to be above 0") + + # Retrieve data + df = yahoofinance_model.get_most_shorted().head(num) + + # Debug user output + if cfg.DEBUG: + print(df.to_string()) + + # Output data + df.dropna(how="all", axis=1, inplace=True) + df = df.replace(float("NaN"), "") + future_column_name = df["Symbol"] + df = df.transpose() + df.columns = future_column_name + df.drop("Symbol") + columns = [] + + initial_str = "Page 0: Overview" + i = 1 + + for col_name in df.columns.values: + initial_str += f"\nPage {i}: {col_name}" + i += 1 + + columns.append( + discord.Embed( + title="Stocks: [Yahoo Finance] Most Shorted", + description=initial_str, + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + for column in df.columns.values: + columns.append( + discord.Embed( + description="```" + df[column].fillna("").to_string() + "```", + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + + await pagination(columns, ctx) + + except Exception as e: + embed = discord.Embed( + title="ERROR Stocks: [Yahoo Finance] Most Shorted", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/stocks/dark_pool_shorts/sidtc.py b/discordbot/stocks/dark_pool_shorts/sidtc.py index 29013fc9059..e2101589876 100644 --- a/discordbot/stocks/dark_pool_shorts/sidtc.py +++ b/discordbot/stocks/dark_pool_shorts/sidtc.py @@ -1,164 +1,96 @@ -import discord -import config_discordbot as cfg -from helpers import pagination - -from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model - - -async def sidtc_command(ctx, arg="float", arg2="10"): - """Gets short interest and days to cover data from GST and sends it - - Parameters - ----------- - arg: str - sort (dark_pool_shorts), -h or help - arg2: str - number - - Returns - ------- - discord message - Sends a message containing an embed with short interest and days to cover - data to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.sidtc {arg} {arg2}") - - # Help - if arg == "-h" or arg == "help": - dark_pool_sort = { - "float": "Float Short %", - "dtc": "Days to Cover", - "si": "Short Interest", - } - - help_txt = "Get short interest and days to cover. [Source: Stockgrid]\n" - - possible_args = "" - for k, v in dark_pool_sort.items(): - possible_args += f"\n{k}: {v}" - - help_txt += "\nPossible arguments:\n" - help_txt += " Field for which to sort by. Default: float\n" - help_txt += f"The choices are:{possible_args}\n" - help_txt += " Number of top tickers to show. Default: 10" - - embed = discord.Embed( - title="Stocks: [Stockgrid] Short Interest and Days to Cover HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - await ctx.send(embed=embed) - - else: - # Parse argument - if arg == "float" or arg == "dtc" or arg == "si": - sort = arg - else: - title = "ERROR Stocks: [Stockgrid] Short Interest and Days to Cover" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"Entered sort argument: {arg}" - "\nEnter a valid sort argument, example: float" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: Bad sort argument entered") - return - - try: - num = int(arg2) - if num < 0: - raise ValueError("Number has to be above 0") - except ValueError: - title = "ERROR Stocks: [Stockgrid] Short Interest and Days to Cover" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No number (int) entered in the second argument." - "\nEnter a valid (positive) number, example: 10" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No (positive) int for second argument entered") - return - - df = stockgrid_model.get_short_interest_days_to_cover(sort) - df = df.iloc[:num] - dp_date = df["Date"].values[0] - df = df.drop(columns=["Date"]) - df["Short Interest"] = df["Short Interest"] / 1_000_000 - df.head() - df.columns = [ - "Ticker", - "Float Short %", - "Days to Cover", - "Short Interest (1M)", - ] - future_column_name = df["Ticker"] - df = df.transpose() - df.columns = future_column_name - df.drop("Ticker") - columns = [] - initial_str = "Page 0: Overview" - i = 1 - for column in df.columns.values: - initial_str = initial_str + "\nPage " + str(i) + ": " + column - i += 1 - columns.append( - discord.Embed( - title="Dark Pool Shorts", description=initial_str, colour=cfg.COLOR - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - for column in df.columns.values: - columns.append( - discord.Embed( - title="Stocks: [Stockgrid] Short Interest and Days to Cover", - description="```The following data corresponds to the date: " - + dp_date - + "\n\n" - + df[column].fillna("").to_string() - + "```", - colour=cfg.COLOR, - ).set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - ) - - await pagination(columns, ctx) - - except Exception as e: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import discord +import config_discordbot as cfg +from helpers import pagination + +from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model + + +async def sidtc_command(ctx, sort="float", num="10"): + """Short interest and days to cover [Stockgrid]""" + + try: + # Debug + if cfg.DEBUG: + print(f"\n!stocks.dps.sidtc {sort} {num}") + + # Check for argument + possible_sorts = ("float", "dtc", "si") + + if sort not in possible_sorts: + raise Exception(f"The possible sorts are: {', '.join(possible_sorts)}") + + if not num.lstrip("-").isnumeric(): + raise Exception("Number has to be an integer") + + num = int(num) + + if num < 0: + raise Exception("Number has to be above 0") + + # Retrieve data + df = stockgrid_model.get_short_interest_days_to_cover(sort) + df = df.iloc[:num] + + # Debug user output + if cfg.DEBUG: + print(df.to_string()) + + # Output data + dp_date = df["Date"].values[0] + df = df.drop(columns=["Date"]) + df["Short Interest"] = df["Short Interest"] / 1_000_000 + df.head() + df.columns = [ + "Ticker", + "Float Short %", + "Days to Cover", + "Short Interest (1M)", + ] + future_column_name = df["Ticker"] + df = df.transpose() + df.columns = future_column_name + df.drop("Ticker") + columns = [] + initial_str = "Page 0: Overview" + i = 1 + for column in df.columns.values: + initial_str = initial_str + "\nPage " + str(i) + ": " + column + i += 1 + columns.append( + discord.Embed( + title="Dark Pool Shorts", description=initial_str, colour=cfg.COLOR + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + for column in df.columns.values: + columns.append( + discord.Embed( + title="Stocks: [Stockgrid] Short Interest and Days to Cover", + description="```The following data corresponds to the date: " + + dp_date + + "\n\n" + + df[column].fillna("").to_string() + + "```", + colour=cfg.COLOR, + ).set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + ) + + await pagination(columns, ctx) + + except Exception as e: + embed = discord.Embed( + title="ERROR Stocks: [Stockgrid] Short Interest and Days to Cover", + colour=cfg.COLOR, + description=e, + ) + embed.set_author( + name=cfg.AUTHOR_NAME, + icon_url=cfg.AUTHOR_ICON_URL, + ) + + await ctx.send(embed=embed) diff --git a/discordbot/stocks/dark_pool_shorts/spos.py b/discordbot/stocks/dark_pool_shorts/spos.py index d45b9d423b9..90548a8193a 100644 --- a/discordbot/stocks/dark_pool_shorts/spos.py +++ b/discordbot/stocks/dark_pool_shorts/spos.py @@ -1,143 +1,94 @@ -import discord -import os -import config_discordbot as cfg -from discordbot import gst_imgur -from matplotlib import pyplot as plt -from gamestonk_terminal.config_plot import PLOT_DPI - -from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model - - -async def spos_command(ctx, arg=""): - """Gets price vs short interest volume plot from GST and sends it - - Parameters - ----------- - arg: str - ticker, -h or help - - Returns - ------- - discord message - Sends a message containing an image of net short position of a given - ticker to the user - """ - - try: - # Debug - if cfg.DEBUG: - print(f"!stocks.dps.spos {arg}") - - # Help - if arg == "-h" or arg == "help": - help_txt = "Plot net short position. [Source: Stockgrid]\n" - help_txt += "\nPossible arguments:\n" - help_txt += " Stock ticker. REQUIRED!\n" - embed = discord.Embed( - title="Stocks: [Stockgrid] Net Short vs Position HELP", - description=help_txt, - colour=cfg.COLOR, - ) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - else: - if arg == "": - title = "ERROR Stocks: [Stockgrid] Net Short vs Position" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "No ticker entered." "\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print("ERROR: No ticker entered") - return - - # Parse argument - ticker = arg.upper() - - plt.ion() - title = f"Stocks: [Stockgrid] Net Short vs Position {arg}" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - - try: - df = stockgrid_model.get_net_short_position(ticker) - except Exception as e: - title = "ERROR Stocks: [Stockgrid] Price vs Short Interest Volume" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - f"Ticker given: {arg}" "\nEnter a valid ticker, example: GME" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(f"POSSIBLE ERROR: Wrong ticker parameter entered\n{e}") - return - - 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: - title = "INTERNAL ERROR" - embed = discord.Embed(title=title, colour=cfg.COLOR) - embed.set_author( - name=cfg.AUTHOR_NAME, - icon_url=cfg.AUTHOR_ICON_URL, - ) - embed.set_description( - "Try updating the bot, make sure DEBUG is True in the config " - "and restart it.\nIf the error still occurs open a issue at: " - "https://github.com/GamestonkTerminal/GamestonkTerminal/issues" - f"\n{e}" - ) - await ctx.send(embed=embed) - if cfg.DEBUG: - print(e) +import os +import config_discordbot as cfg +import discord +from matplotlib import pyplot as plt +import yfinance as yf +from discordbot import gst_imgur +from gamestonk_terminal.config_plot import PLOT_DPI + +from gamestonk_terminal.stocks.dark_pool_shorts import stockgrid_model + + +async def spos_command(ctx, ticker=""): + """Net short vs position [Stockgrid]""" + + try: + # Debug user input + if cfg.DEBUG: + print(f"\n!stocks.dps.spos {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: + print(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)