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:
northern-64bit
2021-11-19 21:21:47 +01:00
committed by GitHub
parent 203133b8b9
commit c528419aad
12 changed files with 1520 additions and 0 deletions

View File

@@ -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()

View 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)

View 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))

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)

View 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)