Merge pull request #244 from jmaslek/port2

refactor portfolio menu
This commit is contained in:
DidierRLopes
2021-03-21 20:45:54 +00:00
committed by GitHub
6 changed files with 180 additions and 107 deletions

View File

@@ -53,7 +53,7 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open):
print(
" fred economic data, \t\t\t from: Federal Reserve Bank of St. Louis "
)
print(" port portfolio, \t\t\t Currently: Robinhood ")
print(" pa portfolio analysis, \t\t Currently Supported: Robinhood ")
if s_ticker:
print(

View File

@@ -2,12 +2,26 @@
This page shows the available brokers for loading in data. If yours is not listed, please submit a new issue and we will look at adding it.
Current brokers:
* Robinhood
Once this screen is accessed, the first command to be run is
````
login
login [brokers]
````
Which will use your login information, which should be stored as environment variables in [config file](/gamestonk_terminal/config_terminal.py)
The brokers should just be your brokers from the list shown on the first menu. To login to Robinhood, the command is
````
login rh
````
When td is added, the command will be
````
login rh td
````
After logging in, the help menu will display which brokers you logged into.
Your login information should be stored as environment variables in [config file](/gamestonk_terminal/config_terminal.py)
Robinhood has Two Factor Authentication, so you will likely be prompted to enter a code that is texted/emailed to you.
###NOTE THAT LOGGING IN WILL SAVE A TOKEN TO `os.path.expanduser("~")/.tokens` WHICH CAN BE USED TO LOGIN EVEN IF USER CREDENTIALS ARE INCORRECT.

View File

@@ -0,0 +1,157 @@
__docformat__ = "numpy"
import argparse
from typing import List
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
from gamestonk_terminal.portfolio import rh_api
class PortfolioController:
CHOICES = [
"help",
"q",
"quit",
"login",
"hold",
"rhhist",
]
BROKERS = [
"rh",
]
def __init__(self):
self.port_parser = argparse.ArgumentParser(add_help=False, prog="port")
self.port_parser.add_argument("cmd", choices=self.CHOICES)
self.brokers_list = set()
@staticmethod
def print_help(broker_list):
if not broker_list:
broker_list = [" None"]
""" Print help """
print("\nPortfolio:")
print(" help show this menu again")
print(
" q quit this menu, and shows back to main menu, logs out of brokers"
)
print(" quit quit to abandon program, logs out of brokers")
print(" login login to your brokers")
print(f"\nCurrent Brokers : {('', ', '.join(broker_list))[bool(broker_list)]}")
print("\nCurrently Supported :")
print(" rh Robinhood - fuck these guys")
print("\nCommands (login required):")
print("")
print(" hold view rh holdings")
print(" rhhist plot rh portfolio history")
print("")
def print_portfolio_menu(self):
print_broke = " "
for broker in self.brokers_list:
print_broke += broker + " "
print("\nCurrent Brokers :" + print_broke)
print("")
print(" hold check holdings")
print(" rhhist plot historical RH portfolio")
print("")
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.port_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.brokers_list)
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_login(self, other_args):
logged_in = False
if not other_args:
print("Please enter brokers you wish to login to")
print("")
return
for broker in other_args:
if broker in self.BROKERS:
api = broker + "_api"
try:
eval(api + ".login()")
self.brokers_list.add(broker)
logged_in = True
except Exception as e:
print("")
print(f"Error at broker : {broker}")
print(e)
print("Make sure credentials are defined in config_terminal.py ")
print("")
else:
print(f"{broker} not supported")
if logged_in:
self.print_portfolio_menu()
def call_rhhist(self, other_args: List[str]):
rh_api.plot_historical(other_args)
def call_hold(self, _):
try:
rh_api.show_holdings()
except Exception as e:
print(e)
print("")
def menu():
"""Portfolio Analysis Menu"""
port_controller = PortfolioController()
port_controller.print_help(port_controller.brokers_list)
while True:
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
completer = NestedCompleter.from_nested_dict(
{c: None for c in port_controller.CHOICES}
)
an_input = session.prompt(
f"{get_flair()} (pa)> ",
completer=completer,
)
else:
an_input = input(f"{get_flair()} (pa)> ")
try:
process_input = port_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

@@ -1,100 +0,0 @@
import argparse
from matplotlib import pyplot as plt
from prompt_toolkit.completion import NestedCompleter
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair
from gamestonk_terminal.menu import session
from gamestonk_terminal.portfolio import rh_api
def print_port(show_login):
""" Print help """
print("\nPortfolio:")
print(" help show this menu again")
print(" q quit this menu, and shows back to main menu")
print(" quit quit to abandon program")
print(" ")
print("Robinhood:")
print("")
if show_login:
print(" login login")
print(" hold look at current holdings")
print(" rhhist look at historical portfolio")
print(" ")
def port_menu():
plt.close("all")
port_parser = argparse.ArgumentParser(prog="port", add_help=False)
choices = ["help", "q", "quit", "hold", "rhhist", "login"]
port_parser.add_argument("cmd", choices=choices)
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
should_print_help = True
print_login = True
while True:
if should_print_help:
print_port(print_login)
should_print_help = False
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
as_input = session.prompt(
f"{get_flair()} (port)> ",
completer=completer,
)
else:
as_input = input(f"{get_flair()} (port)> ")
try:
(ns_known_args, l_args) = port_parser.parse_known_args(as_input.split())
except SystemExit:
print("The command selected doesn't exist\n")
continue
if ns_known_args.cmd == "help":
should_print_help = True
elif ns_known_args.cmd == "q":
# Leave the port menu + logout of robinhood
# logoff raises error if not logged in
try:
rh_api.logoff()
except Exception:
pass
return False
elif ns_known_args.cmd == "quit":
# Will raise exception if not logged in
try:
rh_api.logoff()
except Exception:
pass
# Abandon the program
return True
elif ns_known_args.cmd == "hold":
try:
rh_api.show_holdings()
except Exception as e:
print(e)
print("")
elif ns_known_args.cmd == "rhhist":
rh_api.plot_historical(l_args)
elif ns_known_args.cmd == "login":
try:
rh_api.login()
should_print_help = True
print_login = False
except Exception as e:
print("")
print(e)
print("Make sure credentials are defined in config_terminal.py ")
print("")
should_print_help = False
print_login = True
else:
print("Command not recognized")
print("")

View File

@@ -1,4 +1,5 @@
aiohttp==3.7.4.post0; python_version >= "3.6"
alpaca-trade-api==1.0.1
alpha-vantage==2.3.1
ansiwrap==0.8.4; python_version >= "3.6"
appdirs==1.4.4; python_version >= "3.6"
@@ -103,6 +104,7 @@ rapidfuzz==1.2.1; python_version >= "2.7"
regex==2020.11.13; python_version >= "3.6"
requests==2.25.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0")
retrying==1.3.3
robin-stocks==2.0.3
scipy==1.5.4; python_version >= "3.6"
seaborn==0.11.1; python_version >= "3.6"
send2trash==1.5.0; python_version >= "3.5"

View File

@@ -25,7 +25,7 @@ from gamestonk_terminal.technical_analysis import ta_menu as tam
from gamestonk_terminal.comparison_analysis import ca_controller
from gamestonk_terminal.options import op_menu as opm
from gamestonk_terminal.fred import fred_menu as fm
from gamestonk_terminal.portfolio import port_menu
from gamestonk_terminal.portfolio import port_controller
# import warnings
# warnings.simplefilter("always")
@@ -77,7 +77,7 @@ def main():
"ca",
"op",
"fred",
"port",
"pa",
]
menu_parser.add_argument("opt", choices=choices)
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
@@ -205,8 +205,8 @@ def main():
elif ns_known_args.opt == "fred":
b_quit = fm.fred_menu()
elif ns_known_args.opt == "port":
b_quit = port_menu.port_menu()
elif ns_known_args.opt == "pa":
b_quit = port_controller.menu()
elif ns_known_args.opt == "pred":