def optimizePortEfficient(port, weights, start, plot = False, short = False, printBasicStats=True, how = 'Sharpe'): #Getting Data df = bpf.getData(port, start) #Plotting the portfolio if plot: bpf.plotPort(df, port) if printBasicStats: bpf.basicStats(df, weights, start) #Optimization for Sharpe using Efficient Frontier if short: bounds = (-1,1) else: bounds = (0,1) mu = df.pct_change().mean() * 252 S = risk_models.sample_cov(df) #Method and constraints for optimization if how == 'Sharpe': # Maximized on Sharpe Ratio ef = EfficientFrontier(mu, S, weight_bounds=bounds) #Here the weight bounds are being used to allow short positions as well weights = ef.max_sharpe() cleaned_weights = dict(ef.clean_weights()) print("Weights of an optimal portfolio maximised on Sharpe Ratio:") print(cleaned_weights) ef.portfolio_performance(verbose = True) bpf.getDiscreteAllocations(df, weights) plotting.plot_weights(weights) return weights elif how == "Vol": # Minimized on Volatility efi = EfficientFrontier(mu, S, weight_bounds=bounds) w = dict(efi.min_volatility()) print("Weights of an optimal portfolio minimized on Volatilty (Risk):") print(w) efi.portfolio_performance(verbose = True) bpf.getDiscreteAllocations(df, w) plotting.plot_weights(w) return w elif how == "targetRisk": #Optimized for a given target risk efi = EfficientFrontier(mu, S, weight_bounds=bounds) efi.efficient_risk(0.25) w = dict(efi.clean_weights()) if w ==None: print("No portfolio possible at the given risk level") else: print("Weights of an optimal portfolio for given risk:") print(w) efi.portfolio_performance(verbose = True) bpf.getDiscreteAllocations(df, w) plotting.plot_weights(w) return w
def test_custom_convex_objective_market_neutral_efficient_risk(): target_risk = 0.19 ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) ef.efficient_risk(target_risk, market_neutral=True) built_in = ef.weights # Recreate the market-neutral efficient_risk optimiser using this API ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) ef.add_constraint(lambda x: cp.sum(x) == 0) ef.add_constraint( lambda x: cp.quad_form(x, ef.cov_matrix) <= target_risk**2) ef.convex_objective(lambda x: -x @ ef.expected_returns, weights_sum_to_one=False) custom = ef.weights np.testing.assert_allclose(built_in, custom, atol=1e-7)
def portfolio_opt(input_return_df: pd.DataFrame, input_freq: str, solution: str, weight_bounds = (0,1), risk_aversion=1, market_neutral=False, risk_free_rate=0.0, target_volatility=0.01, target_return=0.11, returns_data=True, compounding=False): """ pyportfolioopt Portfolios Args ---------- input_return_df: pd.DataFrame historical prices only, or historical + forecasts solution: str 'max_sharpe','min_volatility','max_quadratic_utility', 'efficient_risk','efficient_return','custom' input_freq: str daily/monthly Returns ---------- weights_df: 1 x n pd.DataFrame """ if not isinstance(input_return_df, pd.DataFrame): raise ValueError("Not a valid input_price_df. Type should be a pd.DataFrame.") if not isinstance(input_freq, str): raise ValueError("Not a valid input_freq, please enter daily/monthly.") if not isinstance(solution, str): raise ValueError("Not a valid solution.") # annualized mean returns: returns.mean() * frequency mu = calculate_annualized_expected_returns(input_price_df = input_return_df, input_freq = input_freq, returns_data = returns_data, compounding = compounding) # annulized return covariance matrix: returns.cov() * frequency S = calculate_annualized_return_covariance(input_price_df = input_return_df, input_freq = input_freq, returns_data = returns_data, compounding = compounding) # Optimise for maximal Sharpe ratio ef = EfficientFrontier(mu, S, weight_bounds = weight_bounds, gamma = 0) if solution == 'max_sharpe': raw_weights = ef.max_sharpe(risk_free_rate = risk_free_rate) elif solution == 'min_volatility': raw_weights = ef.min_volatility() elif solution == 'max_quadratic_utility': raw_weights = ef.max_quadratic_utility(risk_aversion = risk_aversion, market_neutral = market_neutral) elif solution == 'efficient_risk': raw_weights = ef.efficient_risk(target_volatility = target_volatility, market_neutral = market_neutral) elif solution == 'efficient_return': raw_weights = ef.efficient_return(target_return = target_return, market_neutral = market_neutral) elif solution == 'custom': print('Outside Implement Required.') return None date = input_return_df.index[-1] # the date on which weights are calculated weights_df = pd.DataFrame(raw_weights, columns = raw_weights.keys(), index=[date]) return weights_df
def mean_var(my_portfolio, vol_max=0.15, perf=True) -> list: # changed to take in desired timeline, the problem is that it would use all historical data ohlc = yf.download( my_portfolio.portfolio, start=my_portfolio.start_date, end=my_portfolio.end_date, progress=False, ) prices = ohlc["Adj Close"].dropna(how="all") prices = prices.filter(my_portfolio.portfolio) # sometimes we will pick a date range where company isn't public we can't set price to 0 so it has to go to 1 prices = prices.fillna(1) mu = expected_returns.capm_return(prices) S = risk_models.CovarianceShrinkage(prices).ledoit_wolf() ef = EfficientFrontier(mu, S) ef.add_objective(objective_functions.L2_reg, gamma=my_portfolio.diversification) if my_portfolio.min_weights is not None: ef.add_constraint(lambda x: x >= my_portfolio.min_weights) if my_portfolio.max_weights is not None: ef.add_constraint(lambda x: x <= my_portfolio.max_weights) ef.efficient_risk(vol_max) weights = ef.clean_weights() wts = weights.items() result = [] for val in wts: a, b = map(list, zip(*[val])) result.append(b) if perf is True: ef.portfolio_performance(verbose=True) return flatten(result)
def test_efficient_risk_exp_cov_market_neutral(): df = get_data() ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) ef.cov_matrix = risk_models.exp_cov(df) w = ef.efficient_risk(0.19, market_neutral=True) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 0) assert (ef.weights < 1).all() and (ef.weights > -1).all() np.testing.assert_allclose( ef.portfolio_performance(), (0.3908928033782067, 0.18999999995323363, 1.9520673866815672), atol=1e-6, )
def test_efficient_risk_exp_cov_market_neutral(): df = get_data() ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) ef.cov_matrix = risk_models.exp_cov(df) w = ef.efficient_risk(0.19, market_neutral=True) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 0) assert (ef.weights < 1).all() and (ef.weights > -1).all() np.testing.assert_allclose( ef.portfolio_performance(), (0.3934093962620499, 0.18999999989011893, 1.9653126130421081), atol=1e-6, )
def test_efficient_risk_market_neutral_L2_reg(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) ef.add_objective(objective_functions.L2_reg) w = ef.efficient_risk(0.19, market_neutral=True) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 0) assert (ef.weights < 1).all() and (ef.weights > -1).all() np.testing.assert_allclose( ef.portfolio_performance(), (0.10755645826336145, 0.11079556786108302, 0.7902523535340413), atol=1e-6, )
def test_efficient_risk_market_neutral_L2_reg(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) ef.add_objective(objective_functions.L2_reg) w = ef.efficient_risk(0.19, market_neutral=True) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 0) assert (ef.weights < 1).all() and (ef.weights > -1).all() np.testing.assert_allclose( ef.portfolio_performance(), (0.12790320789339854, 0.1175336636355454, 0.9180621496492316), atol=1e-6, )
def test_efficient_risk_market_neutral(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) w = ef.efficient_risk(0.21, market_neutral=True) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 0) assert (ef.weights < 1).all() and (ef.weights > -1).all() np.testing.assert_allclose( ef.portfolio_performance(), (0.2552600197428133, 0.21, 1.1202858085349783), atol=1e-6, ) sharpe = ef.portfolio_performance()[2] ef_long_only = setup_efficient_frontier() ef_long_only.efficient_risk(0.21) long_only_sharpe = ef_long_only.portfolio_performance()[2] assert long_only_sharpe > sharpe
def test_efficient_risk_market_neutral(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) w = ef.efficient_risk(0.21, market_neutral=True) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 0) assert (ef.weights < 1).all() and (ef.weights > -1).all() np.testing.assert_allclose( ef.portfolio_performance(), (0.28640632960825885, 0.20999999995100788, 1.2686015698590967), atol=1e-6, ) sharpe = ef.portfolio_performance()[2] ef_long_only = setup_efficient_frontier() ef_long_only.efficient_risk(0.21) long_only_sharpe = ef_long_only.portfolio_performance()[2] assert long_only_sharpe > sharpe
def test_efficient_risk_short(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) w = ef.efficient_risk(0.19) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 1) np.testing.assert_allclose( ef.portfolio_performance(), (0.30468522897430295, 0.19, 1.4983424153337392), atol=1e-6, ) sharpe = ef.portfolio_performance()[2] ef_long_only = setup_efficient_frontier() ef_long_only.efficient_risk(0.19) long_only_sharpe = ef_long_only.portfolio_performance()[2] assert sharpe > long_only_sharpe
def test_efficient_risk_short(): ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) w = ef.efficient_risk(0.19) assert isinstance(w, dict) assert set(w.keys()) == set(ef.tickers) np.testing.assert_almost_equal(ef.weights.sum(), 1) np.testing.assert_allclose( ef.portfolio_performance(), (0.30035471606347336, 0.1900000003049494, 1.4755511348079207), atol=1e-6, ) sharpe = ef.portfolio_performance()[2] ef_long_only = setup_efficient_frontier() ef_long_only.efficient_risk(0.19) long_only_sharpe = ef_long_only.portfolio_performance()[2] assert sharpe > long_only_sharpe
ef_maxsharpe = EfficientFrontier(exp_ret, S) ef_maxsharpe.max_sharpe(risk_free_rate=0.005) weights_maxsharpe = ef_maxsharpe.clean_weights() weights_maxsharpe ef_maxsharpe.portfolio_performance(verbose=True) # max quadratic utility ef_maxquad = EfficientFrontier(exp_ret, S, weight_bounds=(0.025, 0.15)) ef_maxquad.max_quadratic_utility(risk_aversion=1, market_neutral=False) weights_maxquad = ef_maxquad.clean_weights() weights_maxquad ef_maxquad.portfolio_performance(verbose=True) # efficient risk ef_effrisk = EfficientFrontier(exp_ret, S, weight_bounds=(0.0, 0.15)) ef_effrisk.efficient_risk(0.15, market_neutral=False) weights_effrisk = ef_effrisk.clean_weights() weights_effrisk ef_effrisk.portfolio_performance(verbose=True) # efficient return ef_effret = EfficientFrontier(exp_ret, S, weight_bounds=(0.03, 0.15)) ef_effret.efficient_return(target_return=0.30, market_neutral=False) weights_effret = ef_effret.clean_weights() weights_effret ef_effret.portfolio_performance(verbose=True) def minimize_negative_skew(w, skew, negative=True): """ Calculate the (negative) "Skew" of a portfolio
'MA': 0.0236174643376172, 'PFE': 0.1, 'JPM': 0.0044154412364586, 'SBUX': 0.0453107516879149} Expected annual return: 22.7% Annual volatility: 12.7% Sharpe Ratio: 1.63 """ # A long/short portfolio maximising return for a target volatility of 10%, # with a shrunk covariance matrix risk model shrink = risk_models.CovarianceShrinkage(df) S = shrink.ledoit_wolf() ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) weights = ef.efficient_risk(target_volatility=0.10) ef.portfolio_performance(verbose=True) """ Expected annual return: 21.0% Annual volatility: 16.8% Sharpe Ratio: 1.13 """ # A market-neutral Markowitz portfolio finding the minimum volatility # for a target return of 20%, taking into account transaction costs. ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) # pretend we were initially equal-weighted old_weights = np.array([1 / ef.n_assets] * ef.n_assets) ef.add_objective(objective_functions.transaction_cost, w_prev=old_weights) weights = ef.efficient_return(target_return=0.20, market_neutral=True)
pd.Series(weights).plot.pie(figsize=(10, 10)) # In[21]: """ As we may check from the output, only part of the stocks compounding the Ibovespa index were selected to be part of our SP maximised portfolio. Let's now conduct some exercises, obtaining other portfolios for different risks. Let's remember that, according to the model for a long-only portfolio, the investor would maximise the SP by taking 11.4% of expected risk, or volatility. What if the investor is a risk-lover, and is willing to invest in a riskier portfolio to increase the odds of higher returns? """ # In[22]: ef = EfficientFrontier(mu, S) ef.efficient_risk(target_volatility=0.15) weights = ef.clean_weights() weights # In[23]: 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[24]: ef.portfolio_performance(verbose=True) # In[25]: """ Comparing this portfolio with 15% of risk, higher than the natural portfolio maximising the SP for the lowest
'MA': 0.0236174643376172, 'PFE': 0.1, 'JPM': 0.0044154412364586, 'SBUX': 0.0453107516879149} Expected annual return: 22.7% Annual volatility: 12.7% Sharpe Ratio: 1.63 """ # A long/short portfolio maximising return for a target volatility of 10%, # with a shrunk covariance matrix risk model shrink = risk_models.CovarianceShrinkage(df) S = shrink.ledoit_wolf() ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) weights = ef.efficient_risk(target_risk=0.10) ef.portfolio_performance(verbose=True) """ Expected annual return: 21.0% Annual volatility: 16.8% Sharpe Ratio: 1.13 """ # A market-neutral Markowitz portfolio finding the minimum volatility # for a target return of 20%, taking into account transaction costs. ef = EfficientFrontier(mu, S, weight_bounds=(-1, 1)) # pretend we were initially equal-weighted old_weights = np.array([1 / ef.n_assets] * ef.n_assets) ef.add_objective(objective_functions.transaction_cost, w_prev=old_weights) weights = ef.efficient_return(target_return=0.20, market_neutral=True)
def generate_outlook(t): df = pd.read_csv("index-125.csv", index_col=None, header=0)## read index d2=get_prices(df)# put index in correct way ###build dates w="-05-27" a=t+w x=str(pd.to_numeric(a[:4])+1)+a[4:] y=str(pd.to_numeric(a[:4])+2)+a[4:] ##find index returns index_t0=d2.loc[a:x] d3=index_t0.sort_index() returns3 =d3.iloc[:,0] returns3=pd.to_numeric(returns3) index_t0 = raw_return(prices=returns3, lag=True) target=qs.stats.volatility(index_t0) #for protfolio for t0 d1=pd.read_csv("prices.csv",parse_dates=True, index_col="תאריך")##read data stocks_t0=d1.dropna(thresh=len(d1) , axis=1) m1 = expected_returns.mean_historical_return(stocks_t0) m2=m1[m1 < m1.quantile(.95)]##drop top 5% stocks_t0=stocks_t0[m2.index] stocks_t0=stocks_t0.sort_index() stocks_t0=stocks_t0.loc[a:x] stocks_t0=stocks_t0.dropna(thresh=len(stocks_t0) , axis=1) stocks_t0=stocks_t0.sort_index(ascending=False) S=risk_models.risk_matrix(stocks_t0,frequency=len(stocks_t0)) mu=expected_returns.mean_historical_return(stocks_t0,frequency=len(stocks_t0)) ef = EfficientFrontier(mu, S) ##target=target+0.017##use this if target is not correct weights = ef.efficient_risk(target_volatility=target)##build weights for EF ef.portfolio_performance(verbose=True) wei=pd.Series(weights)#change to pandas series d7=stocks_t0.pct_change().dropna() d7=d7[wei.index] returns1=wei*d7 d8=returns1.sum(axis=1) portfolio_t0=d8.sort_index() name_index_t0="index_t0"+str(t)+".html" name_portfolio_t0="portfolio_t0"+str(t)+".html" qs.reports.html(index_t0,output=name_index_t0) qs.reports.html(portfolio_t0,output=name_portfolio_t0) #year t1 df3=d1.dropna(thresh=len(d1) , axis=1) df3=df3.sort_index() stocks_t0=df3.loc[x:y] stocks_returns = raw_return(prices=stocks_t0,lag=True) new_rets=stocks_returns[wei.index] protfiolio=wei*new_rets port_t1=protfiolio.sum(axis=1) df = pd.read_csv("index-125.csv", index_col=None, header=0) d2=get_prices(df) index_t1=d2.loc[x:y] index_t1=index_t1.sort_index() returns3 =index_t1.iloc[:,0] returns3=pd.to_numeric(returns3) index_t1 = raw_return(prices=returns3, lag=True) qs.reports.metrics(port_t1,mode='full') name_index_t1="index_t1"+str(t)+".html" name_portfolio_t1="portfolio_t1"+str(t)+".html" name_compare_graph="compare_graph_t1"+str(t)+".html" qs.reports.html(index_t1,output=name_index_t1) qs.reports.html(port_t1,output=name_portfolio_t1) qs.reports.html(port_t1,index_t1,output=name_compare_graph)