summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjmaslek <jmaslek11@gmail.com>2021-09-23 13:50:38 -0400
committerGitHub <noreply@github.com>2021-09-23 13:50:38 -0400
commiteafd65199b18d80a57d8f2d0a2be64f7e067097d (patch)
tree2f42a114e0ee5f96f571cb9716b1009ff5322b49
parent4a50ac101975402c46b1ead791257c04abc91806 (diff)
Major brokers refactor into separate menus (#754)
* Major brokers refactor into separate menus * Add portfolio export folder * Added some extra commands from pyally * Update coinbase account command * poetry update + pin openpyxl to 3.0.7 * requirement files * Update hugo server * Clean hugo files * Update _index.md Add output to _index * Update _index.md * Update _index.md add output * Update _index.md add output * Update _index.md * Update _index.md * Update _index.md * Update _index.md * Update _index.md * Update _index.md * Fix alpaca bug * Fix hugo server + add to main menu
-rw-r--r--exports/portfolio/.gitkeep0
-rw-r--r--gamestonk_terminal/portfolio/brokers/ally/ally_controller.py298
-rw-r--r--gamestonk_terminal/portfolio/brokers/ally/ally_model.py110
-rw-r--r--gamestonk_terminal/portfolio/brokers/ally/ally_view.py161
-rw-r--r--gamestonk_terminal/portfolio/brokers/ally_api.py49
-rw-r--r--gamestonk_terminal/portfolio/brokers/alp_api.py117
-rw-r--r--gamestonk_terminal/portfolio/brokers/alpaca/alpaca_controller.py191
-rw-r--r--gamestonk_terminal/portfolio/brokers/alpaca/alpaca_model.py73
-rw-r--r--gamestonk_terminal/portfolio/brokers/alpaca/alpaca_view.py66
-rw-r--r--gamestonk_terminal/portfolio/brokers/bro_controller.py209
-rw-r--r--gamestonk_terminal/portfolio/brokers/brokers_helpers.py61
-rw-r--r--gamestonk_terminal/portfolio/brokers/coinbase/coinbase_controller.py45
-rw-r--r--gamestonk_terminal/portfolio/brokers/coinbase/coinbase_model.py43
-rw-r--r--gamestonk_terminal/portfolio/brokers/coinbase/coinbase_view.py27
-rw-r--r--gamestonk_terminal/portfolio/brokers/rh_api.py179
-rw-r--r--gamestonk_terminal/portfolio/brokers/robinhood/robinhood_controller.py213
-rw-r--r--gamestonk_terminal/portfolio/brokers/robinhood/robinhood_model.py105
-rw-r--r--gamestonk_terminal/portfolio/brokers/robinhood/robinhood_view.py85
-rw-r--r--poetry.lock330
-rw-r--r--pyproject.toml2
-rw-r--r--requirements-full.txt36
-rw-r--r--requirements.txt36
-rw-r--r--website/content/portfolio/brokers/ally/_index.md11
-rw-r--r--website/content/portfolio/brokers/ally/balances/_index.md10
-rw-r--r--website/content/portfolio/brokers/ally/history/_index.md26
-rw-r--r--website/content/portfolio/brokers/ally/holdings/_index.md21
-rw-r--r--website/content/portfolio/brokers/ally/movers/_index.md34
-rw-r--r--website/content/portfolio/brokers/ally/quote/_index.md25
-rw-r--r--website/content/portfolio/brokers/alpaca/_index.md8
-rw-r--r--website/content/portfolio/brokers/alpaca/history/_index.md17
-rw-r--r--website/content/portfolio/brokers/alpaca/holdings/_index.md10
-rw-r--r--website/content/portfolio/brokers/coinbase/_index.md9
-rw-r--r--website/content/portfolio/brokers/coinbase/account/_index.md27
-rw-r--r--website/content/portfolio/brokers/coinbase/deposits/_index.md19
-rw-r--r--website/content/portfolio/brokers/coinbase/history/_index.md14
-rw-r--r--website/content/portfolio/brokers/coinbase/orders/_index.md15
-rw-r--r--website/content/portfolio/brokers/robinhood/_index.md10
-rw-r--r--website/content/portfolio/brokers/robinhood/history/_index.md19
-rw-r--r--website/content/portfolio/brokers/robinhood/holdings/_index.md18
-rwxr-xr-xwebsite/data/menu/main.yml39
40 files changed, 1984 insertions, 784 deletions
diff --git a/exports/portfolio/.gitkeep b/exports/portfolio/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/exports/portfolio/.gitkeep
diff --git a/gamestonk_terminal/portfolio/brokers/ally/ally_controller.py b/gamestonk_terminal/portfolio/brokers/ally/ally_controller.py
new file mode 100644
index 00000000000..b71d7b378a7
--- /dev/null
+++ b/gamestonk_terminal/portfolio/brokers/ally/ally_controller.py
@@ -0,0 +1,298 @@
+"""Ally Controller"""
+__docformat__ = "numpy"
+
+import argparse
+import os
+from typing import List
+from prompt_toolkit.completion import NestedCompleter
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.menu import session
+from gamestonk_terminal.portfolio.brokers.ally import ally_view
+from gamestonk_terminal.helper_funcs import (
+ get_flair,
+ parse_known_args_and_warn,
+)
+
+
+class AllyController:
+
+ CHOICES = [
+ "?",
+ "cls",
+ "help",
+ "q",
+ "quit",
+ ]
+
+ ALLY_CHOICES = ["holdings", "history", "balances"]
+ ALLY_STOCK_CHOICES = ["quote", "movers"]
+
+ def __init__(self):
+ """CONSTRUCTOR"""
+
+ self._ally_parser = argparse.ArgumentParser(add_help=False, prog="ally")
+ self.CHOICES.extend(self.ALLY_CHOICES)
+ self.CHOICES.extend(self.ALLY_STOCK_CHOICES)
+ self._ally_parser.add_argument("cmd", choices=self.CHOICES)
+
+ def print_help(self):
+ """Print help"""
+ help_text = """
+Ally:
+ cls clear screen
+ ?/help show this menu again
+ q quit this menu, and shows back to main menu
+ quit quit to abandon the program
+
+ holdings show account holdings
+ history show history of your account
+ balances show balance details of account
+
+Stock Information:
+ quote get stock quote
+ movers get ranked lists of movers
+"""
+
+ print(help_text)
+
+ 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
+ """
+
+ # Empty command
+ if not an_input:
+ print("")
+ return None
+
+ (known_args, other_args) = self._ally_parser.parse_known_args(an_input.split())
+
+ # Help menu again
+ if known_args.cmd == "?":
+ self.print_help()
+ return None
+
+ # Clear screen
+ if known_args.cmd == "cls":
+ os.system("cls||clear")
+ return None
+
+ return getattr(
+ self, "call_" + known_args.cmd, lambda: "Command not recognized!"
+ )(other_args)
+
+ def call_help(self, _):
+ """Process Help command"""
+ self.print_help()
+
+ 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_holdings(self, other_args: List[str]):
+ """Process holdings command"""
+ parser = argparse.ArgumentParser(
+ prog="holdings",
+ add_help=False,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ description="Display info about your trading accounts on Ally",
+ )
+ parser.add_argument(
+ "--export",
+ choices=["csv", "json", "xlsx"],
+ default="",
+ type=str,
+ dest="export",
+ help="Export dataframe data to csv,json,xlsx file",
+ )
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+ ally_view.display_holdings(export=ns_parser.export)
+ except Exception as e:
+ print(e, "\n")
+
+ def call_history(self, other_args: List[str]):
+ """Process history command"""
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ prog="history",
+ description="""Account transaction history""",
+ )
+ parser.add_argument(
+ "-n",
+ "--num",
+ dest="num",
+ default=15,
+ type=int,
+ help="Number of recent transactions to show",
+ )
+ parser.add_argument(
+ "--export",
+ choices=["csv", "json", "xlsx"],
+ default="",
+ type=str,
+ dest="export",
+ help="Export dataframe data to csv,json,xlsx file",
+ )
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+ ally_view.display_history(n_to_show=ns_parser.num, export=ns_parser.export)
+ except Exception as e:
+ print(e, "\n")
+
+ def call_balances(self, other_args: List[str]):
+ """Process balances command"""
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ prog="balances",
+ description="""Account balance details""",
+ )
+ parser.add_argument(
+ "--export",
+ choices=["csv", "json", "xlsx"],
+ default="",
+ type=str,
+ dest="export",
+ help="Export dataframe data to csv,json,xlsx file",
+ )
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+ ally_view.display_balances(export=ns_parser.export)
+
+ except Exception as e:
+ print(e, "\n")
+
+ def call_quote(self, other_args: List[str]):
+ """Process balances command"""
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ prog="quote",
+ description="""Get stock quote""",
+ )
+ if other_args and "-" not in other_args[0]:
+ other_args.insert(0, "-t")
+ parser.add_argument(
+ "-t",
+ "--ticker",
+ help="Ticker to get quote for. Can be in form of 'tick1,tick2...'",
+ type=str,
+ dest="ticker",
+ )
+
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+ ally_view.display_stock_quote(ns_parser.ticker)
+
+ except Exception as e:
+ print(e, "\n")
+
+ def call_movers(self, other_args: List[str]):
+ """Process movers command"""
+ parser = argparse.ArgumentParser(
+ add_help=False,
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
+ prog="movers",
+ description="""Get stock movers""",
+ )
+ parser.add_argument(
+ "-l",
+ "--list",
+ help="List to get movers of",
+ choices=[
+ "toplosers",
+ "toppctlosers",
+ "topvolume",
+ "topactive",
+ "topgainers",
+ "toppctgainers",
+ ],
+ default="topactive",
+ dest="list_type",
+ )
+ parser.add_argument(
+ "-e",
+ "--exchange",
+ help="""Exchange to look at. Can be
+ A:American Stock Exchange.
+ N:New York Stock Exchange.
+ Q:NASDAQ
+ U:NASDAQ Bulletin Board
+ V:NASDAQ OTC Other""",
+ choices=["A", "N", "Q", "U", "V"],
+ default="N",
+ dest="exchange",
+ )
+ parser.add_argument(
+ "-n", "--num", help="Number to show", type=int, default=15, dest="num"
+ )
+ parser.add_argument(
+ "--export",
+ choices=["csv", "json", "xlsx"],
+ default="",
+ type=str,
+ dest="export",
+ help="Export dataframe data to csv,json,xlsx file",
+ )
+ try:
+ ns_parser = parse_known_args_and_warn(parser, other_args)
+ if not ns_parser:
+ return
+ ally_view.display_top_lists(
+ list_type=ns_parser.list_type,
+ exchange=ns_parser.exchange,
+ num_to_show=ns_parser.num,
+ export=ns_parser.export,
+ )
+
+ except Exception as e:
+ print(e, "\n")
+
+
+def menu():
+
+ ally_controller = AllyController()
+ ally_controller.print_help()
+
+ while True:
+ # Get input command from user
+ if session and gtff.USE_PROMPT_TOOLKIT:
+ completer = NestedCompleter.from_nested_dict(
+ {c: None for c in ally_controller.CHOICES}
+ )
+ an_input = session.prompt(
+ f"{get_flair()} (bro)>(ally)> ",
+ completer=completer,
+ )
+ else:
+ an_input = input(f"{get_flair()} (bro)>(ally)> ")
+
+ try:
+ process_input = ally_controller.switch(an_input)
+
+ if process_input is not None:
+ return process_input
+
+ except SystemExit:
+ print("The command selected doesn't exist\n")
+ continue
diff --git a/gamestonk_terminal/portfolio/brokers/ally/ally_model.py b/gamestonk_terminal/portfolio/brokers/ally/ally_model.py
new file mode 100644
index 00000000000..3872d8af8fc
--- /dev/null
+++ b/gamestonk_terminal/portfolio/brokers/ally/ally_model.py
@@ -0,0 +1,110 @@
+"""Ally Model"""
+__docformat__ = "numpy"
+
+import ally
+import pandas as pd
+
+
+def get_holdings() -> pd.DataFrame:
+ """Get holdings from Ally account in pandas df
+
+ Returns
+ -------
+ pd.DataFrame
+ Dataframe of positions
+ """
+ a = ally.Ally()
+ return ally_positions_to_df(a.holdings(dataframe=True))
+
+
+def ally_positions_to_df(df: pd.DataFrame) -> pd.DataFrame:
+ """Clean up ally holdings dataframe
+
+ Parameters
+ ----------
+ df : pd.DataFrame
+ Input dataframe of holdings
+
+ Returns
+ -------
+ pd.DataFrame
+ Processed holdings
+ """
+ names = {
+ "costbasis": "CostBasis",
+ "marketvalue": "MarketValue",
+ "sym": "Symbol",
+ "qty": "Quantity",
+ }
+ df = df.loc[:, ["qty", "costbasis", "marketvalue", "sym"]]
+ df[["qty", "costbasis", "marketvalue"]] = df[
+ ["qty", "costbasis", "marketvalue"]
+ ].astype(float)
+ df = df.rename(columns=names)
+ df["PnL"] = df["MarketValue"] - df["CostBasis"]
+ return df
+
+
+def get_history() -> pd.DataFrame:
+ """Gets transaction history for the account."
+
+ Returns
+ -------
+ pd.DataFrame
+ Dataframe of transaction history
+ """
+ a = ally.Ally()
+ return a.history(dataframe=True)
+
+
+def get_balances() -> pd.DataFrame:
+ """Gets balance details for the account."
+
+ Returns
+ -------
+ pd.DataFrame
+ Dataframe of transaction history
+ """
+ a = ally.Ally()
+ return a.balances(dataframe=True)
+
+
+def get_stock_quote(ticker: str) -> pd.DataFrame:
+ """Gets quote for stock ticker
+
+ Parameters
+ ----------
+ ticker : str
+ Ticker to get. Can be in form of 'tick1,tick2...'
+ Returns
+ -------
+ pd.DataFrame
+ Dataframe of ticker quote
+ """
+ a = ally.Ally()
+ return a.quote(
+ ticker,
+ fields=["last", "bid", "ask", "opn", "dollar_value", "chg", "vl"],
+ dataframe=True,
+ )
+
+
+def get_top_movers(list_type: str, exchange: str) -> pd.DataFrame:
+ """
+ Gets top lists from ally Invest API. Documentation for parameters below:
+ https://www.ally.com/api/invest/documentation/market-toplists-get/
+
+ Parameters
+ ----------
+ list_type : str
+ Which list to get data for
+ exchange : str
+ Which exchange to look at
+
+ Returns
+ -------
+ pd.DataFrame
+ DataFrame of top movers
+ """
+ a = ally.Ally()
+ return a.toplists(list_type, exchange, dataframe=True)
diff --git a/gamestonk_terminal/portfolio/brokers/ally/ally_view.py b/gamestonk_terminal/portfolio/brokers/ally/ally_view.py
new file mode 100644
index 00000000000..1bcac72d52e
--- /dev/null
+++ b/gamestonk_terminal/portfolio/brokers/ally/ally_view.py
@@ -0,0 +1,161 @@
+"""Ally View"""
+__docformat__ = "numpy"
+
+import os
+from tabulate import tabulate
+from gamestonk_terminal import feature_flags as gtff
+from gamestonk_terminal.helper_funcs import export_data
+from gamestonk_terminal.portfolio.brokers.ally import ally_model
+
+
+def display_history(n_to_show: int = 15, export: str = ""):
+ history = ally_model.get_history()
+ show_history = history[["amount", "date", "symbol", "transactiontype", "quantity"]]
+ if gtff.USE_TABULATE_DF:
+ print(
+ tabulate(
+ show_history.tail(n_to_show),
+ headers=show_history.columns,
+ tablefmt="fancy_grid",
+ floatfmt=".2f",
+ showindex=False,
+ )
+ )
+ else:
+ print(show_history.tail(n_to_show).to_string())
+ print("")
+ export_data(
+ export, os.path.dirname(os.path.abspath(__file__)), "ally_history", history
+ )
+
+
+def display_holdings(export: str = ""):
+ """Display holdings from ally account
+
+ Parameters
+ ----------
+ export : str, optional
+ Format to export data, by default ""
+ """
+ holdings = ally_model.get_holdings()
+ holdings = holdings.set_index("Symbol")
+ if gtff.USE_TABULATE_DF:
+ print(
+ tabulate(
+ holdings,
+ headers=holdings.columns,
+ tablefmt="fancy_grid",
+ floatfmt=".2f",
+ showindex=True,
+ )
+ )
+ else:
+ print(holdings.to_string())
+ print("")
+ export_data(
+ export,
+ os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
+ "ally_holdings",
+ holdings,
+ )
+
+
+def display_balances(export: str = ""):
+ """Display balances from ally account
+
+ Parameters
+ ----------
+ export : str, optional
+ Format to export data, by default ""
+ """
+ balances = ally_model.get_balances()
+ # Export data here before picking out certain columns
+ export_data(
+ export,
+ os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))),
+ "ally_balances",
+ balances,
+ )
+ # Pick which balances to show
+ balances = balances[
+ [
+ "accountvalue",
+ "buyingpower.stock",
+ "money.cash",
+ "securities.stocks",
+ "securities.total",
+ ]
+ ]
+ if gtff.USE_TABULATE_DF:
+ print(
+ tabulate(
+ balances,
+ headers=balances.columns,
+ tablefmt="fancy_grid",
+ floatfmt=".2f",
+ showindex=False,
+ )
+ )
+ else:
+ print(balances.to_string())
+ print("")
+
+
+def display_stock_quote(ticker: str):
+ """Displays stock quote for ticker/tickers
+
+ Parameters
+ ----------
+ ticker : str
+ Ticker to get. Can be in form of 'tick1,tick2...'
+ """
+ quote = ally_model.get_stock_quote(ticker)
+ if gtff.USE_TABULATE_DF:
+ print(
+ tabulate(
+ quote, tablefmt="fancy_grid", headers=quote.columns, showindex=True
+ )
+ )
+ else:
+ print(quote.to_string())
+ print("")
+
+
+def display_top_lists(
+ list_type: str, exchange: str, num_to_show: int = 20, export: str = ""
+):
+ """<