add government menu, in particular congress data

This commit is contained in:
didier
2021-05-06 00:10:09 +01:00
parent eb2b0d766b
commit a0b533d91c
5 changed files with 570 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
"""Government Controller Module"""
__docformat__ = "numpy"
import argparse
from typing import List
from datetime import datetime
import pandas as pd
from matplotlib import pyplot as plt
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal.government import quiverquant_view
class GovController:
"""Gov Controller class"""
# Command choices
CHOICES = [
"help",
"q",
"quit",
"last_congress",
"buy_congress",
"sell_congress",
"congress",
]
def __init__(
self,
ticker: str,
):
"""Constructor"""
self.ticker = ticker
self.gov_parser = argparse.ArgumentParser(add_help=False, prog="gov")
self.gov_parser.add_argument(
"cmd",
choices=self.CHOICES,
)
@staticmethod
def print_help(self):
"""Print help"""
print("\nExploratory Data Analysis:")
print(" help show this comparison analysis menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print("")
print("Explore:")
print(" last_congress last congress trading")
print(" buy_congress top buy congress tickers")
print(" sell_congress top sell congress tickers")
print("")
if self.ticker:
print(f"Ticker: {self.ticker}")
print(" congress congress trades on the ticker")
print("")
return
def switch(self, an_input: str):
"""Process and dispatch input
Returns
-------
True, False or None
False - quit the menu
True - quit the program
None - continue in the menu
"""
(known_args, other_args) = self.gov_parser.parse_known_args(an_input.split())
return getattr(
self, "call_" + known_args.cmd, lambda: "Command not recognized!"
)(other_args)
def call_help(self, _):
"""Process Help command"""
self.print_help(self)
def call_q(self, _):
"""Process Q command - quit the menu"""
return False
def call_quit(self, _):
"""Process Quit command - quit the program"""
return True
def call_last_congress(self, other_args: List[str]):
"""Process last_congress command"""
quiverquant_view.last_congress(other_args)
def call_buy_congress(self, other_args: List[str]):
"""Process buy_congress command"""
quiverquant_view.buy_congress(other_args)
def call_sell_congress(self, other_args: List[str]):
"""Process sell_congress command"""
quiverquant_view.sell_congress(other_args)
def call_congress(self, other_args: List[str]):
"""Process congress command"""
quiverquant_view.congress(other_args, self.ticker)
def menu(ticker: str):
"""Government Menu"""
gov_controller = GovController(ticker)
gov_controller.call_help(None)
while True:
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
completer = NestedCompleter.from_nested_dict(
{c: None for c in gov_controller.CHOICES}
)
an_input = session.prompt(
f"{get_flair()} (gov)> ",
completer=completer,
)
else:
an_input = input(f"{get_flair()} (gov)> ")
try:
plt.close("all")
process_input = gov_controller.switch(an_input)
if process_input is not None:
return process_input
except SystemExit:
print("The command selected doesn't exist\n")
continue

View File

@@ -0,0 +1,36 @@
import requests
import pandas as pd
# Provided by Quiverquant guys to GST users
API_QUIVERQUANT_KEY = "5cd2a65e96d0486efbe926a7cdbc1e8d8ab6c7b3"
def get_congress_trading(ticker: str = "") -> pd.DataFrame:
"""Returns the most recent transactions by members of U.S. Congress
Parameters
----------
ticker : str
Ticker to get congress trading data from
Returns
-------
pd.DataFrame
Most recent transactions by members of U.S. Congress
"""
if ticker:
url = f"https://api.quiverquant.com/beta/historical/congresstrading/{ticker}"
else:
url = "https://api.quiverquant.com/beta/live/congresstrading"
headers = {
"accept": "application/json",
"X-CSRFToken": "TyTJwjuEC7VV7mOqZ622haRaaUr0x0Ng4nrwSRFKQs7vdoBcJlK9qjAS69ghzhFu",
"Authorization": f"Token {API_QUIVERQUANT_KEY}",
}
response = requests.get(url, headers=headers)
if response.status_code == 200:
return pd.DataFrame(response.json())
return pd.DataFrame()

View File

@@ -0,0 +1,392 @@
import argparse
from typing import List
import pandas as pd
from datetime import datetime, timedelta
from gamestonk_terminal.government import quiverquant_model
from matplotlib import pyplot as plt
from gamestonk_terminal.helper_funcs import (
parse_known_args_and_warn,
check_positive,
plot_autoscale,
)
from gamestonk_terminal.config_plot import PLOT_DPI
from gamestonk_terminal import feature_flags as gtff
def last_congress(other_args: List[str]):
"""Last congress trading
Parameters
----------
other_args : List[str]
Command line arguments to be processed with argparse
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="last_congress",
description="""
Last congress trading. [Source: www.quiverquant.com]
""",
)
parser.add_argument(
"-p",
"--past_transactions_days",
action="store",
dest="past_transactions_days",
type=check_positive,
default=3,
help="Past transaction days",
)
try:
if other_args:
if "-" not in other_args[0]:
other_args.insert(0, "-p")
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_congress = quiverquant_model.get_congress_trading()
if df_congress.empty:
print("No congress trading data found\n")
return
df_congress = df_congress.sort_values("TransactionDate", ascending=False)
df_congress = df_congress[
df_congress["TransactionDate"].isin(
df_congress["TransactionDate"].unique()[
: ns_parser.past_transactions_days
]
)
]
df_congress = df_congress[
[
"TransactionDate",
"Ticker",
"Representative",
"Transaction",
"House",
"Range",
"ReportDate",
]
].rename(
columns={"TransactionDate": "Transaction Date", "ReportDate": "Report Date"}
)
print(df_congress.to_string(index=False))
print("")
except Exception as e:
print(e, "\n")
def buy_congress(other_args: List[str]):
"""Top buy congress trading
Parameters
----------
other_args : List[str]
Command line arguments to be processed with argparse
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="buy_congress",
description="""
Top buy congress trading. [Source: www.quiverquant.com]
""",
)
parser.add_argument(
"-p",
"--past_transactions_months",
action="store",
dest="past_transactions_months",
type=check_positive,
default=6,
help="Past transaction months",
)
parser.add_argument(
"-t",
"--top",
action="store",
dest="top_num",
type=check_positive,
default=10,
help="Number of top tickers",
)
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_congress = quiverquant_model.get_congress_trading()
if df_congress.empty:
print("No congress trading data found\n")
return
df_congress = df_congress.sort_values("TransactionDate", ascending=False)
start_date = datetime.now() - timedelta(
days=ns_parser.past_transactions_months * 30
)
df_congress["TransactionDate"] = pd.to_datetime(df_congress["TransactionDate"])
df_congress = df_congress[df_congress["TransactionDate"] > start_date].dropna()
df_congress["min"] = df_congress["Range"].apply(
lambda x: x.split("-")[0].strip("$").replace(",", "").strip()
)
df_congress["max"] = df_congress["Range"].apply(
lambda x: x.split("-")[1].replace(",", "").strip().strip("$")
if "-" in x
else x.strip("$").replace(",", "")
)
df_congress["lower"] = df_congress[["min", "max", "Transaction"]].apply(
lambda x: float(x["min"])
if x["Transaction"] == "Purchase"
else -float(x["max"]),
axis=1,
)
df_congress["upper"] = df_congress[["min", "max", "Transaction"]].apply(
lambda x: float(x["max"])
if x["Transaction"] == "Purchase"
else -float(x["min"]),
axis=1,
)
df_congress = df_congress.sort_values("TransactionDate", ascending=True)
print(
f"Top {ns_parser.top_num} most sold stocks since last {ns_parser.past_transactions_months} months in the worst case scenario"
)
print(
df_congress.groupby("Ticker")["lower"]
.sum()
.sort_values()
.abs()
.head(n=ns_parser.top_num)
.to_string(header=False)
)
print("")
except Exception as e:
print(e, "\n")
def sell_congress(other_args: List[str]):
"""Top sell congress trading
Parameters
----------
other_args : List[str]
Command line arguments to be processed with argparse
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="sell_congress",
description="""
Top sell congress trading. [Source: www.quiverquant.com]
""",
)
parser.add_argument(
"-p",
"--past_transactions_months",
action="store",
dest="past_transactions_months",
type=check_positive,
default=6,
help="Past transaction months",
)
parser.add_argument(
"-t",
"--top",
action="store",
dest="top_num",
type=check_positive,
default=10,
help="Number of top tickers",
)
try:
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_congress = quiverquant_model.get_congress_trading()
if df_congress.empty:
print("No congress trading data found\n")
return
df_congress = df_congress.sort_values("TransactionDate", ascending=False)
start_date = datetime.now() - timedelta(
days=ns_parser.past_transactions_months * 30
)
df_congress["TransactionDate"] = pd.to_datetime(df_congress["TransactionDate"])
df_congress = df_congress[df_congress["TransactionDate"] > start_date].dropna()
df_congress["min"] = df_congress["Range"].apply(
lambda x: x.split("-")[0].strip("$").replace(",", "").strip()
)
df_congress["max"] = df_congress["Range"].apply(
lambda x: x.split("-")[1].replace(",", "").strip().strip("$")
if "-" in x
else x.strip("$").replace(",", "")
)
df_congress["lower"] = df_congress[["min", "max", "Transaction"]].apply(
lambda x: float(x["min"])
if x["Transaction"] == "Purchase"
else -float(x["max"]),
axis=1,
)
df_congress["upper"] = df_congress[["min", "max", "Transaction"]].apply(
lambda x: float(x["max"])
if x["Transaction"] == "Purchase"
else -float(x["min"]),
axis=1,
)
df_congress = df_congress.sort_values("TransactionDate", ascending=True)
print(
f"Top {ns_parser.top_num} most sold stocks since last {ns_parser.past_transactions_months} months in the worst case scenario"
)
print(
df_congress.groupby("Ticker")["upper"]
.sum()
.sort_values(ascending=False)
.head(n=ns_parser.top_num)
.to_string(header=False)
)
print("")
except Exception as e:
print(e, "\n")
def plot_congress(congress: pd.DataFrame, ticker: str):
"""Plot congress trading
Parameters
----------
other_args : List[str]
Command line arguments to be processed with argparse
ticker: str
Ticker to plot congress trading
"""
plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI)
plt.gca().fill_between(
congress["TransactionDate"].unique(),
congress.groupby("TransactionDate")["lower"].sum().values / 1000,
congress.groupby("TransactionDate")["upper"].sum().values / 1000,
)
plt.xlim(
[congress["TransactionDate"].values[0], congress["TransactionDate"].values[-1]]
)
plt.grid()
plt.title(f"Congress trading on {ticker}")
plt.xlabel("Date")
plt.ylabel("Amount [1k $]")
if gtff.USE_ION:
plt.ion()
plt.show()
def congress(other_args: List[str], ticker: str):
"""Congress trading
Parameters
----------
other_args : List[str]
Command line arguments to be processed with argparse
ticker: str
Ticker to get congress trading data from
"""
parser = argparse.ArgumentParser(
add_help=False,
prog="congress",
description="""
Congress trading. [Source: www.quiverquant.com]
""",
)
parser.add_argument(
"-p",
"--past_transactions_months",
action="store",
dest="past_transactions_months",
type=check_positive,
default=6,
help="Past transaction months",
)
try:
if other_args:
if "-" not in other_args[0]:
other_args.insert(0, "-p")
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
df_congress = quiverquant_model.get_congress_trading(ticker)
if df_congress.empty:
print("No congress trading data found\n")
return
df_congress = df_congress.sort_values("TransactionDate", ascending=False)
start_date = datetime.now() - timedelta(
days=ns_parser.past_transactions_months * 30
)
df_congress["TransactionDate"] = pd.to_datetime(df_congress["TransactionDate"])
df_congress = df_congress[df_congress["TransactionDate"] > start_date]
df_congress["min"] = df_congress["Range"].apply(
lambda x: x.split("-")[0].strip("$").replace(",", "").strip()
)
df_congress["max"] = df_congress["Range"].apply(
lambda x: x.split("-")[1].replace(",", "").strip().strip("$")
if "-" in x
else x.strip("$").replace(",", "")
)
df_congress["lower"] = df_congress[["min", "max", "Transaction"]].apply(
lambda x: int(x["min"])
if x["Transaction"] == "Purchase"
else -int(x["max"]),
axis=1,
)
df_congress["upper"] = df_congress[["min", "max", "Transaction"]].apply(
lambda x: int(x["max"])
if x["Transaction"] == "Purchase"
else -int(x["min"]),
axis=1,
)
df_congress = df_congress.sort_values("TransactionDate", ascending=True)
plot_congress(df_congress, ticker)
print("")
except Exception as e:
print(e, "\n")

View File

@@ -65,6 +65,7 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open):
print(
" > po portfolio optimization, \t optimal portfolio weights from pyportfolioopt"
)
print(" > gov government menu, \t\t congress, senate, house trading")
print(" > fx forex menu, \t\t\t forex support through Oanda")
print(" > rc resource collection, \t\t e.g. hf letters")

View File

@@ -43,6 +43,7 @@ from gamestonk_terminal.forex import fx_controller
from gamestonk_terminal.backtesting import bt_controller
from gamestonk_terminal.resource_collection import rc_controller
from gamestonk_terminal.research import res_controller
from gamestonk_terminal.government import gov_controller
# pylint: disable=too-many-statements,too-many-branches
@@ -99,6 +100,7 @@ def main():
"po",
"fx",
"rc",
"gov",
]
menu_parser.add_argument("opt", choices=choices)
@@ -378,6 +380,9 @@ def main():
elif ns_known_args.opt == "rc":
b_quit = rc_controller.menu()
elif ns_known_args.opt == "gov":
b_quit = gov_controller.menu(s_ticker)
else:
print("Shouldn't see this command!")
continue