def test_portfolio_performance(): """ Cover logic in base_optimizer.portfolio_performance not covered elsewhere. """ ef = setup_efficient_frontier() ef.min_volatility() expected = ef.portfolio_performance() # Cover verbose logic assert (portfolio_performance(ef.weights, ef.expected_returns, ef.cov_matrix, True) == expected) # Internal ticker creations when weights param is a dict and ... w_dict = dict(zip(ef.tickers, ef.weights)) # ... expected_returns is a Series er = pd.Series(ef.expected_returns, index=ef.tickers) assert portfolio_performance(w_dict, er, ef.cov_matrix) == expected # ... cov_matrix is a DataFrame cov = pd.DataFrame(data=ef.cov_matrix, index=ef.tickers, columns=ef.tickers) assert portfolio_performance(w_dict, ef.expected_returns, cov) == expected # Will only support 'tickers' as dict keys that are ints starting from zero. w_dict = dict(zip(range(len(ef.weights)), ef.weights)) assert portfolio_performance(w_dict, ef.expected_returns, ef.cov_matrix) == expected # Weights must not sum to zero. w_dict = dict(zip(range(len(ef.weights)), np.zeros(len(ef.weights)))) with pytest.raises(ValueError): portfolio_performance(w_dict, ef.expected_returns, ef.cov_matrix)
def get_allocation_MPT(tickers, objective, history=500, get_mpt_adjustment=None, date=None, **kwargs): _, df_prices = get_ticker_prices(tickers, history=history, date=date) if objective == "hrp": weights = hrp_portfolio(df_prices) else: returns_model = kwargs.get('returns_model', 'mean_historical_return') risk_model = kwargs.get('risk_model', 'ledoit_wolf') frequency = kwargs.get('frequency', 252) timezone = kwargs.get('timezone', 'US/Mountain') tz = pytz.timezone(timezone) t_end = datetime.now(tz) if date is None else date mu, S = get_mu_sigma(df_prices, returns_model, risk_model, frequency) if (get_mpt_adjustment is None): weights, _, _ = optimal_portfolio(mu, S, objective, get_entire_frontier=False, **kwargs) else: w_max_sharpe, opt_ret, opt_risk = optimal_portfolio( mu, S, objective, get_entire_frontier=True) r, v, _ = portfolio_performance(mu, S, w_max_sharpe) ga_model = kwargs.get('ga_model', 'SMPT_GA_MAX_RET_p200_g5_s2020') with open(f"../../../backend/data/ga/{ga_model}.pickle", "rb+") as f: top10_max_ret = pickle.load(f) kwargs['weights'] = top10_max_ret[0] v_adjusted = get_mpt_adjustment(t_end, v, **kwargs) weights, _, _ = optimal_portfolio( mu, S, "efficient_risk", get_entire_frontier=False, **{"target_volatility": v_adjusted}) weights = {k: Decimal(v) for k, v in weights.items()} return weights
def get_weights(self, context, prices): if self.objective == "hrp": # Hierarchical Risk Parity weights = hrp_portfolio(prices) else: # Modern Portfolio Theory mu, S = get_mu_sigma(prices, self.returns_model, self.risk_model, self.frequency) if (self.get_mpt_adjustment is None): weights, _, _ = optimal_portfolio(mu, S, self.objective, get_entire_frontier=False, **self.kwargs) else: w_max_sharpe, opt_ret, opt_risk = optimal_portfolio(mu, S, self.objective, get_entire_frontier=True) r, v, _ = portfolio_performance(mu, S, w_max_sharpe) v_adjusted = self.get_mpt_adjustment(context.datetime, v, **self.kwargs) weights, _, _ = optimal_portfolio(mu, S, "efficient_risk", get_entire_frontier=False, **{"target_volatility": v_adjusted}) if type(weights) == dict: weights = list(weights.values()) return weights
def generate_markowitz_bullet(prices, returns_model='mean_historical_return', risk_model='ledoit_wolf', frequency=252, span=500, objective='max_sharpe', num_random=20000, ax=None, plot_individual=True, verbose=True, visualise=True): """Plot the markowitz bullet taking reference for plotting style from https://towardsdatascience.com/efficient-frontier-portfolio-optimisation-in-python-e7844051e7f Arguments: prices (pd.DataFrame) – adjusted closing prices of the asset, each row is a date and each column is a ticker/id. returns_model (string, optional) - Model for estimating expected returns of assets, either 'mean_historical_return' or 'ema_historical_return' (default: mean_historical_return) risk_model (string, optional) - Risk model to quantify risk: sample_cov, ledoit_wolf, defaults to ledoit_wolf, as recommended by Quantopian in their lecture series on quantitative finance. frequency (int, optional) – number of time periods in a year, defaults to 252 (the number of trading days in a year) span (int, optional) – Applicable only for 'ema_historical_return' expected returns. The time-span for the EMA, defaults to 500-day EMA) objective (string, optional) - Optimise for either 'max_sharpe', or 'min_volatility', defaults to 'max_sharpe' num_random (int, optional) - Number of random portfolios to generate for Markowitz Bullet. Set to 0 if not required plot_individual (boolean, optional) - If True, plots individual stocks on chart as well verbose (boolean, optional) - If True, prints out optimum portfolio allocations visualise (boolean, optional) - If True, plots Markowitz bullet Returns: r_volatility, r_returns, opt_volatility, opt_returns where r_volatility - array containing expected annual volatility values for generated random portfolios r_returns - array containg expected annual returns values for generated random portfolios opt_volatility - array containing expected annual volatility values along the efficient frontier opt_returns - array containing expected annual returns values along the efficient frontier """ mu, S = get_mu_sigma(prices, returns_model, risk_model, frequency, span) opt_weights, opt_returns, opt_volatility = optimal_portfolio(mu, S, None, True) if (verbose): print("-"*80 + "\nMaximum Sharpe Ratio Portfolio Allocation\n") max_sharpe_returns, max_sharpe_volatility, max_sharpe_ratio = portfolio_performance(mu, S, opt_weights[0], verbose) if (verbose): print("-"*80 + "\nMinimum Volatility Portfolio Allocation\n") min_vol_returns, min_vol_volatility, min_vol_ratio = portfolio_performance(mu, S, opt_weights[1], verbose) if (visualise): plt.style.use('fivethirtyeight') if (ax is None): fig, ax = plt.subplots(figsize=(12, 8)) # Plot Efficient Frontier (Annualised returns vs annualised volatility) ax.plot(opt_volatility, opt_returns, linestyle='-.', linewidth=1, color='black', label='Efficient frontier') # Plot optimum portfolios ax.plot(max_sharpe_volatility, max_sharpe_returns, 'r*', label='Max Sharpe', markersize=20) ax.plot(min_vol_volatility, min_vol_returns, 'g*', label='Min Volatility', markersize=20) # Plot individual stocks in 'prices' pandas dataframe if plot_individual: stock_names = list(prices.columns) s_returns = [] s_volatility = [] for i in range(len(stock_names)): w = [0] * len(stock_names) w[i] = 1 s_returns, s_volatility, _ = portfolio_performance(mu, S, w) ax.plot(s_volatility, s_returns, 'o', markersize=10) ax.annotate(stock_names[i], (s_volatility, s_returns), xytext=(10, 0), textcoords='offset points') # Generate random portfolios if (num_random > 0): r_returns, r_volatility, r_sharpe = tuple(zip(*[portfolio_performance(mu, S, rand_weights(len(mu))) for _ in range(num_random)])) ax.scatter(r_volatility, r_returns, c=r_sharpe, cmap='YlGnBu', marker='o', s=10, alpha=0.3) # random portfolios, colormap based on sharpe ratio # Set graph's axes ax.set_title('Markowitz Bullet') ax.set_xlabel('annualised volatility') ax.set_ylabel('annualised returns') ax.legend() plt.style.use('default') return r_volatility, r_returns, opt_volatility, opt_returns