mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 04:31:13 +00:00
Discord Bot: Adding Government Commands (#956)
* Discord Bot: Adding Government Commands * Fix linting * More linting * Even more linting * Adding topbuys and fixing the errors * Fixing errors and improving commands
This commit is contained in:
@@ -35,6 +35,7 @@ gst_bot.load_extension("economy.economy_menu")
|
||||
gst_bot.load_extension("stocks.dark_pool_shorts.dps_menu")
|
||||
gst_bot.load_extension("stocks.technical_analysis.ta_menu")
|
||||
gst_bot.load_extension("stocks.due_diligence.dd_menu")
|
||||
gst_bot.load_extension("stocks.government.gov_menu")
|
||||
|
||||
# Get all command names
|
||||
all_cmds = gst_bot.all_commands.keys()
|
||||
|
||||
94
discordbot/stocks/government/contracts.py
Normal file
94
discordbot/stocks/government/contracts.py
Normal file
@@ -0,0 +1,94 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from discordbot import gst_imgur
|
||||
from matplotlib import pyplot as plt
|
||||
import os
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
|
||||
|
||||
async def contracts_command(ctx, ticker="", past_transaction_days="", raw=""):
|
||||
"""Displays contracts associated with tickers [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(f"!stocks.gov.contracts {ticker} {past_transaction_days} {raw}")
|
||||
|
||||
if past_transaction_days == "":
|
||||
past_transaction_days = 10
|
||||
else:
|
||||
if not past_transaction_days.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
past_transaction_days = int(past_transaction_days)
|
||||
|
||||
if raw == "false" or raw == "False" or raw == "FALSE" or raw == "":
|
||||
raw = False
|
||||
elif raw == "true" or raw == "True" or raw == "TRUE":
|
||||
raw = True
|
||||
else:
|
||||
raise Exception("raw argument has to be true or false")
|
||||
|
||||
if ticker == "":
|
||||
raise Exception("A ticker is required")
|
||||
|
||||
# Retrieve Data
|
||||
df_contracts = quiverquant_model.get_government_trading("contracts", ticker)
|
||||
|
||||
if df_contracts.empty:
|
||||
raise Exception("No government contracts found")
|
||||
|
||||
# Output Data
|
||||
df_contracts["Date"] = pd.to_datetime(df_contracts["Date"]).dt.date
|
||||
|
||||
df_contracts = df_contracts[
|
||||
df_contracts["Date"].isin(
|
||||
df_contracts["Date"].unique()[:past_transaction_days]
|
||||
)
|
||||
]
|
||||
|
||||
df_contracts.drop_duplicates(inplace=True)
|
||||
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
df_contracts.groupby("Date").sum().div(1000).plot(kind="bar", rot=0, ax=ax)
|
||||
ax.set_ylabel("Amount ($1k)")
|
||||
ax.set_title(f"Sum of latest government contracts to {ticker}")
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig("gov_contracts.png")
|
||||
uploaded_image = gst_imgur.upload_image("gov_contracts.png", title="something")
|
||||
image_link = uploaded_image.link
|
||||
if cfg.DEBUG:
|
||||
print(f"Image URL: {image_link}")
|
||||
title = f"Stocks: [quiverquant.com] Contracts by {ticker}"
|
||||
if raw:
|
||||
description = df_contracts.to_string()
|
||||
embed = discord.Embed(
|
||||
title=title, description=description, colour=cfg.COLOR
|
||||
)
|
||||
else:
|
||||
embed = discord.Embed(title=title, colour=cfg.COLOR)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
embed.set_image(url=image_link)
|
||||
os.remove("gov_contracts.png")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title=f"ERROR Stocks: [quiverquant.com] Contracts by {ticker}",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
327
discordbot/stocks/government/gov_menu.py
Normal file
327
discordbot/stocks/government/gov_menu.py
Normal file
@@ -0,0 +1,327 @@
|
||||
import asyncio
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
|
||||
# pylint: disable=wrong-import-order,too-many-branches
|
||||
from discordbot import gst_bot
|
||||
|
||||
from stocks.government.lasttrades import lasttrades_command
|
||||
from stocks.government.topbuys import topbuys_command
|
||||
from stocks.government.topsells import topsells_command
|
||||
from stocks.government.lastcontracts import lastcontracts_command
|
||||
from stocks.government.qtrcontracts import qtrcontracts_command
|
||||
from stocks.government.toplobbying import toplobbying_command
|
||||
from stocks.government.gtrades import gtrades_command
|
||||
from stocks.government.contracts import contracts_command
|
||||
from stocks.government.histcont import histcont_command
|
||||
from stocks.government.lobbying import lobbying_command
|
||||
|
||||
|
||||
class GovernmentCommands(discord.ext.commands.Cog):
|
||||
"""Government menu"""
|
||||
|
||||
def __init__(self, bot: discord.ext.commands.Bot):
|
||||
self.bot = bot
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.lasttrades")
|
||||
async def lasttrades(
|
||||
self,
|
||||
ctx: discord.ext.commands.Context,
|
||||
gov_type="",
|
||||
past_transactions_days="",
|
||||
representative="",
|
||||
):
|
||||
"""Displays trades made by the congress/senate/house [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
gov_type: str
|
||||
Possible arguments: congress, senate & house
|
||||
past_transactions_days: int
|
||||
Positive number of past transaction days
|
||||
representative: str
|
||||
Enter name of a representative
|
||||
"""
|
||||
await lasttrades_command(ctx, gov_type, past_transactions_days, representative)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.topbuys")
|
||||
async def topbuys(
|
||||
self,
|
||||
ctx: discord.ext.commands.Context,
|
||||
gov_type="",
|
||||
past_transactions_months="",
|
||||
num="",
|
||||
raw="",
|
||||
):
|
||||
"""Displays most purchased stocks by the congress/senate/house [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
gov_type: str
|
||||
Possible arguments: congress, senate & house
|
||||
past_transactions_months: int
|
||||
Positive number of past transaction months
|
||||
num: int
|
||||
Number of most sold stocks to retrieve
|
||||
raw: boolean
|
||||
True or false
|
||||
"""
|
||||
await topbuys_command(ctx, gov_type, past_transactions_months, num, raw)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.topsells")
|
||||
async def topsells(
|
||||
self,
|
||||
ctx: discord.ext.commands.Context,
|
||||
gov_type="",
|
||||
past_transactions_months="",
|
||||
num="",
|
||||
raw="",
|
||||
):
|
||||
"""Displays most sold stocks by the congress/senate/house [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
gov_type: str
|
||||
Possible arguments: congress, senate & house
|
||||
past_transactions_months: int
|
||||
Positive number of past transaction months
|
||||
num: int
|
||||
Number of most sold stocks to retrieve
|
||||
raw: boolean
|
||||
True or false
|
||||
"""
|
||||
await topsells_command(ctx, gov_type, past_transactions_months, num, raw)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.lastcontracts")
|
||||
async def lastcontracts(
|
||||
self, ctx: discord.ext.commands.Context, past_transactions_days="", num=""
|
||||
):
|
||||
"""Displays last government contracts [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
past_transactions_days: int
|
||||
Positive number of past transaction days
|
||||
num: int
|
||||
Number of contracts
|
||||
"""
|
||||
await lastcontracts_command(ctx, past_transactions_days, num)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.qtrcontracts")
|
||||
async def qtrcontracts(
|
||||
self, ctx: discord.ext.commands.Context, num="", analysis=""
|
||||
):
|
||||
"""Displays a look at government contracts [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
analysis: str
|
||||
Possible arguments: total, upmom & downmom
|
||||
num: int
|
||||
Number of contracts
|
||||
"""
|
||||
await qtrcontracts_command(ctx, num, analysis)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.toplobbying")
|
||||
async def toplobbying(self, ctx: discord.ext.commands.Context, num="", raw=""):
|
||||
"""Displays top lobbying firms [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
num: int
|
||||
Number to show
|
||||
raw: boolean
|
||||
True or false
|
||||
"""
|
||||
await toplobbying_command(ctx, num, raw)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.gtrades")
|
||||
async def gtrades(
|
||||
self,
|
||||
ctx: discord.ext.commands.Context,
|
||||
ticker="",
|
||||
gov_type="",
|
||||
past_transactions_months="",
|
||||
raw="",
|
||||
):
|
||||
"""Displays government trades [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ticker: str
|
||||
ticker, -h or help
|
||||
gov_type: str
|
||||
Possible arguments: congress, senate & house
|
||||
past_transactions_months: int
|
||||
Positive number of past transaction months
|
||||
raw: boolean
|
||||
True or false
|
||||
"""
|
||||
await gtrades_command(ctx, ticker, gov_type, past_transactions_months, raw)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.contracts")
|
||||
async def contracts(
|
||||
self,
|
||||
ctx: discord.ext.commands.Context,
|
||||
ticker="",
|
||||
past_transaction_days="",
|
||||
raw="",
|
||||
):
|
||||
"""Displays contracts associated with tickers [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ticker: str
|
||||
ticker, -h or help
|
||||
past_transaction_days: int
|
||||
Number of past transaction months
|
||||
raw: boolean
|
||||
True or false
|
||||
"""
|
||||
await contracts_command(ctx, ticker, past_transaction_days, raw)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.histcont")
|
||||
async def histcont(self, ctx: discord.ext.commands.Context, ticker=""):
|
||||
"""Displays historical quarterly-contracts [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ticker: str
|
||||
ticker, -h or help
|
||||
"""
|
||||
await histcont_command(ctx, ticker)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov.lobbying")
|
||||
async def lobbying(self, ctx: discord.ext.commands.Context, ticker="", num=""):
|
||||
"""Displays lobbying details [quiverquant.com]
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
ticker: str
|
||||
ticker, -h or help
|
||||
num: int
|
||||
Number of events
|
||||
"""
|
||||
await lobbying_command(ctx, ticker, num)
|
||||
|
||||
@discord.ext.commands.command(name="stocks.gov")
|
||||
async def government_menu(self, ctx: discord.ext.commands.Context, ticker=""):
|
||||
"""Stocks Context - Shows Government Menu
|
||||
|
||||
Returns
|
||||
-------
|
||||
Sends a message to the discord user with the commands from the gov context.
|
||||
The user can then select a reaction to trigger a command.
|
||||
"""
|
||||
|
||||
if cfg.DEBUG:
|
||||
print(f"\n!stocks.gov {ticker}")
|
||||
|
||||
text = (
|
||||
"0️⃣ !stocks.gov.lasttrades <GOV_TYPE> <PAST_TRANSACTION_DAYS> "
|
||||
"<REPRESENTATIVE>\n"
|
||||
"1️⃣ !stocks.gov.topbuys <GOV_TYPE> <PAST_TRANSACTION_MONTHS>"
|
||||
"<NUM> <RAW>\n"
|
||||
"2️⃣ !stocks.gov.topsells <GOV_TYPE> <PAST_TRANSACTION_MONTHS>"
|
||||
"<NUM> <RAW>\n"
|
||||
"3️⃣ !stocks.gov.lastcontracts <PAST_TRANSACTION_DAYS> <NUM>\n"
|
||||
"4️⃣ !stocks.gov.qtrcontracts <ANALYSIS> <NUM>\n"
|
||||
"5️⃣ !stocks.gov.toplobbying <NUM> <RAW>\n"
|
||||
)
|
||||
if ticker:
|
||||
text += (
|
||||
f"6️⃣ !stocks.gov.gtrades {ticker} <GOV_TYPE> <PAST_TRANSACTION_MONTHS>"
|
||||
f"<RAW>\n"
|
||||
f"7️⃣ !stocks.gov.contracts {ticker} <PAST_TRANSACTION_DAYS> <RAW>\n"
|
||||
f"8️⃣ !stocks.gov.histcont {ticker}\n"
|
||||
f"9️⃣ !stocks.gov.lobbying {ticker} <NUM>\n"
|
||||
)
|
||||
else:
|
||||
text += (
|
||||
"\nMore commands available when providing a ticker with:"
|
||||
"\n!stocks.gov <TICKER>"
|
||||
)
|
||||
|
||||
title = "Stocks: Government (GOV) Menu"
|
||||
embed = discord.Embed(title=title, description=text, colour=cfg.COLOR)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
msg = await ctx.send(embed=embed)
|
||||
|
||||
emoji_list = ["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣"]
|
||||
|
||||
if ticker:
|
||||
emoji_list += ["5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"]
|
||||
|
||||
for emoji in emoji_list:
|
||||
await msg.add_reaction(emoji)
|
||||
|
||||
def check(reaction, user):
|
||||
return user == ctx.message.author and str(reaction.emoji) in emoji_list
|
||||
|
||||
try:
|
||||
reaction, _ = await gst_bot.wait_for(
|
||||
"reaction_add", timeout=cfg.MENU_TIMEOUT, check=check
|
||||
)
|
||||
if reaction.emoji == "0️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 0")
|
||||
await lasttrades_command(ctx)
|
||||
elif reaction.emoji == "1️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 1")
|
||||
await topbuys_command(ctx)
|
||||
elif reaction.emoji == "2️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 2")
|
||||
await topsells_command(ctx)
|
||||
elif reaction.emoji == "3️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 3")
|
||||
await lastcontracts_command(ctx)
|
||||
elif reaction.emoji == "4️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 4")
|
||||
await qtrcontracts_command(ctx)
|
||||
elif reaction.emoji == "5️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 5")
|
||||
await toplobbying_command(ctx, ticker)
|
||||
elif reaction.emoji == "6️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 6")
|
||||
await gtrades_command(ctx, ticker)
|
||||
elif reaction.emoji == "7️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 7")
|
||||
await contracts_command(ctx, ticker)
|
||||
elif reaction.emoji == "8️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 8")
|
||||
await histcont_command(ctx, ticker)
|
||||
elif reaction.emoji == "9️⃣":
|
||||
if cfg.DEBUG:
|
||||
print("Reaction selected: 9")
|
||||
await lobbying_command(ctx, ticker)
|
||||
|
||||
for emoji in emoji_list:
|
||||
await msg.remove_reaction(emoji, ctx.bot.user)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
for emoji in emoji_list:
|
||||
await msg.remove_reaction(emoji, ctx.bot.user)
|
||||
embed = discord.Embed(
|
||||
description="Error timeout - you snooze you lose! 😋",
|
||||
colour=cfg.COLOR,
|
||||
title="TIMEOUT Stocks: Government (GOV) Menu",
|
||||
).set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
|
||||
def setup(bot: discord.ext.commands.Bot):
|
||||
gst_bot.add_cog(GovernmentCommands(bot))
|
||||
149
discordbot/stocks/government/gtrades.py
Normal file
149
discordbot/stocks/government/gtrades.py
Normal file
@@ -0,0 +1,149 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from discordbot import gst_imgur
|
||||
from matplotlib import pyplot as plt
|
||||
import matplotlib.dates as mdates
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
|
||||
|
||||
async def gtrades_command(
|
||||
ctx, ticker="", gov_type="", past_transactions_months="", raw=""
|
||||
):
|
||||
"""Displays government trades [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(
|
||||
f"!stocks.gov.gtrades {ticker} {gov_type} {past_transactions_months} {raw}"
|
||||
)
|
||||
|
||||
if past_transactions_months == "":
|
||||
past_transactions_months = 10
|
||||
else:
|
||||
if not past_transactions_months.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
past_transactions_months = float(past_transactions_months)
|
||||
|
||||
if raw == "false" or raw == "False" or raw == "FALSE" or raw == "":
|
||||
raw = False
|
||||
elif raw == "true" or raw == "True" or raw == "TRUE":
|
||||
raw = True
|
||||
else:
|
||||
raise Exception("raw argument has to be true or false")
|
||||
|
||||
if ticker == "":
|
||||
raise Exception("A ticker is required")
|
||||
|
||||
possible_args = ["congress", "senate", "house"]
|
||||
if gov_type == "":
|
||||
gov_type = "congress"
|
||||
elif gov_type not in possible_args:
|
||||
raise Exception(
|
||||
"Enter a valid government argument, options are: congress, senate and house"
|
||||
)
|
||||
|
||||
# Retrieve Data
|
||||
df_gov = quiverquant_model.get_government_trading(gov_type, ticker)
|
||||
|
||||
if df_gov.empty:
|
||||
raise Exception(f"No {gov_type} trading data found")
|
||||
|
||||
# Output Data
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=False)
|
||||
|
||||
start_date = datetime.now() - timedelta(days=past_transactions_months * 30)
|
||||
|
||||
df_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"])
|
||||
|
||||
df_gov = df_gov[df_gov["TransactionDate"] > start_date]
|
||||
|
||||
if df_gov.empty:
|
||||
print(f"No recent {gov_type} trading data found\n")
|
||||
return
|
||||
|
||||
df_gov["min"] = df_gov["Range"].apply(
|
||||
lambda x: x.split("-")[0].strip("$").replace(",", "").strip()
|
||||
)
|
||||
df_gov["max"] = df_gov["Range"].apply(
|
||||
lambda x: x.split("-")[1].replace(",", "").strip().strip("$")
|
||||
if "-" in x
|
||||
else x.strip("$").replace(",", "").split("\n")[0]
|
||||
)
|
||||
|
||||
df_gov["lower"] = df_gov[["min", "max", "Transaction"]].apply(
|
||||
lambda x: int(float(x["min"]))
|
||||
if x["Transaction"] == "Purchase"
|
||||
else -int(float(x["max"])),
|
||||
axis=1,
|
||||
)
|
||||
df_gov["upper"] = df_gov[["min", "max", "Transaction"]].apply(
|
||||
lambda x: int(float(x["max"]))
|
||||
if x["Transaction"] == "Purchase"
|
||||
else -1 * int(float(x["min"])),
|
||||
axis=1,
|
||||
)
|
||||
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=True)
|
||||
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
ax.fill_between(
|
||||
df_gov["TransactionDate"].unique(),
|
||||
df_gov.groupby("TransactionDate")["lower"].sum().values / 1000,
|
||||
df_gov.groupby("TransactionDate")["upper"].sum().values / 1000,
|
||||
)
|
||||
|
||||
ax.set_xlim(
|
||||
[
|
||||
df_gov["TransactionDate"].values[0],
|
||||
df_gov["TransactionDate"].values[-1],
|
||||
]
|
||||
)
|
||||
ax.grid()
|
||||
ax.set_title(f"{gov_type.capitalize()} trading on {ticker}")
|
||||
ax.set_xlabel("Date")
|
||||
ax.set_ylabel("Amount ($1k)")
|
||||
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d"))
|
||||
plt.gcf().autofmt_xdate()
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig("gov_gtrades.png")
|
||||
uploaded_image = gst_imgur.upload_image("gov_gtrades.png", title="something")
|
||||
image_link = uploaded_image.link
|
||||
if cfg.DEBUG:
|
||||
print(f"Image URL: {image_link}")
|
||||
title = "Stocks: [quiverquant.com] Government Trades"
|
||||
if raw:
|
||||
description = df_gov.to_string()
|
||||
embed = discord.Embed(
|
||||
title=title, description=description, colour=cfg.COLOR
|
||||
)
|
||||
else:
|
||||
embed = discord.Embed(title=title, colour=cfg.COLOR)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
embed.set_image(url=image_link)
|
||||
os.remove("gov_gtrades.png")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title="ERROR Stocks: [quiverquant.com] Government Trades",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
81
discordbot/stocks/government/histcont.py
Normal file
81
discordbot/stocks/government/histcont.py
Normal file
@@ -0,0 +1,81 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from discordbot import gst_imgur
|
||||
from matplotlib import pyplot as plt
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
|
||||
|
||||
async def histcont_command(ctx, ticker=""):
|
||||
"""Displays historical quarterly-contracts [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(f"!stocks.gov.histcont {ticker}")
|
||||
|
||||
if ticker == "":
|
||||
raise Exception("A ticker is required")
|
||||
|
||||
# Retrieve Data
|
||||
df_contracts = quiverquant_model.get_government_trading(
|
||||
"quarter-contracts", ticker=ticker
|
||||
)
|
||||
|
||||
if df_contracts.empty:
|
||||
print("No quarterly government contracts found\n")
|
||||
return
|
||||
|
||||
# Output Data
|
||||
amounts = df_contracts.sort_values(by=["Year", "Qtr"])["Amount"].values
|
||||
|
||||
qtr = df_contracts.sort_values(by=["Year", "Qtr"])["Qtr"].values
|
||||
year = df_contracts.sort_values(by=["Year", "Qtr"])["Year"].values
|
||||
|
||||
quarter_ticks = [
|
||||
f"{quarter[0]}" if quarter[1] == 1 else "" for quarter in zip(year, qtr)
|
||||
]
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
ax.plot(np.arange(0, len(amounts)), amounts / 1000, "-*", lw=2, ms=15)
|
||||
|
||||
ax.set_xlim([-0.5, len(amounts) - 0.5])
|
||||
ax.set_xticks(np.arange(0, len(amounts)))
|
||||
ax.set_xticklabels(quarter_ticks)
|
||||
ax.grid()
|
||||
ax.set_title(f"Historical Quarterly Government Contracts for {ticker.upper()}")
|
||||
ax.set_xlabel("Date")
|
||||
ax.set_ylabel("Amount ($1k)")
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig("gov_histcont.png")
|
||||
uploaded_image = gst_imgur.upload_image("gov_histcont.png", title="something")
|
||||
image_link = uploaded_image.link
|
||||
if cfg.DEBUG:
|
||||
print(f"Image URL: {image_link}")
|
||||
title = "Stocks: Historical Quarterly Government Contract " + ticker
|
||||
embed = discord.Embed(title=title, colour=cfg.COLOR)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
embed.set_image(url=image_link)
|
||||
os.remove("gov_histcont.png")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title="ERROR Stocks: Historical Quarterly Government Contract",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
95
discordbot/stocks/government/lastcontracts.py
Normal file
95
discordbot/stocks/government/lastcontracts.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from helpers import pagination
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
|
||||
|
||||
async def lastcontracts_command(ctx, past_transactions_days="", num=""):
|
||||
"""Displays last government contracts [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(f"!stocks.gov.lastcontracts {past_transactions_days} {num}")
|
||||
|
||||
if past_transactions_days == "":
|
||||
past_transactions_days = 2
|
||||
else:
|
||||
if not past_transactions_days.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
past_transactions_days = float(past_transactions_days)
|
||||
|
||||
if num == "":
|
||||
num = 20
|
||||
else:
|
||||
if not num.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
num = int(num)
|
||||
|
||||
df_contracts = quiverquant_model.get_government_trading("contracts")
|
||||
|
||||
if df_contracts.empty:
|
||||
print("No government contracts found\n")
|
||||
return
|
||||
|
||||
df_contracts.sort_values("Date", ascending=False)
|
||||
|
||||
df_contracts["Date"] = pd.to_datetime(df_contracts["Date"])
|
||||
|
||||
df_contracts.drop_duplicates(inplace=True)
|
||||
df_contracts = df_contracts[
|
||||
df_contracts["Date"].isin(
|
||||
df_contracts["Date"].unique()[:past_transactions_days]
|
||||
)
|
||||
]
|
||||
|
||||
df_contracts = df_contracts[
|
||||
["Date", "Ticker", "Amount", "Description", "Agency"]
|
||||
][:num]
|
||||
df_contracts_str = df_contracts.to_string()
|
||||
if len(df_contracts_str) <= 4000:
|
||||
embed = discord.Embed(
|
||||
title="Stocks: [quiverquant.com] Top buy government trading",
|
||||
description="```" + df_contracts_str + "```",
|
||||
colour=cfg.COLOR,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
i = 0
|
||||
str_start = 0
|
||||
str_end = 4000
|
||||
columns = []
|
||||
while i <= len(df_contracts_str) / 4000:
|
||||
columns.append(
|
||||
discord.Embed(
|
||||
title="Stocks: [quiverquant.com] Top buy government trading",
|
||||
description="```" + df_contracts_str[str_start:str_end] + "```",
|
||||
colour=cfg.COLOR,
|
||||
).set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
)
|
||||
str_end = str_start
|
||||
str_start += 4000
|
||||
i += 1
|
||||
|
||||
await pagination(columns, ctx)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title="ERROR Stocks: [quiverquant.com] Top buy government trading",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
145
discordbot/stocks/government/lasttrades.py
Normal file
145
discordbot/stocks/government/lasttrades.py
Normal file
@@ -0,0 +1,145 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from helpers import pagination
|
||||
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
|
||||
|
||||
async def lasttrades_command(
|
||||
ctx, gov_type="", past_transactions_days="", representative=""
|
||||
):
|
||||
"""Displays trades made by the congress/senate/house [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(
|
||||
f"!stocks.gov.lasttrades {gov_type} {past_transactions_days} {representative}"
|
||||
)
|
||||
|
||||
if past_transactions_days == "":
|
||||
past_days = 5
|
||||
else:
|
||||
if not past_transactions_days.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
past_days = int(past_transactions_days)
|
||||
|
||||
possible_args = ["congress", "senate", "house"]
|
||||
if gov_type == "":
|
||||
gov_type = "congress"
|
||||
elif gov_type not in possible_args:
|
||||
raise Exception(
|
||||
"Enter a valid government argument, options are: congress, senate and house"
|
||||
)
|
||||
|
||||
# Retrieve Data
|
||||
df_gov = quiverquant_model.get_government_trading(gov_type)
|
||||
|
||||
# Output Data
|
||||
if df_gov.empty:
|
||||
raise Exception(f"No {gov_type} trading data found")
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=False)
|
||||
|
||||
df_gov = df_gov[
|
||||
df_gov["TransactionDate"].isin(
|
||||
df_gov["TransactionDate"].unique()[:past_days]
|
||||
)
|
||||
]
|
||||
|
||||
if gov_type == "congress":
|
||||
df_gov = df_gov[
|
||||
[
|
||||
"TransactionDate",
|
||||
"Ticker",
|
||||
"Representative",
|
||||
"Transaction",
|
||||
"Range",
|
||||
"House",
|
||||
"ReportDate",
|
||||
]
|
||||
].rename(
|
||||
columns={
|
||||
"TransactionDate": "Transaction Date",
|
||||
"ReportDate": "Report Date",
|
||||
}
|
||||
)
|
||||
else:
|
||||
df_gov = df_gov[
|
||||
[
|
||||
"TransactionDate",
|
||||
"Ticker",
|
||||
"Representative",
|
||||
"Transaction",
|
||||
"Range",
|
||||
]
|
||||
].rename(columns={"TransactionDate": "Transaction Date"})
|
||||
|
||||
if representative:
|
||||
df_gov_rep = df_gov[
|
||||
df_gov["Representative"].str.split().str[0] == representative
|
||||
]
|
||||
|
||||
if df_gov_rep.empty:
|
||||
raise Exception(
|
||||
f"No representative {representative} found in the past {past_days}"
|
||||
f" days. The following are available: "
|
||||
f"{', '.join(df_gov['Representative'].str.split().str[0].unique())}"
|
||||
)
|
||||
else:
|
||||
embed = discord.Embed(
|
||||
title=f"Stocks: [quiverquant.com] Trades by {representative}",
|
||||
description="```" + df_gov_rep.to_string(index=False) + "```",
|
||||
colour=cfg.COLOR,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
df_gov_str = df_gov.to_string(index=False)
|
||||
if len(df_gov_str) <= 4000:
|
||||
embed = discord.Embed(
|
||||
title=f"Stocks: [quiverquant.com] Last transactions for {gov_type.upper()}",
|
||||
description="```" + df_gov_str + "```",
|
||||
colour=cfg.COLOR,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
i = 0
|
||||
str_start = 0
|
||||
str_end = 4000
|
||||
columns = []
|
||||
while i <= len(gov_type) / 4000:
|
||||
columns.append(
|
||||
discord.Embed(
|
||||
title=f"Stocks: [quiverquant.com] Last transactions for {gov_type.upper()}",
|
||||
description="```" + gov_type[str_start:str_end] + "```",
|
||||
colour=cfg.COLOR,
|
||||
).set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
)
|
||||
str_end = str_start
|
||||
str_start += 4000
|
||||
i += 1
|
||||
|
||||
await pagination(columns, ctx)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title=f"ERROR Stocks: [quiverquant.com] Trades by {gov_type.upper()}",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
96
discordbot/stocks/government/lobbying.py
Normal file
96
discordbot/stocks/government/lobbying.py
Normal file
@@ -0,0 +1,96 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from helpers import pagination
|
||||
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
|
||||
|
||||
async def lobbying_command(ctx, ticker="", num=""):
|
||||
"""Displays lobbying details [quiverquant.com]"""
|
||||
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(f"!stocks.gov.lobbying {ticker}")
|
||||
|
||||
if ticker == "":
|
||||
raise Exception("A ticker is required")
|
||||
|
||||
if num == "":
|
||||
num = 10
|
||||
else:
|
||||
if not num.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
num = int(num)
|
||||
|
||||
# Retrieve Data
|
||||
df_lobbying = quiverquant_model.get_government_trading(
|
||||
"corporate-lobbying", ticker=ticker
|
||||
)
|
||||
|
||||
if df_lobbying.empty:
|
||||
print("No corporate lobbying found\n")
|
||||
return
|
||||
|
||||
# Output Data
|
||||
report = ""
|
||||
for _, row in (
|
||||
df_lobbying.sort_values(by=["Date"], ascending=False).head(num).iterrows()
|
||||
):
|
||||
amount = (
|
||||
"$" + str(int(float(row["Amount"])))
|
||||
if row["Amount"] is not None
|
||||
else "N/A"
|
||||
)
|
||||
report += f"{row['Date']}: {row['Client']} {amount}"
|
||||
if row["Amount"] is not None:
|
||||
report += "\t" + row["Specific_Issue"].replace("\n", " ").replace(
|
||||
"\r", ""
|
||||
)
|
||||
report += "\n"
|
||||
|
||||
if len(report) <= 4000:
|
||||
embed = discord.Embed(
|
||||
title=f"Stocks: [quiverquant.com] {ticker.upper()} Lobbying Details",
|
||||
description="```" + report + "```",
|
||||
colour=cfg.COLOR,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
await ctx.send(embed=embed)
|
||||
else:
|
||||
i = 0
|
||||
str_start = 0
|
||||
str_end = 4000
|
||||
columns = []
|
||||
while i <= len(report) / 4000:
|
||||
columns.append(
|
||||
discord.Embed(
|
||||
title=f"Stocks: [quiverquant.com] {ticker.upper()} Lobbying Details",
|
||||
description="```" + report[str_start:str_end] + "```",
|
||||
colour=cfg.COLOR,
|
||||
).set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
)
|
||||
str_end = str_start
|
||||
str_start += 4000
|
||||
i += 1
|
||||
|
||||
await pagination(columns, ctx)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title=f"ERROR Stocks: [quiverquant.com] {ticker.upper()} Lobbying Details",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
136
discordbot/stocks/government/qtrcontracts.py
Normal file
136
discordbot/stocks/government/qtrcontracts.py
Normal file
@@ -0,0 +1,136 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from discordbot import gst_imgur
|
||||
from matplotlib import pyplot as plt
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
|
||||
|
||||
async def qtrcontracts_command(ctx, num="", analysis=""):
|
||||
"""Displays a look at government contracts [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(f"!stocks.gov.qtrcontracts {num} {analysis}")
|
||||
|
||||
if num == "":
|
||||
num = 20
|
||||
else:
|
||||
if not num.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
num = int(num)
|
||||
|
||||
possible_args = ["total", "upmom", "downmom"]
|
||||
if analysis == "":
|
||||
analysis = "total"
|
||||
elif analysis not in possible_args:
|
||||
raise Exception(
|
||||
"Enter a valid analysis argument, options are: total, upmom and downmom"
|
||||
)
|
||||
|
||||
# Retrieve Data
|
||||
df_contracts = quiverquant_model.get_government_trading("quarter-contracts")
|
||||
|
||||
if df_contracts.empty:
|
||||
raise Exception("No quarterly government contracts found")
|
||||
|
||||
tickers = quiverquant_model.analyze_qtr_contracts(analysis, num)
|
||||
|
||||
# Output Data
|
||||
if analysis in {"upmom", "downmom"}:
|
||||
description = tickers.to_string()
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
max_amount = 0
|
||||
quarter_ticks = []
|
||||
for symbol in tickers:
|
||||
amounts = (
|
||||
df_contracts[df_contracts["Ticker"] == symbol]
|
||||
.sort_values(by=["Year", "Qtr"])["Amount"]
|
||||
.values
|
||||
)
|
||||
|
||||
qtr = (
|
||||
df_contracts[df_contracts["Ticker"] == symbol]
|
||||
.sort_values(by=["Year", "Qtr"])["Qtr"]
|
||||
.values
|
||||
)
|
||||
year = (
|
||||
df_contracts[df_contracts["Ticker"] == symbol]
|
||||
.sort_values(by=["Year", "Qtr"])["Year"]
|
||||
.values
|
||||
)
|
||||
|
||||
ax.plot(
|
||||
np.arange(0, len(amounts)), amounts / 1_000_000, "-*", lw=2, ms=15
|
||||
)
|
||||
|
||||
if len(amounts) > max_amount:
|
||||
max_amount = len(amounts)
|
||||
quarter_ticks = [
|
||||
f"{quarter[0]} - Q{quarter[1]} " for quarter in zip(year, qtr)
|
||||
]
|
||||
|
||||
ax.set_xlim([-0.5, max_amount - 0.5])
|
||||
ax.set_xticks(np.arange(0, max_amount))
|
||||
ax.set_xticklabels(quarter_ticks)
|
||||
ax.grid()
|
||||
ax.legend(tickers)
|
||||
titles = {
|
||||
"upmom": "Highest increasing quarterly Government Contracts",
|
||||
"downmom": "Highest decreasing quarterly Government Contracts",
|
||||
}
|
||||
ax.set_title(titles[analysis])
|
||||
ax.set_xlabel("Date")
|
||||
ax.set_ylabel("Amount ($1M)")
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig("gov_qtrcontracts.png")
|
||||
uploaded_image = gst_imgur.upload_image(
|
||||
"gov_qtrcontracts.png", title="something"
|
||||
)
|
||||
image_link = uploaded_image.link
|
||||
if cfg.DEBUG:
|
||||
print(f"Image URL: {image_link}")
|
||||
title = "Stocks: [quiverquant.com] Government contracts"
|
||||
embed = discord.Embed(
|
||||
title=title, description=description, colour=cfg.COLOR
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
embed.set_image(url=image_link)
|
||||
os.remove("gov_qtrcontracts.png")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
elif analysis == "total":
|
||||
description = tickers.to_string()
|
||||
embed = discord.Embed(
|
||||
title="Stocks: [quiverquant.com] Government contracts",
|
||||
description=description,
|
||||
colour=cfg.COLOR,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title="ERROR Stocks: [quiverquant.com] Government contracts",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
149
discordbot/stocks/government/topbuys.py
Normal file
149
discordbot/stocks/government/topbuys.py
Normal file
@@ -0,0 +1,149 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from discordbot import gst_imgur
|
||||
from datetime import datetime, timedelta
|
||||
from matplotlib import pyplot as plt
|
||||
import os
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
|
||||
|
||||
async def topbuys_command(
|
||||
ctx, gov_type="", past_transactions_months="", num="", raw=""
|
||||
):
|
||||
"""Displays most purchased stocks by the congress/senate/house [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(
|
||||
f"!stocks.gov.topbuys {gov_type} {past_transactions_months} {num} {raw}"
|
||||
)
|
||||
|
||||
if past_transactions_months == "":
|
||||
past_transactions_months = 5
|
||||
else:
|
||||
if not past_transactions_months.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
past_transactions_months = int(past_transactions_months)
|
||||
|
||||
if num == "":
|
||||
num = 10
|
||||
else:
|
||||
if not num.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
num = int(num)
|
||||
|
||||
if raw == "false" or raw == "False" or raw == "FALSE" or raw == "":
|
||||
raw = False
|
||||
elif raw == "true" or raw == "True" or raw == "TRUE":
|
||||
raw = True
|
||||
else:
|
||||
raise Exception("raw argument has to be true or false")
|
||||
|
||||
possible_args = ["congress", "senate", "house"]
|
||||
if gov_type == "":
|
||||
gov_type = "congress"
|
||||
elif gov_type not in possible_args:
|
||||
raise Exception(
|
||||
"Enter a valid government argument, options are: congress, senate and house"
|
||||
)
|
||||
|
||||
# Retrieve Data
|
||||
df_gov = quiverquant_model.get_government_trading(gov_type)
|
||||
|
||||
if df_gov.empty:
|
||||
print(f"No {gov_type} trading data found\n")
|
||||
return
|
||||
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=False)
|
||||
start_date = datetime.now() - timedelta(days=past_transactions_months * 30)
|
||||
|
||||
df_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"])
|
||||
|
||||
df_gov = df_gov[df_gov["TransactionDate"] > start_date].dropna()
|
||||
# Catch bug where error shown for purchase of >5,000,000
|
||||
df_gov["Range"] = df_gov["Range"].apply(
|
||||
lambda x: "$5,000,001-$5,000,001" if x == ">$5,000,000" else x
|
||||
)
|
||||
df_gov["min"] = df_gov["Range"].apply(
|
||||
lambda x: x.split("-")[0].strip("$").replace(",", "").strip()
|
||||
)
|
||||
df_gov["max"] = df_gov["Range"].apply(
|
||||
lambda x: x.split("-")[1].replace(",", "").strip().strip("$")
|
||||
if "-" in x
|
||||
else x.strip("$").replace(",", "")
|
||||
)
|
||||
df_gov["lower"] = df_gov[["min", "max", "Transaction"]].apply(
|
||||
lambda x: float(x["min"])
|
||||
if x["Transaction"] == "Purchase"
|
||||
else -float(x["max"]),
|
||||
axis=1,
|
||||
)
|
||||
df_gov["upper"] = df_gov[["min", "max", "Transaction"]].apply(
|
||||
lambda x: float(x["max"])
|
||||
if x["Transaction"] == "Purchase"
|
||||
else -float(x["min"]),
|
||||
axis=1,
|
||||
)
|
||||
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=True)
|
||||
if raw:
|
||||
df = pd.DataFrame(
|
||||
df_gov.groupby("Ticker")["upper"]
|
||||
.sum()
|
||||
.div(1000)
|
||||
.sort_values(ascending=False)
|
||||
.head(n=num)
|
||||
)
|
||||
description = "```" + df.to_string() + "```"
|
||||
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values(
|
||||
ascending=False
|
||||
).head(n=num).plot(kind="bar", rot=0, ax=ax)
|
||||
|
||||
ax.set_ylabel("Amount [1k $]")
|
||||
ax.set_title(
|
||||
f"Top {num} purchased stocks over last {past_transactions_months} "
|
||||
f"months (upper bound) for {gov_type.upper()}"
|
||||
)
|
||||
plt.gcf().axes[0].yaxis.get_major_formatter().set_scientific(False)
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig("gov_topbuys.png")
|
||||
uploaded_image = gst_imgur.upload_image("gov_topbuys.png", title="something")
|
||||
image_link = uploaded_image.link
|
||||
if cfg.DEBUG:
|
||||
print(f"Image URL: {image_link}")
|
||||
title = f"Stocks: [quiverquant.com] Top purchases for {gov_type.upper()}"
|
||||
if raw:
|
||||
embed = discord.Embed(
|
||||
title=title, description=description, colour=cfg.COLOR
|
||||
)
|
||||
else:
|
||||
embed = discord.Embed(title=title, colour=cfg.COLOR)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
embed.set_image(url=image_link)
|
||||
os.remove("gov_topbuys.png")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title=f"ERROR Stocks: [quiverquant.com] Top purchases for {gov_type.upper()}",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
85
discordbot/stocks/government/toplobbying.py
Normal file
85
discordbot/stocks/government/toplobbying.py
Normal file
@@ -0,0 +1,85 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from discordbot import gst_imgur
|
||||
from matplotlib import pyplot as plt
|
||||
import os
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
|
||||
|
||||
async def toplobbying_command(ctx, num="", raw=""):
|
||||
"""Displays top lobbying firms [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(f"!stocks.gov.toplobbying {num} {raw}")
|
||||
|
||||
if num == "":
|
||||
num = 10
|
||||
else:
|
||||
if not num.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
num = int(num)
|
||||
|
||||
if raw == "false" or raw == "False" or raw == "FALSE" or raw == "":
|
||||
raw = False
|
||||
elif raw == "true" or raw == "True" or raw == "TRUE":
|
||||
raw = True
|
||||
else:
|
||||
raise Exception("raw argument has to be true or false")
|
||||
|
||||
# Retrieve Data
|
||||
df_lobbying = quiverquant_model.get_government_trading("corporate-lobbying")
|
||||
|
||||
if df_lobbying.empty:
|
||||
raise Exception("No corporate lobbying found")
|
||||
|
||||
df_lobbying["Amount"] = df_lobbying.Amount.astype(float).fillna(0) / 100_000
|
||||
|
||||
lobbying_by_ticker = pd.DataFrame(
|
||||
df_lobbying.groupby("Ticker")["Amount"].agg("sum")
|
||||
).sort_values(by="Amount", ascending=False)
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
lobbying_by_ticker.head(num).plot(kind="bar", ax=ax)
|
||||
ax.set_xlabel("Ticker")
|
||||
ax.set_ylabel("Total Amount ($100k)")
|
||||
ax.set_title(f"Corporate Lobbying Spent since {df_lobbying['Date'].min()}")
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig("ta_toplobbying.png")
|
||||
uploaded_image = gst_imgur.upload_image("ta_toplobbying.png", title="something")
|
||||
image_link = uploaded_image.link
|
||||
if cfg.DEBUG:
|
||||
print(f"Image URL: {image_link}")
|
||||
title = "Stocks: [quiverquant.com] Top Lobbying Firms"
|
||||
if raw:
|
||||
description = lobbying_by_ticker.head(num).to_string()
|
||||
embed = discord.Embed(
|
||||
title=title, description=description, colour=cfg.COLOR
|
||||
)
|
||||
else:
|
||||
embed = discord.Embed(title=title, colour=cfg.COLOR)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
embed.set_image(url=image_link)
|
||||
os.remove("ta_toplobbying.png")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title="ERROR Stocks: [quiverquant.com] Top Lobbying Firms",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
162
discordbot/stocks/government/topsells.py
Normal file
162
discordbot/stocks/government/topsells.py
Normal file
@@ -0,0 +1,162 @@
|
||||
import discord
|
||||
import config_discordbot as cfg
|
||||
from discordbot import gst_imgur
|
||||
from datetime import datetime, timedelta
|
||||
from matplotlib import pyplot as plt
|
||||
import os
|
||||
import pandas as pd
|
||||
|
||||
from gamestonk_terminal.config_plot import PLOT_DPI
|
||||
from gamestonk_terminal.stocks.government import quiverquant_model
|
||||
from gamestonk_terminal.helper_funcs import plot_autoscale
|
||||
|
||||
|
||||
async def topsells_command(
|
||||
ctx, gov_type="", past_transactions_months="", num="", raw=""
|
||||
):
|
||||
"""Displays most sold stocks by the congress/senate/house [quiverquant.com]"""
|
||||
try:
|
||||
# Debug user input
|
||||
if cfg.DEBUG:
|
||||
print(
|
||||
f"!stocks.gov.topsells {gov_type} {past_transactions_months} {num} {raw}"
|
||||
)
|
||||
|
||||
if past_transactions_months == "":
|
||||
past_transactions_months = 5
|
||||
else:
|
||||
if not past_transactions_months.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
past_transactions_months = int(past_transactions_months)
|
||||
|
||||
if num == "":
|
||||
num = 10
|
||||
else:
|
||||
if not num.lstrip("-").isnumeric():
|
||||
raise Exception("Number has to be an integer")
|
||||
num = int(num)
|
||||
|
||||
if raw == "false" or raw == "False" or raw == "FALSE" or raw == "":
|
||||
raw = False
|
||||
elif raw == "true" or raw == "True" or raw == "TRUE":
|
||||
raw = True
|
||||
else:
|
||||
raise Exception("raw argument has to be true or false")
|
||||
|
||||
possible_args = ["congress", "senate", "house"]
|
||||
if gov_type == "":
|
||||
gov_type = "congress"
|
||||
elif gov_type not in possible_args:
|
||||
raise Exception(
|
||||
"Enter a valid government argument, options are: congress, senate and house"
|
||||
)
|
||||
|
||||
# Retrieve Data
|
||||
df_gov = quiverquant_model.get_government_trading(gov_type)
|
||||
|
||||
# Output Data
|
||||
if df_gov.empty:
|
||||
raise Exception(f"No {gov_type} trading data found\n")
|
||||
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=False)
|
||||
|
||||
start_date = datetime.now() - timedelta(days=past_transactions_months * 30)
|
||||
|
||||
df_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"])
|
||||
|
||||
df_gov = df_gov[df_gov["TransactionDate"] > start_date].dropna()
|
||||
|
||||
df_gov["Range"] = df_gov["Range"].apply(
|
||||
lambda x: "$5,000,001-$5,000,001" if x == ">$5,000,000" else x
|
||||
)
|
||||
|
||||
df_gov["min"] = df_gov["Range"].apply(
|
||||
lambda x: x.split("-")[0]
|
||||
.strip("$")
|
||||
.replace(",", "")
|
||||
.strip()
|
||||
.replace(">$", "")
|
||||
.strip()
|
||||
)
|
||||
df_gov["max"] = df_gov["Range"].apply(
|
||||
lambda x: x.split("-")[1]
|
||||
.replace(",", "")
|
||||
.strip()
|
||||
.strip("$")
|
||||
.replace(">$", "")
|
||||
.strip()
|
||||
if "-" in x
|
||||
else x.strip("$").replace(",", "").replace(">$", "").strip()
|
||||
)
|
||||
|
||||
df_gov["lower"] = df_gov[["min", "max", "Transaction"]].apply(
|
||||
lambda x: float(x["min"])
|
||||
if x["Transaction"] == "Purchase"
|
||||
else -float(x["max"]),
|
||||
axis=1,
|
||||
)
|
||||
df_gov["upper"] = df_gov[["min", "max", "Transaction"]].apply(
|
||||
lambda x: float(x["max"])
|
||||
if x["Transaction"] == "Purchase"
|
||||
else -float(x["min"]),
|
||||
axis=1,
|
||||
)
|
||||
|
||||
df_gov = df_gov.sort_values("TransactionDate", ascending=True)
|
||||
if raw:
|
||||
df = pd.DataFrame(
|
||||
df_gov.groupby("Ticker")["upper"]
|
||||
.sum()
|
||||
.div(1000)
|
||||
.sort_values(ascending=True)
|
||||
.abs()
|
||||
.head(n=num)
|
||||
)
|
||||
description = "```" + df.to_string() + "```"
|
||||
|
||||
fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI)
|
||||
|
||||
df_gov.groupby("Ticker")["upper"].sum().div(1000).sort_values().abs().head(
|
||||
n=num
|
||||
).plot(kind="bar", rot=0, ax=ax)
|
||||
ax.set_ylabel("Amount ($1k)")
|
||||
ax.set_title(
|
||||
f"{num} most sold stocks over last {past_transactions_months} months"
|
||||
f" (upper bound) for {gov_type}"
|
||||
)
|
||||
plt.gcf().axes[0].yaxis.get_major_formatter().set_scientific(False)
|
||||
fig.tight_layout()
|
||||
|
||||
plt.savefig("gov_topsells.png")
|
||||
uploaded_image = gst_imgur.upload_image("gov_topsells.png", title="something")
|
||||
image_link = uploaded_image.link
|
||||
if cfg.DEBUG:
|
||||
print(f"Image URL: {image_link}")
|
||||
title = f"Stocks: [quiverquant.com] Top sells for {gov_type.upper()}"
|
||||
if raw:
|
||||
embed = discord.Embed(
|
||||
title=title, description=description, colour=cfg.COLOR
|
||||
)
|
||||
else:
|
||||
embed = discord.Embed(title=title, colour=cfg.COLOR)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
embed.set_image(url=image_link)
|
||||
os.remove("gov_topsells.png")
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
except Exception as e:
|
||||
embed = discord.Embed(
|
||||
title=f"ERROR Stocks: [quiverquant.com] Top sells for {gov_type.upper()}",
|
||||
colour=cfg.COLOR,
|
||||
description=e,
|
||||
)
|
||||
embed.set_author(
|
||||
name=cfg.AUTHOR_NAME,
|
||||
icon_url=cfg.AUTHOR_ICON_URL,
|
||||
)
|
||||
|
||||
await ctx.send(embed=embed)
|
||||
Reference in New Issue
Block a user