diff --git a/gamestonk_terminal/government/gov_controller.py b/gamestonk_terminal/government/gov_controller.py index 5084cefb981..9e0e8c0bf35 100644 --- a/gamestonk_terminal/government/gov_controller.py +++ b/gamestonk_terminal/government/gov_controller.py @@ -23,6 +23,14 @@ class GovController: "buy_congress", "sell_congress", "congress", + "last_senate", + "buy_senate", + "sell_senate", + "senate", + "last_house", + "buy_house", + "sell_house", + "house", ] def __init__( @@ -50,10 +58,18 @@ class GovController: print(" last_congress last congress trading") print(" buy_congress top buy congress tickers") print(" sell_congress top sell congress tickers") + print(" last_senate last senate trading") + print(" buy_senate top buy senate tickers") + print(" sell_senate top sell senate tickers") + print(" last_house last house trading") + print(" buy_house top buy house tickers") + print(" sell_house top sell house tickers") print("") if self.ticker: print(f"Ticker: {self.ticker}") print(" congress congress trades on the ticker") + print(" senate senate trades on the ticker") + print(" house house trades on the ticker") print("") return @@ -87,19 +103,51 @@ class GovController: def call_last_congress(self, other_args: List[str]): """Process last_congress command""" - quiverquant_view.last_congress(other_args) + quiverquant_view.last_government(other_args, "congress") def call_buy_congress(self, other_args: List[str]): """Process buy_congress command""" - quiverquant_view.buy_congress(other_args) + quiverquant_view.buy_government(other_args, "congress") def call_sell_congress(self, other_args: List[str]): """Process sell_congress command""" - quiverquant_view.sell_congress(other_args) + quiverquant_view.sell_government(other_args, "congress") def call_congress(self, other_args: List[str]): """Process congress command""" - quiverquant_view.congress(other_args, self.ticker) + quiverquant_view.government(other_args, self.ticker, "congress") + + def call_last_senate(self, other_args: List[str]): + """Process last_senate command""" + quiverquant_view.last_government(other_args, "senate") + + def call_buy_senate(self, other_args: List[str]): + """Process buy_senate command""" + quiverquant_view.buy_government(other_args, "senate") + + def call_sell_senate(self, other_args: List[str]): + """Process sell_senate command""" + quiverquant_view.sell_government(other_args, "senate") + + def call_senate(self, other_args: List[str]): + """Process senate command""" + quiverquant_view.government(other_args, self.ticker, "senate") + + def call_last_house(self, other_args: List[str]): + """Process last_house command""" + quiverquant_view.last_government(other_args, "house") + + def call_buy_house(self, other_args: List[str]): + """Process buy_house command""" + quiverquant_view.buy_government(other_args, "house") + + def call_sell_house(self, other_args: List[str]): + """Process sell_house command""" + quiverquant_view.sell_government(other_args, "house") + + def call_house(self, other_args: List[str]): + """Process house command""" + quiverquant_view.government(other_args, self.ticker, "house") def menu(ticker: str): diff --git a/gamestonk_terminal/government/quiverquant_model.py b/gamestonk_terminal/government/quiverquant_model.py index 3bf5527108a..597b432352e 100644 --- a/gamestonk_terminal/government/quiverquant_model.py +++ b/gamestonk_terminal/government/quiverquant_model.py @@ -5,11 +5,13 @@ import pandas as pd API_QUIVERQUANT_KEY = "5cd2a65e96d0486efbe926a7cdbc1e8d8ab6c7b3" -def get_congress_trading(ticker: str = "") -> pd.DataFrame: - """Returns the most recent transactions by members of U.S. Congress +def get_government_trading(type: str, ticker: str = "") -> pd.DataFrame: + """Returns the most recent transactions by members of government Parameters ---------- + type: str + Type of government data between: Congress, Senate and House ticker : str Ticker to get congress trading data from @@ -19,10 +21,28 @@ def get_congress_trading(ticker: str = "") -> pd.DataFrame: Most recent transactions by members of U.S. Congress """ - if ticker: - url = f"https://api.quiverquant.com/beta/historical/congresstrading/{ticker}" + if type == "congress": + if ticker: + url = ( + f"https://api.quiverquant.com/beta/historical/congresstrading/{ticker}" + ) + else: + url = "https://api.quiverquant.com/beta/live/congresstrading" + + elif type == "senate": + if ticker: + url = f"https://api.quiverquant.com/beta/historical/senatetrading/{ticker}" + else: + url = "https://api.quiverquant.com/beta/live/senatetrading" + + elif type == "house": + if ticker: + url = f"https://api.quiverquant.com/beta/historical/housetrading/{ticker}" + else: + url = "https://api.quiverquant.com/beta/live/housetrading" + else: - url = "https://api.quiverquant.com/beta/live/congresstrading" + return pd.DataFrame() headers = { "accept": "application/json", @@ -31,6 +51,8 @@ def get_congress_trading(ticker: str = "") -> pd.DataFrame: } response = requests.get(url, headers=headers) if response.status_code == 200: - return pd.DataFrame(response.json()) + return pd.DataFrame(response.json()).rename( + columns={"Date": "TransactionDate", "Senator": "Representative"} + ) return pd.DataFrame() diff --git a/gamestonk_terminal/government/quiverquant_view.py b/gamestonk_terminal/government/quiverquant_view.py index 88f314fa72e..54c2a7f1aef 100644 --- a/gamestonk_terminal/government/quiverquant_view.py +++ b/gamestonk_terminal/government/quiverquant_view.py @@ -14,20 +14,20 @@ 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 +def last_government(other_args: List[str], type: str): + """Last government trading Parameters ---------- other_args : List[str] Command line arguments to be processed with argparse + type: str + Type of government data between: congress, senate and house """ parser = argparse.ArgumentParser( add_help=False, - prog="last_congress", - description=""" - Last congress trading. [Source: www.quiverquant.com] - """, + prog="last_" + type, + description=f"Last {type} trading. [Source: www.quiverquant.com]", ) parser.add_argument( "-p", @@ -45,7 +45,7 @@ def last_congress(other_args: List[str]): dest="representative", type=str, default="", - help="Congress representative", + help="Representative", ) try: @@ -57,72 +57,83 @@ def last_congress(other_args: List[str]): if not ns_parser: return - df_congress = quiverquant_model.get_congress_trading() + df_gov = quiverquant_model.get_government_trading(type) - if df_congress.empty: - print("No congress trading data found\n") + if df_gov.empty: + print(f"No {type} trading data found\n") return - df_congress = df_congress.sort_values("TransactionDate", ascending=False) + df_gov = df_gov.sort_values("TransactionDate", ascending=False) - df_congress = df_congress[ - df_congress["TransactionDate"].isin( - df_congress["TransactionDate"].unique()[ - : ns_parser.past_transactions_days - ] + df_gov = df_gov[ + df_gov["TransactionDate"].isin( + df_gov["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"} - ) + if 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 ns_parser.representative: - df_congress_rep = df_congress[ - df_congress["Representative"].str.split().str[0] - == ns_parser.representative + df_gov_rep = df_gov[ + df_gov["Representative"].str.split().str[0] == ns_parser.representative ] - if df_congress_rep.empty: + if df_gov_rep.empty: print( f"No representative {ns_parser.representative} found in the past {ns_parser.past_transactions_days}" f" days. The following are available: " - f"{', '.join(df_congress['Representative'].str.split().str[0].unique())}" + f"{', '.join(df_gov['Representative'].str.split().str[0].unique())}" ) else: - print(df_congress_rep.to_string(index=False)) + print(df_gov_rep.to_string(index=False)) else: - print(df_congress.to_string(index=False)) + print(df_gov.to_string(index=False)) print("") except Exception as e: print(e, "\n") -def buy_congress(other_args: List[str]): - """Top buy congress trading +def buy_government(other_args: List[str], type: str): + """Top buy government trading Parameters ---------- other_args : List[str] Command line arguments to be processed with argparse + type: str + Type of government data between: congress, senate and house """ parser = argparse.ArgumentParser( add_help=False, - prog="buy_congress", - description=""" - Top buy congress trading. [Source: www.quiverquant.com] - """, + prog="buy_" + type, + description=f"Top buy {type} trading. [Source: www.quiverquant.com]", ) parser.add_argument( "-p", @@ -148,49 +159,49 @@ def buy_congress(other_args: List[str]): if not ns_parser: return - df_congress = quiverquant_model.get_congress_trading() + df_gov = quiverquant_model.get_government_trading(type) - if df_congress.empty: - print("No congress trading data found\n") + if df_gov.empty: + print(f"No {type} trading data found\n") return - df_congress = df_congress.sort_values("TransactionDate", ascending=False) + df_gov = df_gov.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_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"]) - df_congress = df_congress[df_congress["TransactionDate"] > start_date].dropna() + df_gov = df_gov[df_gov["TransactionDate"] > start_date].dropna() - df_congress["min"] = df_congress["Range"].apply( + df_gov["min"] = df_gov["Range"].apply( lambda x: x.split("-")[0].strip("$").replace(",", "").strip() ) - df_congress["max"] = df_congress["Range"].apply( + df_gov["max"] = df_gov["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( + 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_congress["upper"] = df_congress[["min", "max", "Transaction"]].apply( + 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_congress = df_congress.sort_values("TransactionDate", ascending=True) + df_gov = df_gov.sort_values("TransactionDate", ascending=True) plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) - df_congress.groupby("Ticker")["upper"].sum().sort_values(ascending=False).head( + df_gov.groupby("Ticker")["upper"].sum().sort_values(ascending=False).head( n=ns_parser.top_num ).plot(kind="bar", rot=0) plt.ylabel("Amount [$]") @@ -209,20 +220,20 @@ def buy_congress(other_args: List[str]): print(e, "\n") -def sell_congress(other_args: List[str]): - """Top sell congress trading +def sell_government(other_args: List[str], type: str): + """Top sell government trading Parameters ---------- other_args : List[str] Command line arguments to be processed with argparse + type: str + Type of government data between: congress, senate and house """ parser = argparse.ArgumentParser( add_help=False, - prog="sell_congress", - description=""" - Top sell congress trading. [Source: www.quiverquant.com] - """, + prog="sell_" + type, + description=f"Top sell {type} trading. [Source: www.quiverquant.com]", ) parser.add_argument( "-p", @@ -248,49 +259,49 @@ def sell_congress(other_args: List[str]): if not ns_parser: return - df_congress = quiverquant_model.get_congress_trading() + df_gov = quiverquant_model.get_government_trading(type) - if df_congress.empty: - print("No congress trading data found\n") + if df_gov.empty: + print(f"No {type} trading data found\n") return - df_congress = df_congress.sort_values("TransactionDate", ascending=False) + df_gov = df_gov.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_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"]) - df_congress = df_congress[df_congress["TransactionDate"] > start_date].dropna() + df_gov = df_gov[df_gov["TransactionDate"] > start_date].dropna() - df_congress["min"] = df_congress["Range"].apply( + df_gov["min"] = df_gov["Range"].apply( lambda x: x.split("-")[0].strip("$").replace(",", "").strip() ) - df_congress["max"] = df_congress["Range"].apply( + df_gov["max"] = df_gov["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( + 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_congress["upper"] = df_congress[["min", "max", "Transaction"]].apply( + 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_congress = df_congress.sort_values("TransactionDate", ascending=True) + df_gov = df_gov.sort_values("TransactionDate", ascending=True) plt.figure(figsize=plot_autoscale(), dpi=PLOT_DPI) - df_congress.groupby("Ticker")["lower"].sum().sort_values().abs().head( + df_gov.groupby("Ticker")["lower"].sum().sort_values().abs().head( n=ns_parser.top_num ).plot(kind="bar", rot=0) plt.ylabel("Amount [$]") @@ -310,29 +321,34 @@ def sell_congress(other_args: List[str]): print(e, "\n") -def plot_congress(congress: pd.DataFrame, ticker: str): - """Plot congress trading +def plot_government(government: pd.DataFrame, ticker: str, type: str): + """Plot government trading Parameters ---------- other_args : List[str] Command line arguments to be processed with argparse ticker: str - Ticker to plot congress trading + Ticker to plot government trading + type: str + Type of government data between: congress, senate and house """ 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, + government["TransactionDate"].unique(), + government.groupby("TransactionDate")["lower"].sum().values / 1000, + government.groupby("TransactionDate")["upper"].sum().values / 1000, ) plt.xlim( - [congress["TransactionDate"].values[0], congress["TransactionDate"].values[-1]] + [ + government["TransactionDate"].values[0], + government["TransactionDate"].values[-1], + ] ) plt.grid() - plt.title(f"Congress trading on {ticker}") + plt.title(f"{type.capitalize()} trading on {ticker}") plt.xlabel("Date") plt.ylabel("Amount [1k $]") plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d")) @@ -344,8 +360,8 @@ def plot_congress(congress: pd.DataFrame, ticker: str): plt.show() -def congress(other_args: List[str], ticker: str): - """Congress trading +def government(other_args: List[str], ticker: str, type: str): + """Government trading Parameters ---------- @@ -353,13 +369,13 @@ def congress(other_args: List[str], ticker: str): Command line arguments to be processed with argparse ticker: str Ticker to get congress trading data from + type: str + Type of government data between: congress, senate and house """ parser = argparse.ArgumentParser( add_help=False, - prog="congress", - description=""" - Congress trading. [Source: www.quiverquant.com] - """, + prog=type, + description=f"{type} trading. [Source: www.quiverquant.com]", ) parser.add_argument( "-p", @@ -381,47 +397,47 @@ def congress(other_args: List[str], ticker: str): if not ns_parser: return - df_congress = quiverquant_model.get_congress_trading(ticker) + df_gov = quiverquant_model.get_government_trading(type, ticker) - if df_congress.empty: - print("No congress trading data found\n") + if df_gov.empty: + print(f"No {type} trading data found\n") return - df_congress = df_congress.sort_values("TransactionDate", ascending=False) + df_gov = df_gov.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_gov["TransactionDate"] = pd.to_datetime(df_gov["TransactionDate"]) - df_congress = df_congress[df_congress["TransactionDate"] > start_date] + df_gov = df_gov[df_gov["TransactionDate"] > start_date] - df_congress["min"] = df_congress["Range"].apply( + df_gov["min"] = df_gov["Range"].apply( lambda x: x.split("-")[0].strip("$").replace(",", "").strip() ) - df_congress["max"] = df_congress["Range"].apply( + df_gov["max"] = df_gov["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( + df_gov["lower"] = df_gov[["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( + df_gov["upper"] = df_gov[["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) + df_gov = df_gov.sort_values("TransactionDate", ascending=True) - plot_congress(df_congress, ticker) + plot_government(df_gov, ticker, type) print("")