def test_cla_min_volatility_exp_cov_short(): cla = CLA(*setup_cla(data_only=True), weight_bounds=(-1, 1)) df = get_data() cla.cov_matrix = risk_models.exp_cov(df).values w = cla.min_volatility() 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.2634735528776959, 0.13259590618253303, 1.8362071642131053), )
def test_cla_min_volatility_exp_cov_short(): cla = CLA(*setup_cla(data_only=True), weight_bounds=(-1, 1)) df = get_data() cla.cov_matrix = risk_models.exp_cov(df).values w = cla.min_volatility() 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.23215576461823062, 0.1325959061825329, 1.6000174569958052), )
def test_cla_custom_bounds(): bounds = [(0.01, 0.13), (0.02, 0.11)] * 10 cla = CLA(*setup_cla(data_only=True), weight_bounds=bounds) df = get_data() cla.cov_matrix = risk_models.exp_cov(df).values w = cla.min_volatility() assert isinstance(w, dict) assert set(w.keys()) == set(cla.tickers) np.testing.assert_almost_equal(cla.weights.sum(), 1) assert (0.01 <= cla.weights[::2]).all() and (cla.weights[::2] <= 0.13).all() assert (0.02 <= cla.weights[1::2]).all() and (cla.weights[1::2] <= 0.11).all()
def setup_cla(data_only=False): df = get_data() mean_return = expected_returns.mean_historical_return(df) sample_cov_matrix = risk_models.sample_cov(df) if data_only: return mean_return, sample_cov_matrix return CLA(mean_return, sample_cov_matrix)
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_frontier(cls, weights): cls.efficient_portfolio = CLA(cls.mean_returns_avg, cls.e_cov) (ret, vol, weight) = cls.efficient_portfolio.efficient_frontier() plt.show() def statistics(weights): pret = np.sum(cls.Stock_data_frames.mean() * weights) * 252 pvol = np.sqrt(np.dot(weights.T, np.dot(cls.e_cov, weights))) return np.array([pret, pvol, pret / pvol]) def min_func_sharpe(weights): return -statistics(weights)[2] def min_func_variance(weights): return statistics(weights)[1]**2 cons = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1}) bnds = tuple((0, 1) for x in range(cls.num_stocks)) ew = FinancialInfo.num_stocks * [1 / cls.num_stocks] cls.opts = sco.minimize(min_func_sharpe, ew, method='SlSQP', bounds=bnds, constraints=cons) cls.optv = sco.minimize(min_func_variance, ew, method='SlSQP', bounds=bnds, constraints=cons) plt.figure(figsize=(10, 4)) plt.scatter(cls.pvol, cls.prets, c=cls.prets / cls.pvol, marker='o', cmap='RdYlBu') plt.scatter(vol, ret, s=4, c='g', marker='x') plt.plot(statistics(cls.opts['x'])[1], statistics(cls.opts['x'])[0], 'r*', markersize=15) plt.plot(statistics(cls.optv['x'])[1], statistics(cls.optv['x'])[0], 'y*', markersize=15) plt.grid = True plt.xlabel('expected volatility') plt.ylabel('expected return') plt.colorbar(label='Sharpe ratio')
def test_cla_custom_bounds(): bounds = [(0.01, 0.13), (0.02, 0.11)] * 10 cla = CLA(*setup_cla(data_only=True), weight_bounds=bounds) df = get_data() cla.cov_matrix = risk_models.exp_cov(df).values w = cla.min_volatility() assert isinstance(w, dict) assert set(w.keys()) == set(cla.tickers) np.testing.assert_almost_equal(cla.weights.sum(), 1) assert (0.01 <= cla.weights[::2]).all() and (cla.weights[::2] <= 0.13).all() assert (0.02 <= cla.weights[1::2]).all() and (cla.weights[1::2] <= 0.11).all() # Test polymorphism of the weight_bounds param. bounds2 = ([bounds[0][0], bounds[1][0]] * 10, [bounds[0][1], bounds[1][1]] * 10) cla2 = CLA(*setup_cla(data_only=True), weight_bounds=bounds2) cla2.cov_matrix = risk_models.exp_cov(df).values w2 = cla2.min_volatility() assert dict(w2) == dict(w)
def calculateInvestment(limit=10, count=10, write_to_file=True, show_cla=False, tpv=20000): symbols = getSymbolsFromDatabase() prices = createDataFrame(symbols[:limit], count) mu = expected_returns.mean_historical_return(prices) S = risk_models.CovarianceShrinkage(prices).ledoit_wolf() ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) ef.add_objective(objective_functions.L2_reg) ef.min_volatility() c_weights = ef.clean_weights() if write_to_file == True: ef.save_weights_to_file("weights.txt") if show_cla == True: cla = CLA(mu, S) ef_plot(cla) ef.portfolio_performance(verbose=True) latest_prices = disc_alloc.get_latest_prices(prices) allocation_minv, leftover = disc_alloc.DiscreteAllocation( c_weights, latest_prices, total_portfolio_value=tpv).lp_portfolio() return allocation_minv, leftover
Sigma = risk_models.sample_cov(df_stocks) #Максимальный коэффициент Шарпа ef = EfficientFrontier( mu, Sigma, weight_bounds=(0, 1)) #weight bounds in negative allows shorting of stocks sharpe_pfolio = ef.max_sharpe( ) #May use add objective to ensure minimum zero weighting to individual stocks sharpe_pwt = ef.clean_weights() print(sharpe_pwt) ef.portfolio_performance(verbose=True) ef1 = EfficientFrontier(mu, Sigma, weight_bounds=(0, 1)) minvol = ef1.min_volatility() minvol_pwt = ef1.clean_weights() print(minvol_pwt) ef1.portfolio_performance(verbose=True, risk_free_rate=0.27) cl_obj = CLA(mu, Sigma) ax = pplt.plot_efficient_frontier(cl_obj, showfig=False) ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: '{:.0%}'.format(x))) ax.yaxis.set_major_formatter(FuncFormatter(lambda y, _: '{:.0%}'.format(y))) lalatest_prices = get_latest_prices(df_stocks) allocation_minv, rem_minv = DiscreteAllocation( minvol_pwt, latest_prices, total_portfolio_value=100000).lp_portfolio() print(allocation_minv) print( "Осталось денежных средств после построения портфеля с минимальной волатильностью - {:.2f} рублей" .format(rem_minv)) print() latest_prices1 = get_latest_prices(df_stocks) allocation_shp, rem_shp = DiscreteAllocation( sharpe_pwt, latest_prices1, total_portfolio_value=100000).lp_portfolio() print(allocation_shp)
def test_cla_two_assets(): mu = np.array([[0.02569294], [0.16203987]]) cov = np.array([[0.0012765, -0.00212724], [-0.00212724, 0.01616983]]) assert CLA(mu, cov)
def _get_efficient_weights(self): cla = CLA(self.mu, self.S) cla.max_sharpe() (mu, sigma, weights) = cla.efficient_frontier() return mu, sigma, weights
sample_cov = assets.pct_change().cov() * 252 # Compute the returns and efficient covariance for each epoch e_return = {} e_cov = {} 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,
def create_xl_EFPortfolio(df, lb, ub, resample_rule): dfReSample = create_epochs(df, resample_rule) """ # Create a dictionary of time periods (or 'epochs') epochs = { '0' : {'start': '1-1-2005', 'end': '31-12-2006'}, '1' : {'start': '1-1-2007', 'end': '31-12-2008'}, '2' : {'start': '1-1-2009', 'end': '31-12-2010'} } """ epochs = dfReSample.to_dict('index') # Compute the efficient covariance for each epoch e_return = {} e_cov = {} efficient_portfolio = {} liW = [] liR = [] for x in epochs.keys(): period = df.loc[epochs[x]['start']:epochs[x]['end']] j = (x + 1) / len(epochs.keys()) sys.stdout.write('\r') sys.stdout.write("[%-20s] %d%%" % ('=' * int(20 * j), 100 * j)) sys.stdout.flush() try: # Compute the annualized average (mean) historical return # mu = expected_returns.mean_historical_return(period)#, frequency = 252) mu = expected_returns.ema_historical_return(period, frequency=252, span=500) # Compute the efficient covariance matrix Sigma = risk_models.CovarianceShrinkage(period).ledoit_wolf() # Initialize the Crtical Line Algorithm object efficient_portfolio[x] = CLA(mu, Sigma, weight_bounds=(lb, ub)) efficient_portfolio[x].max_sharpe() # min_volatility() cleaned_weights = efficient_portfolio[x].clean_weights() e_return[x] = mu e_cov[x] = Sigma liW.append(pd.DataFrame({'epochs': x, 'weights': cleaned_weights})) liR.append(pd.DataFrame({'epochs': x, 'returns': mu})) except Exception as e: sys.stdout.write('\r') sys.stdout.write('%s%s %s%s%s\n' % ('#', x, 'error:', epochs[x], e)) dfWeightsEF = pd.concat(liW) dfWeightsEF.reset_index(inplace=True) dfWeightsEF.columns = ['asset', 'epochs', 'weights'] dfWeightsEF = dfWeightsEF.pivot(index='epochs', columns='asset', values='weights') dfReturnsEF = pd.concat(liR) dfReturnsEF.reset_index(inplace=True) dfReturnsEF.columns = ['asset', 'epochs', 'returns'] dfReturnsEF = dfReturnsEF.pivot(index='epochs', columns='asset', values='returns') dfWeightsEF.to_excel(r"weightsEF.xlsx") dfReturnsEF.to_excel(r"returnsEF.xlsx") dfReturns = df.pct_change().dropna() dfNAV = pd.merge(dfWeightsEF, dfReSample, left_index=True, right_index=True) dfNAV = dfNAV.drop(columns=['start']) dfNAV.set_index('end', inplace=True) dfNAV.index.names = ['DATE'] dfNAV = dfNAV.resample('D').ffill() dfNAV = dfNAV.loc[dfNAV.index.isin(dfReturns.index.tolist())] dfReturns = dfReturns.loc[dfReturns.index.isin(dfNAV.index.tolist())] dfNAV['RET'] = (dfNAV.values * dfReturns.values).sum(axis=1).tolist() dfNAV['NAV'] = (1 + dfNAV['RET']).cumprod() dfNAV = pd.merge(dfNAV, dfReturns, left_index=True, right_index=True, suffixes=('_weight', '_return')) dfNAV.to_excel(r"navEF.xlsx") return
'GM': 0.05557666024185722, '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,
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