diff options
author | montezdesousa <79287829+montezdesousa@users.noreply.github.com> | 2022-11-25 23:10:48 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-11-25 18:10:48 -0500 |
commit | 7480c5efe01dd800fe466e648786a9c16efb90e5 (patch) | |
tree | c60258dcac8632200769c1440d1e946795202078 | |
parent | 79046608b603bf07d6666151ffbb00413a21787c (diff) |
Fix portfolio optimization SDK bugs (#3582)
* Small improvement to text handling
* fix plot and engine
* change msg
* fix po engine
* fix rc
* fix error
* opt pytest
* bug fix
Co-authored-by: colin99d <colin99delahunty@gmail.com>
Co-authored-by: minhhoang1023 <40023817+minhhoang1023@users.noreply.github.com>
Co-authored-by: James Maslek <jmaslek11@gmail.com>
5 files changed, 560 insertions, 318 deletions
diff --git a/openbb_terminal/portfolio/portfolio_optimization/po_engine.py b/openbb_terminal/portfolio/portfolio_optimization/po_engine.py index 8a201bbe138..d46854f4c4c 100644 --- a/openbb_terminal/portfolio/portfolio_optimization/po_engine.py +++ b/openbb_terminal/portfolio/portfolio_optimization/po_engine.py @@ -1,4 +1,4 @@ -from typing import Dict, List +from typing import Dict, List, Tuple import pandas as pd from openbb_terminal.portfolio.portfolio_optimization import ( excel_model, @@ -14,8 +14,7 @@ class PoEngine: def __init__( self, - symbols: List[str] = None, - categories: Dict[str, Dict[str, str]] = None, + symbols_categories: Dict[str, Dict[str, str]] = None, symbols_file_path: str = None, parameters_file_path: str = None, ): @@ -23,9 +22,7 @@ class PoEngine: Parameters ---------- - symbols : List[str] - List of symbols - categories : Dict[str, float], optional + symbols_categories : Dict[str, float], optional Categories, by default None symbols_file_path : str, optional Symbols file path, by default None @@ -33,14 +30,18 @@ class PoEngine: Parameters file path, by default None """ - self._categories: Dict[str, Dict[str, str]] = categories or {} + self._categories: Dict[str, Dict[str, str]] = {} + self._symbols: List[str] = [] self._weights: Dict[str, float] = {} self._returns: pd.DataFrame = None self._params: Dict[str, float] = {} self._current_model: str - if symbols is not None: - self._symbols: List[str] = symbols + if symbols_categories is not None: + self._symbols, self._categories = PoEngine.__parse_dictionary( + symbols_categories + ) + elif symbols_file_path is not None: self._symbols, self._categories = excel_model.load_allocation( symbols_file_path @@ -53,6 +54,65 @@ class PoEngine: parameters_file_path ) + @staticmethod + def __parse_dictionary( + symbols_categories: Dict[str, Dict[str, str]] + ) -> Tuple[List[str], Dict[str, Dict[str, str]]]: + """Parse the categories dictionary + + Parameters + ---------- + symbols_categories : Dict[str, Dict[str, str]] + Categories + + Returns + ------- + Tuple[List[str], Dict[str, Dict[str, str]]] + Symbols and categories + """ + if isinstance(symbols_categories, dict): + symbols = PoEngine.__get_symbols_from_categories(symbols_categories) + else: + raise TypeError("'symbols_categories' must be a dictionary.") + + for symbol in symbols: + symbols_categories["CURRENCY"].setdefault(symbol, "USD") + symbols_categories["CURRENT_INVESTED_AMOUNT"].setdefault(symbol, "0") + + return symbols, symbols_categories + + @staticmethod + def __get_symbols_from_categories( + symbols_categories: Dict[str, Dict[str, str]] + ) -> List[str]: + """Get the symbols from the categories dictionary + + Parameters + ---------- + symbols_categories : Dict[str, Dict[str, str]], optional + Categories + + Returns + ------- + List[str] + List of symbols + """ + + try: + symbols = [] + for item in symbols_categories.items(): + _, values = item + for v in values.keys(): + symbols.append(v) + + return list(set(symbols)) + + except Exception: + console.print( + "Unsupported dictionary format. See `portfolio.po.load` examples for correct format." + ) + return [] + def get_symbols(self): return self._symbols @@ -66,16 +126,6 @@ class PoEngine: """ return list(self._categories.keys()) - def set_categories_dict(self, categories: Dict[str, Dict[str, str]]): - """Set the categories - - Parameters - ---------- - categories : Dict[str, Dict[str, str]] - Categories - """ - self._categories = categories - def get_category(self, category: str = None) -> Dict[str, str]: """Get the category diff --git a/openbb_terminal/portfolio/portfolio_optimization/po_model.py b/openbb_terminal/portfolio/portfolio_optimization/po_model.py index ce1ed827cb5..fbe77182ef6 100644 --- a/openbb_terminal/portfolio/portfolio_optimization/po_model.py +++ b/openbb_terminal/portfolio/portfolio_optimization/po_model.py @@ -59,7 +59,7 @@ def validate_parameters_type(parameters): @log_start_end(log=logger) def generate_portfolio( - symbols: List[str] = None, + symbols_categories: Dict[str, Dict[str, str]] = None, symbols_file_path: str = None, parameters_file_path: str = None, ) -> Union[PoEngine, None]: @@ -67,8 +67,8 @@ def generate_portfolio( Parameters ---------- - symbols : List[str], optional - List of symbols, by default None + symbols_categories: Dict[str, Dict[str, str]] = None + Categories, by default None symbols_file_path : str, optional Symbols file full path, by default None parameters_file_path : str, optional @@ -82,25 +82,44 @@ def generate_portfolio( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) >>> weights, performance = openbb.portfolio.po.equal(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb - >>> p = openbb.portfolio.po.load(symbols=["AAPL", "MSFT", "AMZN"]) + >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") >>> weights, performance = openbb.portfolio.po.equal(portfolio_engine=p) """ - if symbols: + if symbols_file_path: return PoEngine( - symbols=symbols, + symbols_file_path=symbols_file_path, parameters_file_path=parameters_file_path, ) - if symbols_file_path: + + if symbols_categories: return PoEngine( - symbols_file_path=symbols_file_path, + symbols_categories=symbols_categories, parameters_file_path=parameters_file_path, ) - console.print("No file or symbols provided") + + console.print("No 'symbols_file_path' or 'symbols_categories' provided.") return None @@ -163,14 +182,12 @@ def load_parameters_file( @log_start_end(log=logger) def validate_inputs( - symbols=None, portfolio_engine=None, kwargs=None + portfolio_engine=None, kwargs=None ) -> Tuple[List[str], PoEngine, dict]: """Check valid inputs Parameters ---------- - symbols : List[str], optional - List of symbols, by default None portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine @@ -183,15 +200,12 @@ def validate_inputs( List of symbols, Portfolio optimization engine, Keyword arguments """ - if symbols: - portfolio_engine = PoEngine(symbols=symbols) - parameters = kwargs - elif portfolio_engine: + if portfolio_engine: symbols = portfolio_engine.get_symbols() parameters = portfolio_engine.get_params().copy() parameters.update(kwargs) else: - console.print("No 'symbols' or 'portfolio_engine' provided.") + console.print("No 'portfolio_engine' provided.") validate_parameters_type(parameters) @@ -263,7 +277,7 @@ def get_portfolio_performance(weights: Dict, data: pd.DataFrame, **kwargs) -> Di @log_start_end(log=logger) def get_maxsharpe( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize Sharpe ratio weights @@ -272,8 +286,6 @@ def get_maxsharpe( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -367,14 +379,25 @@ def get_maxsharpe( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> openbb.portfolio.po.maxsharpe(symbols=["AAPL", "MSFT", "AMZN"]) - ( value - AAPL 1.0 - MSFT 0.0 - AMZN 0.0, - {'Return': 0.3448948339574538, - 'Volatility': 0.36513261935342495, - 'Sharpe ratio': 0.9445741510802071}) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.maxsharpe(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -382,7 +405,7 @@ def get_maxsharpe( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -400,7 +423,7 @@ def get_maxsharpe( @log_start_end(log=logger) def get_minrisk( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize minimum risk weights @@ -409,8 +432,6 @@ def get_minrisk( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -504,14 +525,25 @@ def get_minrisk( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> openbb.portfolio.po.minrisk(symbols=["AAPL", "MSFT", "AMZN"]) - ( value - AAPL 0.25044 - MSFT 0.49509 - AMZN 0.25447, - {'Return': 0.2248615963428331, - 'Volatility': 0.32736590080425004, - 'Sharpe ratio': 0.6868815468880802}) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.minrisk(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -519,7 +551,7 @@ def get_minrisk( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -537,7 +569,7 @@ def get_minrisk( @log_start_end(log=logger) def get_maxutil( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize maximum utility weights @@ -546,8 +578,6 @@ def get_maxutil( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -641,14 +671,25 @@ def get_maxutil( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> openbb.portfolio.po.maxutil(symbols=["AAPL", "MSFT", "AMZN"]) - ( value - AAPL 1.0 - MSFT 0.0 - AMZN 0.0, - {'Return': 0.3448948339574538, - 'Volatility': 0.36513261935342495, - 'Sharpe ratio': 0.9445741510802071}) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.maxutil(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -656,7 +697,7 @@ def get_maxutil( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -674,7 +715,7 @@ def get_maxutil( @log_start_end(log=logger) def get_maxret( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize maximum return weights @@ -683,8 +724,6 @@ def get_maxret( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -778,14 +817,25 @@ def get_maxret( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> openbb.portfolio.po.maxret(symbols=["AAPL", "MSFT", "AMZN"]) - ( value - AAPL 1.0 - MSFT 0.0 - AMZN 0.0, - {'Return': 0.3448948339574538, - 'Volatility': 0.36513261935342495, - 'Sharpe ratio': 0.9445741510802071}) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.maxret(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -793,7 +843,7 @@ def get_maxret( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -811,7 +861,7 @@ def get_maxret( @log_start_end(log=logger) def get_maxdiv( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize diversification weights @@ -820,8 +870,6 @@ def get_maxdiv( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -892,14 +940,25 @@ def get_maxdiv( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> openbb.portfolio.po.maxdiv(symbols=["AAPL", "MSFT", "AMZN"]) - ( value - AAPL 0.33696 - MSFT 0.26766 - AMZN 0.39538, - {'Return': 0.21717206203731806, - 'Volatility': 0.3310292858117002, - 'Sharpe ratio': 0.6560509034866852}) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.maxdiv(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -907,7 +966,7 @@ def get_maxdiv( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -925,7 +984,7 @@ def get_maxdiv( @log_start_end(log=logger) def get_maxdecorr( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize decorrelation weights @@ -934,8 +993,6 @@ def get_maxdecorr( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -984,14 +1041,25 @@ def get_maxdecorr( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> openbb.portfolio.po.maxdecorr(symbols=["AAPL", "MSFT", "AMZN"]) - ( value - AAPL 0.33444 - MSFT 0.24963 - AMZN 0.41593, - {'Return': 0.2142767096699773, - 'Volatility': 0.33184082287769623, - 'Sharpe ratio': 0.6457213666835423}) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.maxdecorr(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -999,7 +1067,7 @@ def get_maxdecorr( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -1017,7 +1085,7 @@ def get_maxdecorr( @log_start_end(log=logger) def get_blacklitterman( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize decorrelation weights @@ -1026,8 +1094,6 @@ def get_blacklitterman( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -1085,14 +1151,25 @@ def get_blacklitterman( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> openbb.portfolio.po.blacklitterman(symbols=["AAPL", "MSFT", "AMZN"]) - ( value - AAPL 0.48920 - MSFT 0.28391 - AMZN 0.22689, - {'Return': 0.2563301105112327, - 'Volatility': 0.33132073874339424, - 'Sharpe ratio': 0.7736615325784322}) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.blacklitterman(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -1100,7 +1177,7 @@ def get_blacklitterman( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -1118,7 +1195,7 @@ def get_blacklitterman( @log_start_end(log=logger) def get_ef( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[ pd.DataFrame, pd.DataFrame, @@ -1136,8 +1213,6 @@ def get_ef( portfolio_engine : PoEngine, optional Portfolio optimization engine, by default None Use `portfolio.po.load` to load a portfolio engine - symbols : List[str], optional - List of symbols, by default None interval : str, optional Interval to get data, by default '3y' start_date : str, optional @@ -1202,7 +1277,25 @@ def get_ef( Examples -------- >>> from openbb_terminal.sdk import openbb - >>> frontier = openbb.portfolio.po.ef(symbols=["AAPL", "MSFT", "AMZN"]) + >>> d = { + "SECTOR": { + "AAPL": "INFORMATION TECHNOLOGY", + "MSFT": "INFORMATION TECHNOLOGY", + "AMZN": "CONSUMER DISCRETIONARY", + }, + "CURRENT_INVESTED_AMOUNT": { + "AAPL": "100000.0", + "MSFT": "200000.0", + "AMZN": "300000.0", + }, + "CURRENCY": { + "AAPL": "USD", + "MSFT": "USD", + "AMZN": "USD", + }, + } + >>> p = openbb.portfolio.po.load(symbols_categories=d) + >>> weights, performance = openbb.portfolio.po.ef(portfolio_engine=p) >>> from openbb_terminal.sdk import openbb >>> p = openbb.portfolio.po.load(symbols_file_path="~/openbb_terminal/miscellaneous/portfolio_examples/allocation/60_40_Portfolio.xlsx") @@ -1210,7 +1303,7 @@ def get_ef( """ valid_symbols, valid_portfolio_engine, valid_kwargs = validate_inputs( - symbols, portfolio_engine, kwargs + portfolio_engine, kwargs ) if not valid_symbols: return pd.DataFrame() @@ -1218,7 +1311,7 @@ def get_ef( frontier, mu, cov, returns, weights, X1, Y1, port = optimizer_model.get_ef( symbols=valid_symbols, **valid_kwargs ) - valid_portfolio_engine.set_weights(weights=weights) + valid_portfolio_engine.set_weights(weights=weights.to_dict()["weights"]) valid_portfolio_engine.set_returns(returns=returns) return frontier, mu, cov, returns, weights, X1, Y1, port @@ -1226,7 +1319,7 @@ def get_ef( @log_start_end(log=logger) def get_riskparity( - portfolio_engine: PoEngine = None, symbols: List[str] = None, **kwargs + portfolio_engine: PoEngine = None, **kwargs ) -> Tuple[pd.DataFrame, Dict]: """Optimize with Risk Parity using the risk budgeting approach @@ -1235,8 +1 |