def display_ef( stocks: List[str], period: str = "3mo", n_portfolios: int = 300, risk_free: bool = False, ): """Display efficient frontier Parameters ---------- stocks : List[str] List of the stocks to be included in the weights other_args : List[str] argparse other args """ fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) ef, rets, stds = optimizer_model.generate_random_portfolios( stocks, period, n_portfolios) # The ef needs to be deep-copied to avoid error in plotting sharpe ef2 = copy.deepcopy(ef) sharpes = rets / stds ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r") for ticker, ret, std in zip(ef.tickers, ef.expected_returns, np.sqrt(np.diag(ef.cov_matrix))): ax.annotate(ticker, (std * 1.01, ret)) plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True) # Find the tangency portfolio rfrate = get_rf() ef2.max_sharpe(risk_free_rate=rfrate) ret_sharpe, std_sharpe, _ = ef2.portfolio_performance( verbose=True, risk_free_rate=rfrate) ax.scatter(std_sharpe, ret_sharpe, marker="*", s=100, c="r", label="Max Sharpe") # Add risk free line if risk_free: y = ret_sharpe * 1.2 b = get_rf() m = (ret_sharpe - b) / std_sharpe x2 = (y - b) / m x = [0, x2] y = [b, y] line = Line2D(x, y, color="#FF0000", label="Capital Allocation Line") ax.set_xlim(xmin=min(stds) * 0.8) ax.add_line(line) ax.set_title(f"Efficient Frontier simulating {n_portfolios} portfolios") ax.legend() fig.tight_layout() ax.grid(b=True, which="major", color="#666666", linestyle="-") if gtff.USE_ION: plt.ion() plt.show() console.print("")
def show_ef(stocks: List[str], other_args: List[str]): parser = argparse.ArgumentParser(add_help=False, prog="ef") parser.add_argument( "-p", "--period", default="3mo", dest="period", help="period to get yfinance data from", choices=period_choices, ) parser.add_argument( "-n", default=300, dest="n_port", help="number of portfolios to simulate" ) try: ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return if len(stocks) < 2: print("Please have at least 2 loaded tickers to calculate weights.\n") return stock_prices = process_stocks(stocks, ns_parser.period) mu = expected_returns.mean_historical_return(stock_prices) S = risk_models.sample_cov(stock_prices) ef = EfficientFrontier(mu, S) fig, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) # Generate random portfolios n_samples = ns_parser.n_port w = np.random.dirichlet(np.ones(len(mu)), n_samples) rets = w.dot(mu) stds = np.sqrt(np.diag(w @ S @ w.T)) sharpes = rets / stds ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r") plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True) # Find the tangency portfolio ef.max_sharpe() ret_sharpe, std_sharpe, _ = ef.portfolio_performance() ax.scatter(std_sharpe, ret_sharpe, marker="*", s=100, c="r", label="Max Sharpe") ax.set_title("Efficient Frontier") ax.legend() plt.tight_layout() plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) if gtff.USE_ION: plt.ion() plt.show() print("") except Exception as e: print(e) print("")
def plot_stock_insights(stock_price, Portfolio): mu = expected_returns.mean_historical_return(stock_price) S = risk_models.sample_cov(stock_price) ef = EfficientFrontier(mu, S) cleaned_weights = ef.clean_weights() cla = CLA(mu, S) plotting.plot_efficient_frontier(cla) plotting.plot_covariance(S) plotting.plot_weights(cleaned_weights)
def test_cla_plot_ax(): plt.figure() df = get_data() rets = expected_returns.mean_historical_return(df) S = risk_models.exp_cov(df) cla = CLA(rets, S) fig, ax = plt.subplots(figsize=(12, 10)) plotting.plot_efficient_frontier(cla, ax=ax) assert len(ax.findobj()) == 143 plt.close() plt.close()
def test_cla_plot(): df = get_data() rets = expected_returns.mean_historical_return(df) S = risk_models.exp_cov(df) cla = CLA(rets, S) ax = plotting.plot_efficient_frontier(cla, showfig=False) assert len(ax.findobj()) == 143 ax = plotting.plot_efficient_frontier(cla, show_assets=False, showfig=False) assert len(ax.findobj()) == 161
def test_default_ef_plot(): plt.figure() ef = setup_efficient_frontier() ax = plotting.plot_efficient_frontier(ef, show_assets=True) assert len(ax.findobj()) == 125 plt.clf() # with constraints ef = setup_efficient_frontier() ef.add_constraint(lambda x: x <= 0.15) ef.add_constraint(lambda x: x[0] == 0.05) ax = plotting.plot_efficient_frontier(ef) assert len(ax.findobj()) == 125 plt.clf() plt.close()
def test_plotting_edge_case(): # raised in issue #333 mu = pd.Series([0.043389, 0.036194]) S = pd.DataFrame([[0.000562, 0.002273], [0.002273, 0.027710]]) ef = EfficientFrontier(mu, S) fig, ax = plt.subplots() with pytest.warns(UserWarning): plotting.plot_efficient_frontier( ef, ef_param="return", ef_param_range=np.linspace(0.036194, 0.043389, 10), ax=ax, show_assets=False, )
def test_ef_plot_utility(): ef = setup_efficient_frontier() delta_range = np.arange(0.001, 100, 1) ax = plotting.plot_efficient_frontier(ef, ef_param_range=delta_range, showfig=False) assert len(ax.findobj()) == 125
def test_ef_plot_errors(): plt.figure() ef = setup_efficient_frontier() delta_range = np.arange(0.001, 50, 1) # Test invalid ef_param with pytest.raises(NotImplementedError): plotting.plot_efficient_frontier( ef, ef_param="blah", ef_param_range=delta_range, showfig=False ) # Test invalid optimizer with pytest.raises(NotImplementedError): plotting.plot_efficient_frontier( None, ef_param_range=delta_range, showfig=False ) plt.clf() plt.close()
def ef_plot_return(): ef = setup_efficient_frontier() return_range = np.linspace(0, ef.expected_returns.max(), 50) ax = plotting.plot_efficient_frontier(ef, ef_param="return", ef_param_range=return_range, showfig=False) assert len(ax.findobj()) == 125
def test_ef_plot_utility_short(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(None, None)) delta_range = np.linspace(0.001, 20, 100) ax = plotting.plot_efficient_frontier(ef, ef_param_range=delta_range, showfig=False) assert len(ax.findobj()) == 161
def test_default_ef_plot_labels(): plt.figure() ef = setup_efficient_frontier() ax = plotting.plot_efficient_frontier(ef, show_assets=True, show_tickers=True) assert len(ax.findobj()) == 124 + len(ef.tickers) plt.clf()
def test_ef_plot_utility(): plt.figure() ef = setup_efficient_frontier() delta_range = np.arange(0.001, 50, 1) ax = plotting.plot_efficient_frontier( ef, ef_param="utility", ef_param_range=delta_range, showfig=False ) assert len(ax.findobj()) == 125 plt.clf() plt.close()
def test_constrained_ef_plot_utility(): ef = setup_efficient_frontier() ef.add_constraint(lambda w: w[0] >= 0.2) ef.add_constraint(lambda w: w[2] == 0.15) ef.add_constraint(lambda w: w[3] + w[4] <= 0.10) delta_range = np.linspace(0.001, 20, 100) ax = plotting.plot_efficient_frontier(ef, ef_param_range=delta_range, showfig=False) assert len(ax.findobj()) == 125
def test_ef_plot_return(): plt.figure() ef = setup_efficient_frontier() # Internally _max_return() is used, so subtract epsilon max_ret = ef.expected_returns.max() - 0.0001 return_range = np.linspace(0, max_ret, 30) ax = plotting.plot_efficient_frontier( ef, ef_param="return", ef_param_range=return_range, showfig=False ) assert len(ax.findobj()) == 125 plt.clf() plt.close()
def test_ef_plot_risk(): ef = setup_efficient_frontier() ef.min_volatility() min_risk = ef.portfolio_performance()[1] ef = setup_efficient_frontier() risk_range = np.linspace(min_risk + 0.05, 0.5, 50) ax = plotting.plot_efficient_frontier(ef, ef_param="risk", ef_param_range=risk_range, showfig=False) assert len(ax.findobj()) == 125
def plot_stock_insights(self, scatter=False): ef = EfficientFrontier(self.mu, self.S) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() cla = CLA(self.mu, self.S) try: eff_front = plotting.plot_efficient_frontier(cla) eff_front.tick_params(axis='both', which='major', labelsize=5) eff_front.tick_params(axis='both', which='minor', labelsize=5) eff_front.get_figure().savefig(os.path.join( self.output_path, "efficient_frontier.png"), dpi=300) except: print("Failed to plot efficient frontier") cov = plotting.plot_covariance(self.S) weights_bar = plotting.plot_weights(cleaned_weights) if self.save_output: cov.tick_params(axis='both', which='major', labelsize=5) cov.tick_params(axis='both', which='minor', labelsize=5) cov.get_figure().savefig(os.path.join(self.output_path, "cov_matrix.png"), dpi=300) weights_bar.tick_params(axis='both', which='major', labelsize=5) weights_bar.tick_params(axis='both', which='minor', labelsize=5) weights_bar.get_figure().savefig(os.path.join( self.output_path, "weights_bar.png"), dpi=300) retscomp = self.stock_prices.pct_change() corrMatrix = retscomp.corr() corr_heat = sns.heatmap(corrMatrix, xticklabels=True, yticklabels=True) plt.title("Corr heatmap") if self.save_output: corr_heat.tick_params(axis='both', which='major', labelsize=5) corr_heat.tick_params(axis='both', which='minor', labelsize=5) fig = corr_heat.get_figure() fig.figsize = (10, 10) fig.savefig(os.path.join(self.output_path, "corr_heatmap.png"), dpi=300) plt.show() if scatter: plt.figure() plt.title("Corr scatter") self.scattermat = pd.plotting.scatter_matrix(retscomp, diagonal='kde', figsize=(10, 10)) if self.save_output: plt.savefig(os.path.join(self.output_path, "corr_scatter.png"), dpi=300) plt.show()
def test_ef_plot_return(): plt.figure() ef = setup_efficient_frontier() # FIXME: Internally _max_return() is used, which uses a solver so can have numerical differences to the inputs. # hence the epsilon here max_ret = ef.expected_returns.max() - 0.0001 return_range = np.linspace(0, max_ret, 50) ax = plotting.plot_efficient_frontier(ef, ef_param="return", ef_param_range=return_range, showfig=False) assert len(ax.findobj()) == 125 plt.clf() plt.close()
def test_constrained_ef_plot_risk(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(None, None)) ef.add_constraint(lambda w: w[0] >= 0.2) ef.add_constraint(lambda w: w[2] == 0.15) ef.add_constraint(lambda w: w[3] + w[4] <= 0.10) # 100 portfolios with risks between 0.10 and 0.30 risk_range = np.linspace(0.157, 0.40, 100) ax = plotting.plot_efficient_frontier(ef, ef_param="risk", ef_param_range=risk_range, show_assets=True, showfig=False) assert len(ax.findobj()) == 137
num_small = len([k for k in weights if weights[k] <= 1e-4]) print(f"{num_small}/{len(ef.tickers)} ticker have zero weight") # In[13]: ef.portfolio_performance(verbose=True) # In[14]: from pypfopt import CLA, plotting cla = CLA(mu, S) cla.max_sharpe() cla.portfolio_performance(verbose=True) ax = plotting.plot_efficient_frontier(cla, showfig=False) # In[15]: """ We could have a portfolio with annual vol of 11.4% and expected annual return of 22.3%. It is possible to obtain a positive SR by defining portfolios with stocks that are part of the ibovespa index. This output, despite interesting, is not useful in itself. Let's then convert it into an allocation that an investor could use to weight her own portfolio """ # In[18]: from pypfopt.discrete_allocation import DiscreteAllocation, get_latest_prices latest_prices = get_latest_prices(df)
end='2020-06-06', data_source='yahoo') price_data.append(prices.assign(ticker=ticker)[['Adj Close']]) df_stocks = pd.concat(price_data, axis=1) df_stocks.columns = tickers df_stocks.head() #Annualized Return mu = expected_returns.mean_historical_return(df_stocks) #Sample Variance of Portfolio Sigma = risk_models.sample_cov(df_stocks) #Max Sharpe Ratio - Tangent to the EF ef = EfficientFrontier(mu, Sigma, weight_bounds=(0, 1)) fig, ax = plt.subplots() plotting.plot_efficient_frontier(ef) ef.max_sharpe() ret_tangent, std_tangent, _ = ef.portfolio_performance() ax.scatter(std_tangent, ret_tangent, marker="*", s=100, c="r", label="Max Sharpe") ax.set_title("Efficient Frontier") ax.legend() plt.tight_layout() plt.show()
#Максимальный коэффициент Шарпа 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) print(
def show_ef(stocks: List[str], other_args: List[str]): """Display efficient frontier Parameters ---------- stocks : List[str] List of the stocks to be included in the weights other_args : List[str] argparse other args """ parser = argparse.ArgumentParser( add_help=False, formatter_class=argparse.ArgumentDefaultsHelpFormatter, prog="ef", description="""This function plots random portfolios based on their risk and returns and shows the efficient frontier.""", ) parser.add_argument( "-p", "--period", default="3mo", dest="period", help="period to get yfinance data from", choices=period_choices, ) parser.add_argument( "-n", "--number-portfolios", default=300, type=check_non_negative, dest="n_port", help="number of portfolios to simulate", ) try: if other_args: if "-" not in other_args[0]: other_args.insert(0, "-n") ns_parser = parse_known_args_and_warn(parser, other_args) if not ns_parser: return if len(stocks) < 2: print( "Please have at least 2 loaded tickers to calculate weights.\n" ) return stock_prices = process_stocks(stocks, ns_parser.period) mu = expected_returns.mean_historical_return(stock_prices) S = risk_models.sample_cov(stock_prices) ef = EfficientFrontier(mu, S) _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) # Generate random portfolios n_samples = ns_parser.n_port w = np.random.dirichlet(np.ones(len(mu)), n_samples) rets = w.dot(mu) stds = np.sqrt(np.diag(w @ S @ w.T)) sharpes = rets / stds ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r") plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True) # Find the tangency portfolio ef.max_sharpe() ret_sharpe, std_sharpe, _ = ef.portfolio_performance() ax.scatter(std_sharpe, ret_sharpe, marker="*", s=100, c="r", label="Max Sharpe") ax.set_title( f"Efficient Frontier simulating {ns_parser.n_port} portfolios") ax.legend() plt.tight_layout() plt.grid(b=True, which="major", color="#666666", linestyle="-") plt.minorticks_on() plt.grid(b=True, which="minor", color="#999999", linestyle="-", alpha=0.2) if gtff.USE_ION: plt.ion() plt.show() print("") except Exception as e: print(e, "\n")
'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) plotting.plot_efficient_frontier(cla) # to plot """ {'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, 'XOM': 0.0005100736411646903,
# df = pd.read_csv("tests/resources/stock_prices.csv", parse_dates=True, index_col="date") df = pd.read_csv(os.path.join(path, 'stock_prices.csv'), parse_dates=True, index_col="Date") returns = df.pct_change().dropna() # Calculate expected returns and sample covariance mu = expected_returns.mean_historical_return(df) S = risk_models.sample_cov(df) # Optimise for maximal Sharpe ratio ef = EfficientFrontier(mu, S) raw_weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() ef.save_weights_to_file("weights.csv") # saves to file print(cleaned_weights) ef.portfolio_performance(verbose=True) latest_prices = get_latest_prices(df) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=600) allocation, leftover = da.lp_portfolio() print("Discrete allocation:", allocation) print("Funds remaining: ${:.2f}".format(leftover)) cla = CLA(mu, S) plotting.plot_efficient_frontier(cla) plotting.plot_covariance(S) plotting.plot_weights(cleaned_weights)
def display_ef( stocks: List[str], period: str = "3mo", n_portfolios: int = 300, risk_free: bool = False, external_axes: Optional[List[plt.Axes]] = None, ): """Display efficient frontier Parameters ---------- stocks : List[str] List of the stocks to be included in the weights period : str Time period to get returns for n_portfolios: int Number of portfolios to simulate external_axes: Optional[List[plt.Axes]] Optional axes to plot on """ if external_axes is None: _, ax = plt.subplots(figsize=plot_autoscale(), dpi=PLOT_DPI) else: ax = external_axes[0] ef, rets, stds = optimizer_model.generate_random_portfolios( stocks, period, n_portfolios) # The ef needs to be deep-copied to avoid error in plotting sharpe ef2 = copy.deepcopy(ef) sharpes = rets / stds ax.scatter(stds, rets, marker=".", c=sharpes) plotting.plot_efficient_frontier(ef, ax=ax, show_assets=False) for ticker, ret, std in zip(ef.tickers, ef.expected_returns, np.sqrt(np.diag(ef.cov_matrix))): ax.scatter(std, ret, s=50, marker=".", c="w") ax.annotate(ticker, (std * 1.01, ret)) # Find the tangency portfolio rfrate = get_rf() ef2.max_sharpe(risk_free_rate=rfrate) ret_sharpe, std_sharpe, _ = ef2.portfolio_performance( verbose=True, risk_free_rate=rfrate) ax.scatter(std_sharpe, ret_sharpe, marker="*", s=100, c="r", label="Max Sharpe") # Add risk free line if risk_free: y = ret_sharpe * 1.2 b = get_rf() m = (ret_sharpe - b) / std_sharpe x2 = (y - b) / m x = [0, x2] y = [b, y] line = Line2D(x, y, label="Capital Allocation Line") ax.set_xlim(xmin=min(stds) * 0.8) ax.add_line(line) ax.set_title(f"Efficient Frontier simulating {n_portfolios} portfolios") ax.legend(loc="best", scatterpoints=1) theme.style_primary_axis(ax) if external_axes is None: theme.visualize_output()
#to get a grasp how our chosen portfolio correlates with each other asset in the portfolio we state a cov heatmap plotting.plot_covariance(cov_matrix_tickers, plot_correlation=True) ##create the Efficient frontier line and visualize it #in order to visualize the efficient frontier from the optimized portfolio, we need to initiate a new built-in method #we use the CLA method, because it is more robust than the default option cla = CLA(mu_target_tickers, cov_matrix_tickers) if risk_tolerance == 'Low': cla.min_volatility() else: cla.max_sharpe() #plot the efficient frontier line ax_portfolio = plotting.plot_efficient_frontier(cla, ef_param='risk', ef_param_range=np.linspace( 0.2, 0.6, 100), points=1000) #initialize Discrete Allocation to get a full picture what you could buy with a given amount #the Discrete Allocation gives you the discrete amount of shares you have to allocate given your available funds from pypfopt import DiscreteAllocation from datetime import datetime from datetime import timedelta #create list out of sliced tickers dataframe tickers_list = tickers.index.to_list() #create a dictionary which can be used for the Discrete Allocation as an input weight_pf = {} values_pf = tickers['Weight']
def plot_ef( stocks: List[str], variance: float, per_ret: float, rf_rate: float, period: str = "3mo", n_portfolios: int = 300, risk_free: bool = False, ): """Display efficient frontier Parameters ---------- stocks : List[str] List of the stocks to be included in the weights variance : float The variance for the portfolio per_ret : float The portfolio's return for the portfolio rf_rate : float The risk free rate period : str The period to track n_portfolios : int The number of portfolios to generate risk_free : bool Include the risk-free asset """ fig, ax = plt.subplots(figsize=(10, 5), dpi=PLOT_DPI) ef, rets, stds = optimizer_model.generate_random_portfolios( [x.upper() for x in stocks], period, n_portfolios) sharpes = rets / stds ax.scatter(stds, rets, marker=".", c=sharpes, cmap="viridis_r") plotting.plot_efficient_frontier(ef, ax=ax, show_assets=True) # Find the tangency portfolio ret_sharpe, std_sharpe, _ = ef.portfolio_performance( risk_free_rate=rf_rate) ax.scatter(std_sharpe, ret_sharpe, marker="*", s=100, c="r", label="Max Sharpe") plt.plot(variance, per_ret, "ro", label="Portfolio") # Add risk free line if risk_free: y = ret_sharpe * 1.2 m = (ret_sharpe - rf_rate) / std_sharpe x2 = (y - rf_rate) / m x = [0, x2] y = [rf_rate, y] line = Line2D(x, y, color="#FF0000", label="Capital Allocation Line") ax.set_xlim(xmin=min(stds) * 0.8) ax.add_line(line) ax.set_title(f"Efficient Frontier simulating {n_portfolios} portfolios") ax.legend() fig.tight_layout() ax.grid(b=True, which="major", color="#666666", linestyle="-") if gtff.USE_ION: plt.ion() imgdata = BytesIO() fig.savefig(imgdata, format="png") plt.close("all") imgdata.seek(0) return ImageReader(imgdata)