add basic portfolio optimization controller

This commit is contained in:
Jamie
2021-04-11 16:15:11 -04:00
parent a50c97b4d5
commit ccd322d6b6
7 changed files with 219 additions and 0 deletions

View File

@@ -15,6 +15,7 @@ from gamestonk_terminal.comparison_analysis import yahoo_finance_api as yf_api
from gamestonk_terminal.comparison_analysis import market_watch_api as mw_api
from gamestonk_terminal.comparison_analysis import finbrain_api as f_api
from gamestonk_terminal.comparison_analysis import finviz_compare_view
from gamestonk_terminal.portfolio_optimization import port_optimization_controller
from gamestonk_terminal.menu import session
from prompt_toolkit.completion import NestedCompleter
@@ -42,6 +43,7 @@ class ComparisonAnalysisController:
"ownership",
"performance",
"technical",
"po"
]
def __init__(
@@ -107,6 +109,8 @@ class ComparisonAnalysisController:
print(" performance brief performance comparison")
print(" technical brief technical comparison")
print("")
print(" po portfolio optimzation from selected tickers")
print("")
return
@staticmethod
@@ -312,6 +316,10 @@ class ComparisonAnalysisController:
"""Process technical command"""
finviz_compare_view.screener(other_args, "technical", self.ticker, self.similar)
def call_po(self, _):
"""Open Portfolio Optimization menu with ticker and similar"""
port_optimization_controller.menu([self.ticker] + self.similar)
def menu(stock: pd.DataFrame, ticker: str, start: datetime, interval: str):
"""Comparison Analysis Menu"""

View File

@@ -60,6 +60,7 @@ def print_help(s_ticker, s_start, s_interval, b_is_market_open):
)
print(" pa portfolio analysis, \t\t supports: robinhood, alpaca, ally ")
print(" crypto cryptocurrencies, \t\t uses coingecko api")
print(" po portfolio analysis, \t\t UPDATE ME BEFORE PR")
if s_ticker:
print(

View File

@@ -0,0 +1,16 @@
# Portfolio Optimization
This menu aims to discover optimal portfolios for selected stocks
###add
Adds tickers to current list for optimization
````
usage: add ticker1,ticker2,...
````
###optimize
Runs optimization
````
usage: optimize
````

View File

@@ -0,0 +1,28 @@
""" Portfolio Optimization Functions"""
__docformat__ = "numpy"
import argparse
from typing import List
def optimize(list_of_stocks:List, other_args:List[str]):
"""
Parameters
----------
list_of_stocks: List[str]
List of tickers to be included in optimization
Returns
-------
weights : dict
Dictionary of weights where keys are the tickers
"""
weights = {}
n_stocks = len(list_of_stocks)
for stock in list_of_stocks:
weights[stock] = round(1/n_stocks, 5)
return weights

View File

@@ -0,0 +1,160 @@
"""Portfolio Optimization Controller Module"""
__docformat__ = "numpy"
import argparse
from typing import List, Set
from datetime import datetime
from gamestonk_terminal import feature_flags as gtff
from gamestonk_terminal.helper_funcs import get_flair, parse_known_args_and_warn
from gamestonk_terminal.menu import session
from gamestonk_terminal.portfolio_optimization import port_opt_api as po_api
from prompt_toolkit.completion import NestedCompleter
class PortfolioOptimization:
CHOICES = ["help",
"q",
"quit",
"clear",
"add",
"optimize"]
def __init__(self,
tickers:Set[str] = None
):
"""
Construct Portfolio Optimization
"""
self.po_parser = argparse.ArgumentParser(add_help=False, prog="po")
self.po_parser.add_argument("cmd", choices=self.CHOICES )
self.tickers = set(tickers)
@staticmethod
def print_help(tickers: Set[str]):
"""Print help"""
print("\nPortfolio Optimization:")
print(" help show this menu again")
print(
" q quit this menu, and shows back to main menu"
)
print(" quit quit to abandon program")
print(
f"\nCurrent Tickers: {('None', ', '.join(tickers))[bool(tickers)]}"
)
print("")
print(" add add ticker to optimize")
print(" optimize run optimization")
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.po_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.tickers)
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_add(self, other_args:List[str]):
self.add_stocks(self, other_args)
def call_optimize(self, other_args:List[str]):
weights = po_api.optimize(self.tickers, other_args)
print("Optimal Weights for Equal Weighting:")
print(weights)
print("")
@staticmethod
def add_stocks(self, other_args: List[str]):
""" Add ticker to current list for optimization"""
parser = argparse.ArgumentParser(
add_help=False,
prog="add",
description="""Add tickers for optimizing.""",
)
parser.add_argument(
"-t",
"--tickers",
dest="add_tickers",
type=lambda s: [str(item).upper() for item in s.split(",")],
default=[],
help="add tickers to optimzation.",
)
try:
# For the case where a user uses: 'select NIO,XPEV,LI'
if other_args:
if "-" not in other_args[0]:
other_args.insert(0, "-t")
ns_parser = parse_known_args_and_warn(parser, other_args)
if not ns_parser:
return
for ticker in ns_parser.add_tickers:
self.tickers.add(ticker)
print(
f"\nCurrent Tickers: {('None', ', '.join(self.tickers))[bool(self.tickers)]}"
)
print("")
except Exception as e:
print(e)
print("")
def menu(tickers:List[str]):
"""Portfolio Optimization Menu"""
if tickers == ['']:
tickers = []
po_controller = PortfolioOptimization(tickers)
po_controller.call_help(tickers)
while True:
# Get input command from user
if session and gtff.USE_PROMPT_TOOLKIT:
completer = NestedCompleter.from_nested_dict(
{c: None for c in po_controller.CHOICES}
)
an_input = session.prompt(
f"{get_flair()} (po)> ",
completer=completer,
)
else:
an_input = input(f"{get_flair()} (po)> ")
try:
process_input = po_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

@@ -31,6 +31,7 @@ from gamestonk_terminal.residuals_analysis import ra_controller
from gamestonk_terminal.portfolio import port_controller
from gamestonk_terminal.cryptocurrency import crypto_controller
from gamestonk_terminal.screener import screener_controller
from gamestonk_terminal.portfolio_optimization import port_optimization_controller as po_controller
# import warnings
# warnings.simplefilter("always")
@@ -88,7 +89,9 @@ def main():
"pa",
"crypto",
"ra",
"po"
]
menu_parser.add_argument("opt", choices=choices)
completer = NestedCompleter.from_nested_dict({c: None for c in choices})
@@ -242,6 +245,9 @@ def main():
elif ns_known_args.opt == "crypto":
b_quit = crypto_controller.menu()
elif ns_known_args.opt == "po":
b_quit = po_controller.menu([s_ticker])
elif ns_known_args.opt == "pred":
if not gtff.ENABLE_PREDICT: