def test_cla_max_sharpe_short(): cla = CLA(*setup_cla(data_only=True), weight_bounds=(-1, 1)) w = cla.max_sharpe() assert isinstance(w, dict) assert set(w.keys()) == set(cla.tickers) np.testing.assert_almost_equal(cla.weights.sum(), 1) np.testing.assert_allclose( cla.portfolio_performance(), (0.44859872371106785, 0.26762066559448255, 1.601515797589826), ) sharpe = cla.portfolio_performance()[2] cla_long_only = setup_cla() cla_long_only.max_sharpe() long_only_sharpe = cla_long_only.portfolio_performance()[2] assert sharpe > long_only_sharpe
def test_cla_max_sharpe_short(): cla = CLA(*setup_cla(data_only=True), weight_bounds=(-1, 1)) w = cla.max_sharpe() assert isinstance(w, dict) assert set(w.keys()) == set(cla.tickers) np.testing.assert_almost_equal(cla.weights.sum(), 1) np.testing.assert_allclose( cla.portfolio_performance(), (0.3799273115521356, 0.23115368271125736, 1.5570909679242886), ) sharpe = cla.portfolio_performance()[2] cla_long_only = setup_cla() cla_long_only.max_sharpe() long_only_sharpe = cla_long_only.portfolio_performance()[2] assert sharpe > long_only_sharpe
def _get_efficient_weights(self): cla = CLA(self.mu, self.S) cla.max_sharpe() (mu, sigma, weights) = cla.efficient_frontier() return mu, sigma, weights
'GOOG': 0.049560084289929286, 'JPM': 0.017675709092515708, 'MA': 0.03812737349732021, 'PFE': 0.07786528342813454, 'RRC': 0.03161528695094597, 'SBUX': 0.039844436656239136, 'SHLD': 0.027113184241298865, 'T': 0.11138956508836476, 'UAA': 0.02711590957075009, 'WMT': 0.10569551148587905, 'XOM': 0.11175337115721229} """ # Crticial Line Algorithm cla = CLA(mu, S) print(cla.max_sharpe()) cla.portfolio_performance(verbose=True) """ {'GOOG': 0.020889868669945022, 'AAPL': 0.08867994115132602, 'FB': 0.19417572932251745, 'BABA': 0.10492386821217001, 'AMZN': 0.0644908140418782, 'GE': 0.0, 'AMD': 0.0, 'WMT': 0.0034898157701416382, 'BAC': 0.0, 'GM': 0.0, 'T': 2.4138966206946562e-19, 'UAA': 0.0, 'SHLD': 0.0,
def optimal_portfolio(mu, S, objective='max_sharpe', get_entire_frontier=True, **kwargs): """Solve for optimal portfolio. Wrapper for pypfopt functions Arguments: mu (pd.Series) - Expected annual returns S (pd.DataFrame/np.ndarray) - Expected annual volatility objective (string, optional) - Optimise for either 'max_sharpe', or 'min_volatility', defaults to 'max_sharpe' get_entire_frontier (boolean, optional) - Also get the entire efficient frontier, defaults to True """ # if need to efficiently compute the entire efficient frontier for plotting, use CLA # else use standard EfficientFrontier optimiser. # (Note that optimum weights might be slightly different depending on whether CLA or EfficientFrontier was used) Optimiser = CLA if get_entire_frontier else EfficientFrontier op = Optimiser(mu, S) # risk_aversion = kwargs.get("risk_aversion", 1) # only for max quadratic utility if (objective is None): # Get weights for both max_sharpe and min_volatility opt_weights = [] op.max_sharpe() opt_weights.append(op.clean_weights()) op.min_volatility() opt_weights.append(op.clean_weights()) # ef = EfficientFrontier(mu, S) # ef.max_quadratic_utility(risk_aversion) # opt_weights.append(ef.clean_weights()) else: if (objective == 'max_sharpe'): op.max_sharpe() elif ('min_vol' in objective): op.min_volatility() elif (objective == 'efficient_risk'): target_volatility = kwargs.get("target_volatility", None) if target_volatility is None: print("Error: You have to specify the target_volatility!") return None, None, None, None else: try: op.efficient_risk(target_volatility) except ValueError: # could not solve based on target_volatility, we try lookup table instead cla = CLA(mu, S) cla.max_sharpe() ef_returns, ef_risks, ef_weights = cla.efficient_frontier(points=300) lookup_v_w = dict(zip(ef_risks, ef_weights)) lookup_v_w = OrderedDict(sorted(lookup_v_w.items())) w = lookup_v_w[min(lookup_v_w.keys(), key=lambda key: abs(key-target_volatility))] w = [i[0] for i in w] # flatten return w, None, None elif (objective == 'efficient_return'): target_return = kwargs.get("target_return", None) if target_return is None: print("Error: You have to specify the target_return!") return None, None, None, None else: op.efficient_return(target_return) # elif (objective == 'max_quadratic_utility'): # op.max_quadratic_utility(risk_aversion) # # print("Using MAX_QUADRATIC UTILITY") opt_weights = op.clean_weights() if get_entire_frontier: opt_returns, opt_risks, _ = op.efficient_frontier(points=200) return opt_weights, opt_returns, opt_risks else: return opt_weights, None, None