for x in epochs.keys(): sub_price = assets.loc[epochs[x]['start']:epochs[x]['end']] e_return[x] = mean_historical_return(assets, frequency=252) e_cov[x] = CovarianceShrinkage(sub_price).ledoit_wolf() # Display the efficient covariance matrices for all epochs print("Efficient Covariance Matrices\n", e_cov) # Initialize the Crtical Line Algorithm object efficient_portfolio_during = CLA(e_return["during"], e_cov["during"]) # Find the minimum volatility portfolio weights and display them print(efficient_portfolio_during.min_volatility()) # Compute the efficient frontier (ret, vol, weights) = efficient_portfolio_during.efficient_frontier() # Add the frontier to the plot showing the 'before' and 'after' frontiers plt.scatter(vol, ret, s=4, c='g', marker='.', label='During') plt.legend() plt.show() # plotting using PyPortfolioOpt pplot.plot_covariance(cs, plot_correlation=False, show_tickers=True) pplot.plot_efficient_frontier(efficient_portfolio_during, points=100, show_assets=True) pplot.plot_weights(cw) # Dealing with many negligible weights # efficient portfolio allocation
def _get_efficient_weights(self): cla = CLA(self.mu, self.S) cla.max_sharpe() (mu, sigma, weights) = cla.efficient_frontier() return mu, sigma, weights
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