def max_quad_utility_weights(rets_bl, covar_bl, config): print('Begin max quadratic utility optimization') returns, sigmas, weights, deltas = [], [], [], [] for delta in np.arange(1, 10, 1): ef = EfficientFrontier(rets_bl, covar_bl, weight_bounds= \ (config['min_position_size'] ,config['max_position_size'])) ef.max_quadratic_utility(delta) ret, sigma, __ = ef.portfolio_performance() weights_vec = ef.clean_weights() returns.append(ret) sigmas.append(sigma) deltas.append(delta) weights.append(weights_vec) fig, ax = plt.subplots() ax.plot(sigmas, returns) for i, delta in enumerate(deltas): ax.annotate(str(delta), (sigmas[i], returns[i])) plt.xlabel('Volatility (%) ') plt.ylabel('Returns (%)') plt.title('Efficient Frontier for Max Quadratic Utility Optimization') plt.show() opt_delta = float( input('Enter the desired point on the efficient frontier: ')) ef = EfficientFrontier(rets_bl, covar_bl, weight_bounds= \ (config['min_position_size'] ,config['max_position_size'])) ef.max_quadratic_utility(opt_delta) opt_weights = ef.clean_weights() opt_weights = pd.DataFrame.from_dict(opt_weights, orient='index') opt_weights.columns = ['Max Quad Util'] return opt_weights, ef
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 optimizePortfolio(self, option='sharpe'): ''' Optimize for maximal Sharpe ratio / minimum volatility (Default to Sharpe) TODO: Allow for more options Return EfficientFrontier object ''' mu = self.calculateMu() S = self.calculateSampleCovarianceMatrix() ef = EfficientFrontier(mu, S) if option == 'sharpe': weights = ef.max_sharpe( ) #Maximize the Sharpe ratio, and get the raw weights elif option == 'volatility': weights = ef.min_volatility() else: raise SystemExit("Not found optimize option (Sharpe/Volatility)") self.cleaned_weights = ef.clean_weights() print( self.cleaned_weights ) #Note the weights may have some rounding error, meaning they may not add up exactly to 1 but should be close ef.portfolio_performance(verbose=True) return ef
def test_custom_tracking_error(): df = get_data() historical_rets = expected_returns.returns_from_prices(df).dropna() benchmark_rets = historical_rets["AAPL"] historical_rets = historical_rets.drop("AAPL", axis=1) S = risk_models.sample_cov(historical_rets, returns_data=True) opt = BaseConvexOptimizer( n_assets=len(historical_rets.columns), tickers=list(historical_rets.columns), weight_bounds=(0, 1), ) opt.convex_objective( objective_functions.ex_post_tracking_error, historic_returns=historical_rets, benchmark_returns=benchmark_rets, ) w = opt.clean_weights() ef = EfficientFrontier(None, S) ef.convex_objective( objective_functions.ex_post_tracking_error, historic_returns=historical_rets, benchmark_returns=benchmark_rets, ) w2 = ef.clean_weights() assert w == w2
def min_var(my_portfolio, perf=True) -> list: 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) 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.min_volatility() 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 portfolio_opt(self): portfolio = self.portfolio.split(",") df = self.db.load_data(TableName.DAY, time_from=self.time_from, symbols=portfolio) # df = FinI.add_date_col(df) df = df[["close", "sym"]] df2 = df.copy() df2 = df2.drop(columns=["close", "sym"]) for sym in portfolio: df2[sym] = df[df["sym"] == sym]["close"] df2 = df2.drop_duplicates() # df = df.transpose() # df.index = pd.to_datetime(df['date']).astype(int) / 10**9 st.write(df2) # Calculate expected returns and sample covariance mu = expected_returns.mean_historical_return(df2) S = risk_models.sample_cov(df2) # Optimize for maximal Sharp 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 st.write(cleaned_weights) mu, sigma, sharpe = ef.portfolio_performance(verbose=True) st.write("Expected annual return: {:.1f}%".format(100 * mu)) st.write("Annual volatility: {:.1f}%".format(100 * sigma)) st.write("Sharpe Ratio: {:.2f}".format(sharpe))
def allocate(df): tickers = [df.columns[k] for k in range(df.shape[1])] ohlc = yf.download(tickers, start="2010-01-01", end="2020-01-01") prices = ohlc["Adj Close"] market_prices = yf.download("^BVSP", start="2010-01-01", end="2020-01-01")["Adj Close"] mcaps = {} for t in tickers: stock = yf.Ticker(t) mcaps[t] = stock.info["marketCap"] S = risk_models.CovarianceShrinkage(prices).ledoit_wolf() delta = black_litterman.market_implied_risk_aversion(market_prices) market_prior = black_litterman.market_implied_prior_returns( mcaps, delta, S) bl = BlackLittermanModel(S, pi="market", market_caps=mcaps, risk_aversion=delta, absolute_views=df.to_dict('records')[0]) ret_bl = bl.bl_returns() S_bl = bl.bl_cov() ef = EfficientFrontier(ret_bl, S_bl) ef.add_objective(objective_functions.L2_reg) ef.max_sharpe() weights = ef.clean_weights() return weights
def max_sharpe_weights(rets_bl, covar_bl, config): ef = EfficientFrontier(rets_bl, covar_bl, weight_bounds= \ (config['min_position_size'] ,config['max_position_size'])) ef.max_sharpe() weights = ef.clean_weights() weights = pd.DataFrame.from_dict(weights, orient='index') weights.columns = ['Max Sharpe'] return weights, ef
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 optimise(portfolio_data): returns = pd.Series(get_returns(portfolio_data)) covariance_matrix = pd.DataFrame(get_cov_matrix(portfolio_data)) ef = EfficientFrontier(returns, covariance_matrix) ef.min_volatility() # max_sharpe or min_volatility cleaned_weights = ef.clean_weights() fix_keys(cleaned_weights, portfolio_data) print(cleaned_weights) ef.save_weights_to_file("weights.csv") # saves to file ef.portfolio_performance(verbose=True)
def test_clean_weights_short(): ef = setup_efficient_frontier() ef = EfficientFrontier(*setup_efficient_frontier(data_only=True), weight_bounds=(-1, 1)) ef.min_volatility() # In practice we would never use such a high cutoff number_tiny_weights = sum(np.abs(ef.weights) < 0.05) cleaned = ef.clean_weights(cutoff=0.05) cleaned_weights = cleaned.values() clean_number_tiny_weights = sum(abs(i) < 0.05 for i in cleaned_weights) assert clean_number_tiny_weights == number_tiny_weights
def calculate_allocation(stock_price, cash, 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() latest_prices = get_latest_prices(stock_price) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=cash) allocation, leftover = da.lp_portfolio() print("Discrete allocation:", allocation) print("Funds remaining: ${:.2f}".format(leftover))
def optimize(data): mu = expected_returns.mean_historical_return(data) S = risk_models.sample_cov(data) # Optimise for maximal Sharpe ratio ef = EfficientFrontier(mu, S) ef.max_sharpe() cleaned_weights = ef.clean_weights() weights = np.array(list(cleaned_weights.values())) folio = (data.iloc[:, :] * weights).sum(axis=1) perf = ef.portfolio_performance(verbose=True) return weights, folio, perf
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 optimMarkowitz(datatrain, datatest, pmin, pmax, optimmodel, returnmodel, riskmodel, Gam, rf): try: if returnmodel == 'historical': mu = expected_returns.mean_historical_return(datatrain) elif returnmodel == 'emahistorical': mu = expected_returns.ema_historical_return(datatrain) if riskmodel == 'historicalcov': S = risk_models.sample_cov(datatrain) elif riskmodel == 'exphistoricalcov': S = risk_models.exp_cov(datatrain) ef = EfficientFrontier(mu, S, weight_bounds=(pmin, pmax)) #gamma>0 permet de forcer l'optimiseur à utiliser plus de titres ef.add_objective(objective_functions.L2_reg, gamma=Gam) if optimmodel == 'min_volatility': ef.min_volatility() elif optimmodel == 'max_sharpe': ef.max_sharpe(risk_free_rate=rf) cleaned_weights = ef.clean_weights() #round and clean ... ef.save_weights_to_file( '/Users/Maxime/AMUNDI/PortMgmnt/ModulePyPortfolioOpt/OptimiseurProjet/weights.csv' ) # save to file perf = ef.portfolio_performance(verbose=True, risk_free_rate=rf) weightsfinal = pd.read_csv( '/Users/Maxime/AMUNDI/PortMgmnt/ModulePyPortfolioOpt/OptimiseurProjet/weights.csv', header=None) #For the following chart poids = weightsfinal.to_numpy() poids = poids[:, 1] RankedDataFrame = pd.DataFrame(index=datatest.index) for i, rows in weightsfinal.iterrows(): RankedDataFrame[rows[0]] = datatest[rows[0]] weightsfinal.rename(columns={ 0: ' Asset Class', 1: 'Poids' }, inplace=True) weightsfinal['Poids'] = round(weightsfinal['Poids'] * 100, 4) except ValueError: print('Le modèle spécifié est incorrect') return poids, RankedDataFrame, cleaned_weights, S, mu, perf
def calculate_allocation(self, cash): # if you have cash to allocate to a set of stocks, this function will return how to allocate that # see rebalance_weight to identify most suitable portfolio self.cash = cash ef = EfficientFrontier(self.mu, self.S) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() latest_prices = get_latest_prices(self.stock_prices) da = DiscreteAllocation(cleaned_weights, latest_prices, total_portfolio_value=cash) allocation, leftover = da.lp_portfolio() print("Discrete allocation:", allocation) print("Funds remaining: ${:.2f}".format(leftover))
def build_portfolio_weights(stock_data, weights_filename): # Calculate expected returns and sample covariance if isinstance(stock_data, pd.Series): stock_data = stock_data.to_frame() mu = expected_returns.mean_historical_return(stock_data) S = risk_models.sample_cov(stock_data) # Optimize for maximal Sharpe ratio ef = EfficientFrontier(mu, S) raw_weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() ef.save_weights_to_file(weights_filename) # saves to file ef.portfolio_performance(verbose=True) return cleaned_weights
def optimise_portfolio(stock_price, Portfolio): returns = stock_price.pct_change().dropna() # Calculate expected returns and sample covariance mu = expected_returns.mean_historical_return(stock_price) S = risk_models.sample_cov(stock_price) # 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) Portfolio.ef = ef Portfolio.mu = mu Portfolio.S = S Portfolio.weights = cleaned_weights
def get_result(l): data = yf.download(tickers=l, period="max", interval="1d", auto_adjust=True) data = data['Close'] mu = expected_returns.mean_historical_return(data) S = CovarianceShrinkage(data).ledoit_wolf() ef = EfficientFrontier(mu, S) raw_weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() data = [] for x in cleaned_weights.keys(): if cleaned_weights[x] != 0: data.append({'name': x, 'y': cleaned_weights[x]}) answer = {'data': data, 'performance': ef.portfolio_performance()} return answer
def Optimize(array): df = pd.read_csv('latest_stock_prices.csv', parse_dates=True, index_col="date") data = df[df.columns.intersection(array)] data.dtypes mu = expected_returns.mean_historical_return(data) S = risk_models.sample_cov(data) # 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)
def run_portfolio_optimization() -> None: df_corr = _load_df_correlation_economist() df_corr = df_corr.set_index(df_corr['state']) df_mu_sigma = _compute_df_mu_sigma_return() df_mu_sigma = df_mu_sigma.sort_values('STATE_INIT') df_corr = df_corr.loc[df_mu_sigma['STATE_INIT']][ df_mu_sigma['STATE_INIT'].values] # Covariance = diag(S) * Corr * diag(S) # Note: This isn't going to be exactly correct since the Economist correlations are not the # market returns, but let's assume they're roughly equal df_cov = pandas.DataFrame(np.matmul( np.matmul(np.diag(df_mu_sigma['STD_D_YES'].values), df_corr.values), np.diag(df_mu_sigma['STD_D_YES'].values)), index=df_mu_sigma['STATE_INIT'].values, columns=df_mu_sigma['STATE_INIT'].values) sns.heatmap(df_corr, fmt=',.1f') plt.title('Correlation matrix of state performance') plt.show() df_mu_sigma.to_csv(os.path.join(_data_dir(), 'mu_sigma.csv')) df_cov.to_csv(os.path.join(_data_dir(), 'vcov_matrix.csv')) ef = EfficientFrontier( expected_returns=df_mu_sigma.set_index('STATE_INIT')['MU_D_YES'], cov_matrix=df_cov) raw_weights = ef.max_sharpe(risk_free_rate=0) df_weights = pandas.DataFrame([(state, w) for state, w in ef.clean_weights().items()], columns=['STATE_INIT', 'WEIGHT']) df_weights[df_weights['WEIGHT'].gt(0)].set_index( 'STATE_INIT')['WEIGHT'].plot.barh() plt.title('Optimal portfolio weights (D win)') plt.ylabel('State market') plt.xlabel('Weight') sns.despine() plt.show() print(df_weights.sort_values('WEIGHT', ascending=False)) ef.portfolio_performance(verbose=True) df_weights.to_csv('portfolio_weights.csv', index=False)
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 optimise_portfolio(self, use_filter=True): self.stock_prices.fillna(value=self.stock_prices.mean(), inplace=True) self.stock_prices = self.stock_prices.dropna(axis=1, how='any') risk_free_rate = 0.02 risk_aversion = 0.5 self.filter_stock_prices() self.holding = self.holding[self.holding.Symbol.isin( self.fil_stock_prices.keys())] if use_filter: self.mu = expected_returns.mean_historical_return( self.fil_stock_prices) self.S = risk_models.sample_cov(self.fil_stock_prices) else: self.mu = expected_returns.mean_historical_return( self.stock_prices) self.S = risk_models.sample_cov(self.stock_prices) self.index_return = self.stock_prices.sum( axis=1)[-1] / self.stock_prices.sum(axis=1)[0] self.index_price = self.stock_prices.sum(axis=1) returns = self.stock_prices.pct_change().dropna() # Calculate expected returns and sample covariance #calculate old portfolio position # Optimise for maximal Sharpe ratio ef = EfficientFrontier(self.mu, self.S) # raw_weights = ef.max_quadratic_utility(risk_aversion) raw_weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() ef.save_weights_to_file(os.path.join(self.output_path, "weights.csv")) # saves to file print(cleaned_weights) ef.portfolio_performance(verbose=True) self.ef = ef self.weights = cleaned_weights self.rebalance_weight()
def cli(risk_free_rate, start, span, verbose, tickers): # Read in price data thelen = len(tickers) price_data = [] successful_tickers = [] for ticker in range(thelen): click.echo(tickers[ticker]) try: prices = web.DataReader(tickers[ticker], start=start, data_source='yahoo') if verbose >= 1: click.echo(tickers[ticker] + ':') click.echo(prices) price_data.append(prices.assign(ticker=ticker)[['Adj Close']]) successful_tickers.append(tickers[ticker]) except: pass df = pd.concat(price_data, axis=1) df.columns = successful_tickers df.head() #Checking if any NaN values in the data nullin_df = pd.DataFrame(df, columns=tickers) print(nullin_df.isnull().sum()) # Calculate expected returns and sample covariance mu = expected_returns.ema_historical_return(df, span=span) S = risk_models.sample_cov(df) # Optimise for maximal Sharpe ratio ef = EfficientFrontier( mu, S) #weight bounds in negative allows shorting of stocks raw_weights = ef.max_sharpe(risk_free_rate=risk_free_rate) cleaned_weights = ef.clean_weights() click.echo(cleaned_weights) ef.portfolio_performance(verbose=True)
def efficient_frontier(my_portfolio, 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") df = 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 df = df.fillna(1) mu = expected_returns.mean_historical_return(df) S = risk_models.sample_cov(df) # optimize for max sharpe ratio ef = EfficientFrontier(mu, S) 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) weights = ef.max_sharpe() cleaned_weights = ef.clean_weights() wts = cleaned_weights.items() result = [] for val in wts: a, b = map(list, zip(*[val])) result.append(b) if perf is True: pred = ef.portfolio_performance(verbose=True) return flatten(result)
def get_portfolio_distribution(watchlist_id): assets = get_assets(watchlist_id) if (len(assets) == 0): aggregate_data = {} aggregate_data['composition'] = "No stocks in the watchlist" aggregate_data['Expected annual return:'] = "0" aggregate_data['Annual volatility:'] = "0" aggregate_data['Sharpe Ratio:'] = "0" return aggregate_data tickers = [] for stock_x in assets: # Create empty dict for stock data tickers.append(f"{stock_x[1]}.AX") yf.pdr_override() x = datetime.datetime.now() Previous_Date = datetime.datetime.today() - datetime.timedelta(days=365) data = pdr.get_data_yahoo(tickers, start=Previous_Date.strftime('%Y-%m-%d'), end=x.strftime('%Y-%m-%d')) data = data['Close'] mu = expected_returns.mean_historical_return(data) S = risk_models.sample_cov(data) ef = EfficientFrontier(mu, S) raw_weights = ef.min_volatility() cleaned_weights = ef.clean_weights() perf = ef.portfolio_performance() aggregate_data = {} aggregate_data['dictionary_composition'] = cleaned_weights.items() aggregate_data['Expected_annual_return:'] = f"Expected annual return: {perf[0]*100:.2f}%" aggregate_data['Annual_volatility:'] = f"Annual volatility: {perf[1]*100:.2f}%" aggregate_data['Sharpe_Ratio:'] = f"Sharpe Ratio: {perf[2]:.2f}"" return aggregate_data
daily_return = np.log(prices / prices.shift(1)) #relabel columns daily_return['Date'] = dates cols = ['Date'] + prices.columns.to_list() daily_return = daily_return.reindex(columns=cols) #write to csv daily_return.to_csv(r"C:\Users\Jonathan\Investing\ETF_daily_returns.csv", na_rep=np.nan) # Read in price data df = pd.read_csv(r"C:\Users\Jonathan\Investing\ETF_closing_prices.csv", parse_dates=True, index_col="Unnamed: 0") # 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(r"C:\Users\Jonathan\Investing\weights.csv") print(cleaned_weights) ef.portfolio_performance(verbose=True) weights = pd.read_csv(r"C:\Users\Jonathan\Investing\weights.csv", header=None) weights.columns = ['Ticker', 'Prop'] non_zero_weights = weights[weights.Prop != 0] print(non_zero_weights) non_zero_weights.to_csv(r'C:\Users\Jonathan\Desktop\stash_weights.csv')
class OptPortfolio(BaseEstimator): ''' Portfolio optimization used both for train and validation ''' def __init__(self, target_function: str = "efficient_risk", target_function_params: dict = {}, budget: int = 10000): self.target_function = target_function self.target_function_params = target_function_params self.budget = budget self.frequency = None # self.mu = expected_returns.mean_historical_return(prices) # self.S = risk_models.CovarianceShrinkage(prices).ledoit_wolf() # self.ef = EfficientFrontier(self.mu, self.S) # self.ef.add_objective(objective_functions.L2_reg) # getattr(self.ef,target_function)(**target_function_params) # self.weights = self.ef.clean_weights() # # self.da = DiscreteAllocation(self.weights, prices.iloc[-1], total_portfolio_value=money) # alloc, leftover = self.da.lp_portfolio() # print(f"Leftover: ${leftover:.2f}") # print(f"Alloc: ${alloc:.2f}") # self.discrete_portfolio = ( # prices[[k for k, v in alloc.items()]] * np.asarray([[v for k, v in alloc.items()]])).dropna().sum( # axis=1) def fit(self, prices: pd.DataFrame): # TODO: make prices instance of portfolio ''' Given prices finds wieghts (coefficients), most optimal portfolio given target function. :param prices: :return: ''' self.frequency = autodetect_frequency(prices) self.mu = expected_returns.mean_historical_return( prices, frequency=self.frequency) self.S = risk_models.CovarianceShrinkage( prices, frequency=self.frequency).ledoit_wolf() # self.S=risk_models.exp_cov(prices) self.ef = EfficientFrontier(self.mu, self.S) self.ef.add_objective(objective_functions.L2_reg) getattr(self.ef, self.target_function)(**self.target_function_params) self.coef_ = self.ef.clean_weights() return self def predict(self, prices: pd.DataFrame): ''' Predicts portfolio given found optimal portoflio weights. :param prices: :return: optimal portofolio (in currency of input) ''' self.allocate(prices) # da = DiscreteAllocation(self.coef_, prices.iloc[-1], total_portfolio_value=self.budget) # alloc, leftover = da.lp_portfolio() # print(f"Leftover: ${leftover:.2f}") # print(f"Alloc: ${alloc}") discrete_portfolio = ( prices[[k for k, v in self.alloc.items()]] * np.asarray([[v for k, v in self.alloc.items()]])).dropna() return discrete_portfolio def allocate(self, prices: pd.DataFrame) -> Tuple[dict, float]: ''' Given weights for portfolio and last prices, finds best discrete allocation of assets. :param prices: :return: allocation and leftover of portfolio ''' da = DiscreteAllocation(self.coef_, prices.iloc[-1], total_portfolio_value=self.budget) self.alloc, self.leftover = da.lp_portfolio() print("Period end:", prices.index[0]) print(f"Leftover: ${self.leftover:.2f}") print(f"Alloc: ${self.alloc}") return self.alloc, self.leftover @property def weights(self): return self.coef_ @property def allocations(self): return self.alloc @property def leftover(self): return self.leftover
), layout = layout) fig.show() fig.write_image(fr"{output_dir}\CorrelationHeatmap.png") #py.iplot(fig, filename='Beta/Untreated_Heatmap') #fig.write_image(fr"{output_dir3}\{name}_range_graph.png") # min volatility portfolio ef_minvol = EfficientFrontier(exp_ret, S) # ef.add_objective(objective_functions.transaction_cost, # w_prev=initial_weights, k=0.01) ef_minvol.min_volatility() weights_minvol = ef_minvol.clean_weights() weights_minvol ef_minvol.portfolio_performance(verbose=True) # max sharpe portfolio 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
prior = black_litterman.market_implied_prior_returns(mcaps, delta, S) # 1. SBUX will drop by 20% # 2. GOOG outperforms FB by 10% # 3. BAC and JPM will outperform T and GE by 15% views = np.array([-0.20, 0.10, 0.15]).reshape(-1, 1) picking = np.array([ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, -0.5, 0, 0, 0.5, 0, -0.5, 0, 0, 0, 0, 0, 0, 0, 0.5, 0], ]) bl = BlackLittermanModel(S, Q=views, P=picking, pi=prior, tau=0.01) rets = bl.bl_returns() ef = EfficientFrontier(rets, S) ef.max_sharpe() print(ef.clean_weights()) ef.portfolio_performance(verbose=True) """ {'GOOG': 0.2015, 'AAPL': 0.2368, 'FB': 0.0, 'BABA': 0.06098, 'AMZN': 0.17148, 'GE': 0.0, 'AMD': 0.0, 'WMT': 0.0, 'BAC': 0.18545, 'GM': 0.0, 'T': 0.0, 'UAA': 0.0, 'SHLD': 0.0,