mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-29 05:21:48 +00:00
add government menu, in particular congress data
This commit is contained in:
136
gamestonk_terminal/government/gov_controller.py
Normal file
136
gamestonk_terminal/government/gov_controller.py
Normal 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
|
||||
36
gamestonk_terminal/government/quiverquant_model.py
Normal file
36
gamestonk_terminal/government/quiverquant_model.py
Normal 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()
|
||||
392
gamestonk_terminal/government/quiverquant_view.py
Normal file
392
gamestonk_terminal/government/quiverquant_view.py
Normal 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")
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user