I prefer to MVO it!

[This article was first published on R on OSM, and kindly contributed to R-bloggers]. (You may report problem concerning the content material on this web page right here)


Need to share your content material on R-bloggers? click on right here when you’ve got a weblog, or right here if you happen to do not.

In our final publish, we ran via a bunch of weighting eventualities utilizing our returns simulation. This resulted in three million portfolios comprised partly, or whole, of 4 property: shares, bonds, gold, and actual property. These simulations relaxed the allocation constraints to permit us to exclude property, yielding a wider vary of return and threat outcomes, whereas reducing the probability of attaining our threat and return targets. We bucketed the portfolios to simplify the evaluation across the risk-return commerce off. We then calculated the median returns and threat for every bucket and located that some buckets achieved Sharpe ratios near or higher than that implied by our unique risk-return constraint. Slicing the info additional, we calculated the common weights for the higher Sharpe ratio portfolios. The consequence: comparatively equal-weighting tended to supply a greater risk-reward end result than important overweighting.

On the finish of the publish we famous that we might have a bypassed a lot of this knowledge wrangling and easily calculated the optimum portfolio weights for varied threat profiles utilizing mean-variance optimization. That’s what we plan to do right this moment.

The insanity behind all this knowledge wrangling was to determine the very best return afforded by a given stage of threat. Imply-variance optimization (MVO) solves that downside extra elegantly than our “hacky” strategies. It makes use of quadratic programming to attenuate the portfolio variance by altering the weights of the assorted property within the portfolio. It’s topic to the constraints (within the easiest type) that the return of any explicit portfolio is not less than equal to the anticipated return of the portfolio and the weights of the property sum to at least one.

Extra formally it may be expressed as follows:

Decrease: (frac{1}{2}w’sum w)
Topic to: (r’w = mu and e’w = 1)

Right here (w) = asset weights, (sum) = the covariance matrix of the property with themselves and each different asset, (r) = returns of the property, (mu) = anticipated return of the portfolio, (e’) = a vector of ones. It’s understood that one is using matrix notation, so the (w’) is the transpose of (w).

In the event you perceive that, it’s most likely the roughest rendition of MVO you’ve seen and if you happen to don’t, don’t fear about it. The purpose is thru some nifty math, you may clear up for the exact weights so that each portfolio that falls alongside a line has the bottom volatility for a given stage of return or the best return for a given stage of volatility. This line known as the environment friendly frontier since effectivity in econospeak means each asset is optimally allotted and frontier, nicely you get that one we hope.

What does this appear to be in apply? Let’s convey again our unique portfolio, run the simulations, after which calculate the environment friendly frontier. We graph our unique simulation with the unique weighting constraint (all property are within the portfolio) under.

Recall that after we ran this simulation we averaged the weightings for these portfolios that achieved our constraints of not lower than a 7% return and less 10% threat on an annual foundation. We then utilized that weighting to our first 5 12 months take a look at interval. We present the weighting under.

Earlier than we have a look at the ahead returns and the environment friendly frontier, let’s see the place our portfolio lies within the unique simulation to orient ourselves. It’s the pink dot.

As is obvious, the portfolio leads to the upper finish of the continuum, however there are different portfolios that dominate it. Now the second we’ve been ready for—portfolio optimization! Taking a spread of returns between the minimal and most of the simulated portfolios, we’ll calculate the optimum weights to supply the best return for the bottom quantity of threat.

Wow! That optimization stuff certain does work. The blue line representing the environment friendly frontier clearly exhibits that there are different portfolios that might generate a lot larger returns for the implied stage of threat we’re taking over. Alternatively, if we transfer horizontally to the left we see that we might obtain the identical stage of return at a a lot decrease stage of threat, proven by the place the blue line crosses above 7% return.

Recall for illustrative functions we used a easy model for the unique weight simulation that required an funding in all property. Once we calm down that constraint, we get a a lot wider vary of outcomes, as we identified within the final publish. What if we ran the weighting simulation with the relaxed constraint? What would our simulation and allocation appear to be in that case? We present these outcomes under.

We see a wider vary of outcomes, which yields the next weighting to bonds and a decrease one to gold than the earlier portfolio. Now we’ll overlay the location of our passable portfolio on the broader weight simulation together with the environment friendly frontier within the graph under.

Who wants mean-variance optimization whenever you’ve acquired knowledge science simulation?! As one can see, whenever you permit portfolio weights to method zero in lots of, however not all, of the property, you may approximate the environment friendly frontier with out having to depend on quadratic programming. This could give new that means to “p-hacking.” Nonetheless, quadratic programming is more likely to be lots quicker that operating hundreds of simulations with a big portfolio of property. Recall for the 4 asset portfolio after we relaxed the inclusion constraint, that tripled the variety of simulations. Therefore, for any simulation by which some portfolios received’t be invested in all of the property, the variety of calculations will increase by an element of the entire variety of property minus one.

Regardless of the case, we see that the passable portfolio might not be that passable given how a lot it’s dominated by the environment friendly frontier. Recall, nonetheless, we weren’t attempting to realize an optimum portfolio per se. We “simply” needed a portfolio that will meet our risk-return constraints.

Let’s see what occurs after we use our passable portfolio’s weights on the primary five-year take a look at interval. Within the graph under, we calculate our portfolios threat and return after which place it inside our weight simulation scatter plot. We additionally calculate the danger and returns of assorted portfolios utilizing the weights we derived from our environment friendly frontier above and add that our graph because the blue line.

Uh oh, not so environment friendly. The weights from the earlier environment friendly frontier didn’t obtain optimum portfolios sooner or later and produced an uncommon form too. This illustrates one of many essential issues with mean-variance optimization: “optimum weights are delicate to return estimates”. In different phrases, in case your estimate of returns aren’t that nice, your optimum portfolio weights received’t be so optimum. Furthermore, even when your estimates replicate all presently obtainable info, that doesn’t imply they’ll be that correct sooner or later.

A good way to see that is to calculate the environment friendly frontier utilizing as a lot of the info as we’ve, ignoring incomplete instances (which produces bias) and plotting that in opposition to the unique and first five-year simulations

You win some; you lose some. As is clear, completely different return estimates yield completely different frontiers each retrospectively and prospectively. Ought to we be skeptical of imply mean-variance optimization as Warren Buffett is of “geeks bearing presents”? Probably not. It’s a sublime answer to the thorny downside of portfolio building. However it’s not very dynamic and it doesn’t precisely permit for a lot uncertainty round estimates.

There have been a quantity makes an attempt to deal with such shortcomings together with multi-period fashions, inter-temporal fashions, and even a statistics-free method, amongst others. Even summarizing these completely different approaches would take us far afield of this publish. Suffice it to say, there isn’t a transparent winner; as an alternative every refinement addresses a selected problem or suits a selected threat choice.

We’ve now partially revealed why we’ve been speaking a couple of “passable” portfolio all alongside. It’s the trade-off between satsificing and optimum. Whereas we can’t presumably focus on all of the nuances of satisficing now, our temporary clarification is that this. Satisficing is discovering the very best obtainable answer when the optimum one is unsure or unattainable. It was an idea developed by Herbert Simon who argued that call makers might select an optimum answer to a simplified actuality or a passable answer to a messy one.

If the “optimum” answer to portfolio allocation is a shifting goal with a number of approaches to calculating it, lots of which contain quite a lot of complexity, then electing a “good-enough” answer may be extra passable. The associated fee to change into conversant within the technical particulars essential to know a number of the options, not to mention compile all the info essential, may very well be prohibitive. In fact, if you happen to’re a fund supervisor being paid to outperform (i.e., beat everybody else attempting to beat you), then it behooves you to hunt out these arcane options in case your commpetitors are apt to make use of them too.

This dialogue explains, partly, why the “easy” 1/n or 60/40 inventory/bond portfolios are so well-liked. The train of mean-variance optimization and all its offshoots might merely be an excessive amount of effort if the solutions it offers aren’t dramatically higher than a simplified method. However it could be mistaken to put the blame for poor outcomes or uncertainty on MVO: monetary markets have far more noise than sign.

In pursuit of the sign, our subsequent posts will have a look at the “easy” portfolios and see what they produce over a number of simulations relative to the passable and optimum portfolios we’ve already mentioned. In the event you assume this weblog is producing extra noise than sign or vice versa, we wish to know! Our e-mail deal with is after the R and Python code under.

R code:

# Written in R 3.6.2
# Code for any supply('operate.R') is discovered on the finish. ## Load packages
suppressPackageStartupMessages({ library(tidyquant) library(tidyverse) library(quadprog)
}) ## Load knowledge
df <- readRDS("port_const.rds")
dat <- readRDS("port_const_long.rds")
sym_names <- c("inventory", "bond", "gold", "realt", "rfr") ## Name simuation capabilities
supply("Portfolio_simulation_functions.R") ## Run simulation
set.seed(123)
port_sim_1 <- port_sim(df[2:61,2:5],1000,4) ## Graph
port_sim_1$graph + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA)) ## Run choice operate and graph results_1 <- port_select_func(port_sim_1, 0.07, 0.1, sym_names[1:4])
results_1$graph # Create passable portfolio
satis_ret <- sum(results_1$port_wts*colMeans(df[2:61, 2:5]))
satis_risk <- sqrt(as.numeric(results_1$port_wts) %*% cov(df[2:61, 2:5]) %*% as.numeric(results_1$port_wts))
port_satis <- knowledge.body(returns = satis_ret, threat = satis_risk) # Graph with simulated
port_sim_1$graph + geom_point(knowledge = port_satis, aes(threat*sqrt(12)*100, returns*1200), measurement = 4, coloration="pink") + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA)) ## Discover environment friendly frontier
supply("Efficient_frontier.R")
eff_port <- eff_frontier_long(df[2:61,2:5], risk_increment = 0.01) df_eff <- knowledge.body(returns = eff_port$exp_ret, threat = eff_port$stdev) port_sim_1$graph + geom_line(knowledge = df_eff, aes(threat*sqrt(12)*100, returns*1200), coloration = 'blue', measurement = 1.5, linetype = "dashed") + geom_point(knowledge = port_satis, aes(threat*sqrt(12)*100, returns*1200), measurement = 4, coloration="pink") + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA)) # Simulation with leaving out property
port_sim_1lv <- port_sim_lv(df[2:61,2:5],1000,4) lv_graf <- port_sim_1lv$graph + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA), plot.title = element_text(measurement=10)) ## Run choice operate results_1lv <- port_select_func(port_sim_1lv, 0.07, 0.1, sym_names[1:4])
lv_res_graf <- results_1lv$graph + theme(plot.title = element_text(measurement=10)) gridExtra::grid.organize(lv_graf, lv_res_graf, ncol=2) ## Create passable knowledge body and graph omit portfolios with environment friendly frontier
satis_ret_lv <- sum(results_1lv$port_wts*colMeans(df[2:61, 2:5]))
satis_risk_lv <- sqrt(as.numeric(results_1lv$port_wts) %*% cov(df[2:61, 2:5]) %*% as.numeric(results_1lv$port_wts)) port_satis_lv <- knowledge.body(returns = satis_ret_lv, threat = satis_risk_lv) port_sim_1lv$graph + geom_line(knowledge = df_eff, aes(threat*sqrt(12)*100, returns*1200), coloration = 'blue', measurement = 1.5, linetype = "dashed") + geom_point(knowledge = port_satis_lv, aes(threat*sqrt(12)*100, returns*1200), measurement = 4, coloration="pink") + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA)) ## Run operate and create precise portfolio and knowledge body for graph
port_1_act <- rebal_func(df[62:121,2:5],results_1lv$port_wts) port_act <- knowledge.body(returns = imply(port_1_act$ret_vec), threat = sd(port_1_act$ret_vec), sharpe = imply(port_1_act$ret_vec)/sd(port_1_act$ret_vec)*sqrt(12)) ## Simulate portfolios on first five-year interval
set.seed(123)
port_sim_2 <- port_sim_lv(df[62:121,2:5], 1000, 4) eff_ret1 <- apply(eff_port[,1:4], 1, operate(x) x %*% colMeans(df[62:121, 2:5]))
eff_risk1 <- sqrt(apply(eff_port[,1:4], 1, operate(x) as.numeric(x) %*% cov(df[62:121,2:5]) %*% as.numeric(x))) eff_port1 <- knowledge.body(returns = eff_ret1, threat = eff_risk1) ## Graph simulation with chosen portfolio
port_sim_2$graph + geom_point(knowledge = port_act, aes(threat*sqrt(12)*100, returns*1200), measurement = 4, coloration="pink") + geom_line(knowledge = eff_port1, aes(threat*sqrt(12)*100, returns*1200), coloration = 'pink', measurement = 2) + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA)) ## Utilizing long run knowledge
eff_port_old <- eff_frontier_long(dat[1:253,2:5], risk_increment = 0.01) df_eff_old <- knowledge.body(returns = eff_port_old$exp_ret, threat = eff_port_old$stdev) p1 <- port_sim_1lv$graph + geom_line(knowledge = df_eff_old, aes(threat*sqrt(12)*100, returns*1200), coloration = 'blue', measurement = 1.5) + geom_point(knowledge = port_satis, aes(threat*sqrt(12)*100, returns*1200), measurement = 4, coloration="pink") + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA), plot.title = element_text(measurement=10)) + labs(title = 'Simulated portfolios with long-term optimzation') # For ahead graph
eff_ret1_old <- apply(eff_port_old[,1:4], 1, operate(x) x %*% colMeans(dat[1:253, 2:5], na.rm = TRUE))
eff_risk1_old <- sqrt(apply(eff_port_old[,1:4], 1, operate(x) as.numeric(x) %*% cov(dat[1:253,2:5], use = 'pairwise.full.obs') %*% as.numeric(x))) eff_port1_old <- knowledge.body(returns = eff_ret1_old, threat = eff_risk1_old) ## Graph simulation with chosen portfolio
p2 <- port_sim_2$graph + geom_point(knowledge = port_act, aes(threat*sqrt(12)*100, returns*1200), measurement = 4, coloration="pink") + geom_line(knowledge = eff_port1_old, aes(threat*sqrt(12)*100, returns*1200), coloration = 'blue', measurement = 2) + theme(legend.place = c(0.05,0.8), legend.key.measurement = unit(.5, "cm"), legend.background = element_rect(fill = NA), plot.title = element_text(measurement=10)) + labs(title = 'Ahead portfolios with long-term optimization') gridExtra::grid.organize(p1, p2, ncol=2) #### Portfolio_simulation_functions.R
# Portfolio simulations ## Portfolio simuation operate
port_sim <- operate(df, sims, cols){ if(ncol(df) != cols){ print("Columns do not match") break } # Create weight matrix wts <- matrix(nrow = sims, ncol = cols) for(i in 1:sims){ a <- runif(cols,0,1) b <- a/sum(a) wts[i,] <- b } # Discover returns mean_ret <- colMeans(df) # Calculate covariance matrix cov_mat <- cov(df) # Calculate random portfolios port <- matrix(nrow = sims, ncol = 2) for(i in 1:sims){ port[i,1] <- as.numeric(sum(wts[i,] * mean_ret)) port[i,2] <- as.numeric(sqrt(t(wts[i,]) %*% cov_mat %*% wts[i,])) } colnames(port) <- c("returns", "threat") port <- as.knowledge.body(port) port$Sharpe <- port$returns/port$threat*sqrt(12) max_sharpe <- port[which.max(port$Sharpe),] graph <- port %>% ggplot(aes(threat*sqrt(12)*100, returns*1200, coloration = Sharpe)) + geom_point(measurement = 1.2, alpha = 0.4) + scale_color_gradient(low = "darkgrey", excessive = "darkblue") + labs(x = "Threat (%)", y = "Return (%)", title = "Simulated portfolios") out <- record(port = port, graph = graph, max_sharpe = max_sharpe, wts = wts) } ## Portfolio Simulation go away port_sim_lv <- operate(df, sims, cols){ if(ncol(df) != cols){ print("Columns do not match") break } # Create weight matrix wts <- matrix(nrow = (cols-1)*sims, ncol = cols) depend <- 1 for(i in 1:(cols-1)){ for(j in 1:sims){ a <- runif((cols-i+1),0,1) b <- a/sum(a) c <- pattern(c(b,rep(0,i-1))) wts[count,] <- c depend <- depend+1 } } # Discover returns mean_ret <- colMeans(df) # Calculate covariance matrix cov_mat <- cov(df) # Calculate random portfolios port <- matrix(nrow = (cols-1)*sims, ncol = 2) for(i in 1:nrow(port)){ port[i,1] <- as.numeric(sum(wts[i,] * mean_ret)) port[i,2] <- as.numeric(sqrt(t(wts[i,]) %*% cov_mat %*% wts[i,])) } colnames(port) <- c("returns", "threat") port <- as.knowledge.body(port) port$Sharpe <- port$returns/port$threat*sqrt(12) max_sharpe <- port[which.max(port$Sharpe),] graph <- port %>% ggplot(aes(threat*sqrt(12)*100, returns*1200, coloration = Sharpe)) + geom_point(measurement = 1.2, alpha = 0.4) + scale_color_gradient(low = "darkgrey", excessive = "darkblue") + labs(x = "Threat (%)", y = "Return (%)", title = "Simulated portfolios") out <- record(port = port, graph = graph, max_sharpe = max_sharpe, wts = wts) } ## Load portfolio choice operate
port_select_func <- operate(port, return_min, risk_max, port_names){ port_select <- cbind(port$port, port$wts) port_wts <- port_select %>% mutate(returns = returns*12, threat = threat*sqrt(12)) %>% filter(returns >= return_min, threat <= risk_max) %>% summarise_at(vars(4:7), imply) %>% `colnames<-`(port_names) p <- port_wts %>% rename("Shares" = inventory, "Bonds" = bond, "Gold" = gold, "Actual property" = realt) %>% collect(key,worth) %>% ggplot(aes(reorder(key,worth), worth*100 )) + geom_bar(stat='id', place = "dodge", fill = "blue") + geom_text(aes(label=spherical(worth,2)*100), vjust = -0.5) + scale_y_continuous(limits = c(0,max(port_wts*100+2))) + labs(x="", y = "Weights (%)", title = "Common weights for risk-return constraints") out <- record(port_wts = port_wts, graph = p) out } ## Perform for portfolio returns with out rebalancing
rebal_func <- operate(act_ret, weights){ ret_vec <- c() wt_mat <- matrix(nrow = nrow(act_ret), ncol = ncol(act_ret)) for(i in 1:nrow(wt_mat)){ wt_ret <- act_ret[i,]*weights # wt'd return ret <- sum(wt_ret) # whole return ret_vec[i] <- ret weights <- (weights + wt_ret)/(sum(weights)+ret) # new weight primarily based on change in asset worth wt_mat[i,] <- as.numeric(weights) } out <- record(ret_vec = ret_vec, wt_mat = wt_mat) out
} #### Efficient_frontier.R
# Tailored from https://www.nexteinstein.org/wp-content/uploads/websites/6/2017/01/ORIG_Portfolio-Optimization-Utilizing-R_Pseudo-Code.pdf eff_frontier_long <- operate(returns, risk_premium_up = 0.5, risk_increment = 0.005){ covariance <- cov(returns, use = "pairwise.full.obs") num <- ncol(covariance) Amat <- cbind(1, diag(num)) bvec <- c(1, rep(0, num)) meq <- 1 risk_steps <- risk_premium_up/risk_increment+1 depend <- 1 eff <- matrix(nrow = risk_steps, ncol = num + 3) colnames(eff) <- c(colnames(returns), "stdev", "exp_ret", "sharpe") loop_step <- seq(0, risk_premium_up, risk_increment) for(i in loop_step){ dvec <- colMeans(returns, na.rm = TRUE)*i sol <- quadprog::clear up.QP(covariance, dvec = dvec, Amat = Amat, bvec = bvec, meq = meq) eff[count, "stdev"] <- sqrt(sum(sol$answer * colSums(covariance * sol$answer))) eff[count, "exp_ret"] <- as.numeric(sol$answer %*% colMeans(returns, na.rm = TRUE)) eff[count, "sharpe"] <- eff[count,"exp_ret"]/eff[count, "stdev"] eff[count, 1:num] <- sol$answer depend <- depend + 1 } return(as.knowledge.body(eff)) }

Python code:

# Load libraries
import pandas as pd
import pandas_datareader.knowledge as net
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline plt.type.use('ggplot') # SKIP IF ALREADY HAVE DATA
# Load knowledge
start_date = '1970-01-01'
end_date = '2019-12-31'
symbols = ["WILL5000INDFC", "BAMLCC0A0CMTRIV", "GOLDPMGBD228NLBM", "CSUSHPINSA", "DGS5"]
sym_names = ["stock", "bond", "gold", "realt", 'rfr']
filename = 'data_port_const.pkl' strive: df = pd.read_pickle(filename) print('Information loaded')
besides FileNotFoundError: print("File not discovered") print("Loading knowledge", 30*"-") knowledge = net.DataReader(symbols, 'fred', start_date, end_date) knowledge.columns = sym_names data_mon = knowledge.resample('M').final()
df = data_mon.pct_change()['1987':'2019']
# df.to_pickle(filename) # If you have not saved the file dat = data_mon.pct_change()['1971':'2019']
# pd.to_pickle(df,filename) # if you have not saved the file # Portfolio simulation capabilities ## Simulation operate
class Port_sim: def calc_sim(df, sims, cols): wts = np.zeros((sims, cols)) for i in vary(sims): a = np.random.uniform(0,1,cols) b = a/np.sum(a) wts[i,] = b mean_ret = df.imply() port_cov = df.cov() port = np.zeros((sims, 2)) for i in vary(sims): port[i,0] = np.sum(wts[i,]*mean_ret) port[i,1] = np.sqrt(np.dot(np.dot(wts[i,].T,port_cov), wts[i,])) sharpe = port[:,0]/port[:,1]*np.sqrt(12) best_port = port[np.where(sharpe == max(sharpe))] max_sharpe = max(sharpe) return port, wts, best_port, sharpe, max_sharpe def calc_sim_lv(df, sims, cols): wts = np.zeros(((cols-1)*sims, cols)) depend=Zero for i in vary(1,cols): for j in vary(sims): a = np.random.uniform(0,1,(cols-i+1)) b = a/np.sum(a) c = np.random.selection(np.concatenate((b, np.zeros(i))),cols, exchange=False) wts[count,] = c depend+=1 mean_ret = df.imply() port_cov = df.cov() port = np.zeros(((cols-1)*sims, 2)) for i in vary(sims): port[i,0] = np.sum(wts[i,]*mean_ret) port[i,1] = np.sqrt(np.dot(np.dot(wts[i,].T,port_cov), wts[i,])) sharpe = port[:,0]/port[:,1]*np.sqrt(12) best_port = port[np.where(sharpe == max(sharpe))] max_sharpe = max(sharpe) return port, wts, best_port, sharpe, max_sharpe def graph_sim(port, sharpe): plt.determine(figsize=(14,6)) plt.scatter(port[:,1]*np.sqrt(12)*100, port[:,0]*1200, marker='.', c=sharpe, cmap='Blues') plt.colorbar(label='Sharpe ratio', orientation = 'vertical', shrink = 0.25) plt.title('Simulated portfolios', fontsize=20) plt.xlabel('Threat (%)') plt.ylabel('Return (%)') plt.present() # Constraint operate
def port_select_func(port, wts, return_min, risk_max): port_select = pd.DataFrame(np.concatenate((port, wts), axis=1)) port_select.columns = ['returns', 'risk', 1, 2, 3, 4] port_wts = port_select[(port_select['returns']*12 >= return_min) & (port_select['risk']*np.sqrt(12) <= risk_max)] port_wts = port_wts.iloc[:,2:6] port_wts = port_wts.imply(axis=0) return port_wts def port_select_graph(port_wts): plt.determine(figsize=(12,6)) key_names = {1:"Shares", 2:"Bonds", 3:"Gold", 4:"Actual property"} lab_names = [] graf_wts = port_wts.sort_values()*100 for i in vary(len(graf_wts)): title = key_names[graf_wts.index[i]] lab_names.append(title) plt.bar(lab_names, graf_wts, coloration='blue') plt.ylabel("Weight (%)") plt.title("Common weights for risk-return constraint", fontsize=15) for i in vary(len(graf_wts)): plt.annotate(str(spherical(graf_wts.values[i])), xy=(lab_names[i], graf_wts.values[i]+0.5)) plt.present() # Return operate with no rebalancing
def rebal_func(act_ret, weights): ret_vec = np.zeros(len(act_ret)) wt_mat = np.zeros((len(act_ret), len(act_ret.columns))) for i in vary(len(act_ret)): wt_ret = act_ret.iloc[i,:].values*weights ret = np.sum(wt_ret) ret_vec[i] = ret weights = (weights + wt_ret)/(np.sum(weights) + ret) wt_mat[i,] = weights return ret_vec, wt_mat ## Rum simulation and graph
np.random.seed(123)
port_sim_1, wts_1, _, sharpe_1, _ = Port_sim.calc_sim(df.iloc[1:60,0:4],1000,4) Port_sim.graph_sim(port_sim_1, sharpe_1) # Weight selection
results_1_wts = port_select_func(port_sim_1, wts_1, 0.07, 0.1)
port_select_graph(results_1_wts) # Compute passable portfolio
satis_ret = np.sum(results_1_wts * df.iloc[1:60,0:4].imply(axis=0).values)
satis_risk = np.sqrt(np.dot(np.dot(results_1_wts.T, df.iloc[1:60,0:4].cov()),results_1_wts)) # Graph simulation with precise portfolio return
plt.determine(figsize=(14,6))
plt.scatter(port_sim_1[:,1]*np.sqrt(12)*100, port_sim_1[:,0]*1200, marker='.', c=sharpe_1, cmap='Blues')
plt.colorbar(label='Sharpe ratio', orientation = 'vertical', shrink = 0.25)
plt.scatter(satis_risk*np.sqrt(12)*100, satis_ret*1200, c='pink', s=50)
plt.title('Simulated portfolios', fontsize=20)
plt.xlabel('Threat (%)')
plt.ylabel('Return (%)')
plt.present() # Create environment friendly frontier operate
from scipy.optimize import decrease def eff_frontier(df_returns, min_ret, max_ret): n = len(df_returns.columns) def get_data(weights): weights = np.array(weights) returns = np.sum(df_returns.imply() * weights) threat = np.sqrt(np.dot(weights.T, np.dot(df_returns.cov(), weights))) sharpe = returns/threat return np.array([returns,risk,sharpe]) # Contraints def check_sum(weights): return np.sum(weights) - 1 # Rante of returns mus = np.linspace(min_ret,max_ret,20) # Perform to attenuate def minimize_volatility(weights): return get_data(weights)[1] # Inputs init_guess = np.repeat(1/n,n) bounds = tuple([(0,1) for _ in range(n)]) eff_risk = [] port_weights = [] for mu in mus: # operate for return cons = ({'sort':'eq','enjoyable': check_sum}, {'sort':'eq','enjoyable': lambda w: get_data(w)[0] - mu}) consequence = decrease(minimize_volatility,init_guess,technique='SLSQP',bounds=bounds,constraints=cons) eff_risk.append(consequence['fun']) port_weights.append(consequence.x) eff_risk = np.array(eff_risk) return mus, eff_risk, port_weights ## Create variables for froniter operate
df_returns = df.iloc[1:60, 0:4]
min_ret = min(port_sim_1[:,0])
max_ret = max(port_sim_1[:,0]) eff_ret, eff_risk, eff_weights = eff_frontier(df_returns, min_ret, max_ret) ## Graph environment friendly frontier plt.determine(figsize=(12,6))
plt.scatter(port_sim_1[:,1]*np.sqrt(12)*100, port_sim_1[:,0]*1200, marker='.', c=sharpe_1, cmap='Blues')
plt.plot(eff_risk*np.sqrt(12)*100,eff_ret*1200,'b--',linewidth=2)
plt.scatter(satis_risk*np.sqrt(12)*100, satis_ret*1200, c='pink', s=50) plt.colorbar(label='Sharpe ratio', orientation = 'vertical', shrink = 0.25)
plt.title('Simulated portfolios', fontsize=20)
plt.xlabel('Threat (%)')
plt.ylabel('Return (%)')
plt.present() ## Graph with unconstrained weights
np.random.seed(123)
port_sim_1lv, wts_1lv, _, sharpe_1lv, _ = Port_sim.calc_sim_lv(df.iloc[1:60,0:4],1000,4) Port_sim.graph_sim(port_sim_1lv, sharpe_1lv) # Weight selection
results_1lv_wts = port_select_func(port_sim_1lv, wts_1lv, 0.07, 0.1)
port_select_graph(results_1lv_wts) # Passable portfolio unconstrained weights
satis_ret1 = np.sum(results_1lv_wts * df.iloc[1:60,0:4].imply(axis=0).values)
satis_risk1 = np.sqrt(np.dot(np.dot(results_1lv_wts.T, df.iloc[1:60,0:4].cov()),results_1lv_wts)) # Graph with environment friendly frontier
plt.determine(figsize=(12,6))
plt.scatter(port_sim_1lv[:,1]*np.sqrt(12)*100, port_sim_1lv[:,0]*1200, marker='.', c=sharpe_1lv, cmap='Blues')
plt.plot(eff_risk*np.sqrt(12)*100,eff_ret*1200,'b--',linewidth=2)
plt.scatter(satis_risk1*np.sqrt(12)*100, satis_ret1*1200, c='pink', s=50) plt.colorbar(label='Sharpe ratio', orientation = 'vertical', shrink = 0.25)
plt.title('Simulated portfolios', fontsize=20)
plt.xlabel('Threat (%)')
plt.ylabel('Return (%)')
plt.present() # 5 12 months ahead with unconstrained passable portfolio
# Returns
## Run rebalance operate utilizing desired weights
port_1_act, wt_mat = rebal_func(df.iloc[61:121,0:4], results_1lv_wts)
port_act = {'returns': np.imply(port_1_act), 'threat': np.std(port_1_act), 'sharpe': np.imply(port_1_act)/np.std(port_1_act)*np.sqrt(12)} # Run simulation on current five-years
np.random.seed(123)
port_sim_2lv, wts_2lv, _, sharpe_2lv, _ = Port_sim.calc_sim_lv(df.iloc[61:121,0:4],1000,4) # Graph simulation with precise portfolio return
plt.determine(figsize=(14,6))
plt.scatter(port_sim_2lv[:,1]*np.sqrt(12)*100, port_sim_2lv[:,0]*1200, marker='.', c=sharpe_2lv, cmap='Blues')
plt.plot(eff_risk*np.sqrt(12)*100,eff_ret*1200,'b--',linewidth=2)
plt.scatter(port_act['risk']*np.sqrt(12)*100, port_act['returns']*1200, c='pink', s=50) plt.colorbar(label='Sharpe ratio', orientation = 'vertical', shrink = 0.25)
plt.title('Simulated portfolios', fontsize=20)
plt.xlabel('Threat (%)')
plt.ylabel('Return (%)')
plt.present() ## Eficient frontier on long run knowledge
df_returns_l = dat.iloc[1:254, 0:4]
min_ret_l = min(port_sim_1[:,0])
max_ret_l = max(port_sim_1[:,0]) eff_ret_l, eff_risk_l, eff_weightsl = eff_frontier(df_returns1, min_ret1, max_ret1) ## Graph with unique
plt.determine(figsize=(12,6))
plt.scatter(port_sim_1lv[:,1]*np.sqrt(12)*100, port_sim_1lv[:,0]*1200, marker='.', c=sharpe_1lv, cmap='Blues')
plt.plot(eff_risk_l*np.sqrt(12)*100,eff_ret_l*1200,'b--',linewidth=2)
plt.scatter(satis_risk1*np.sqrt(12)*100, satis_ret1*1200, c='pink', s=50) plt.colorbar(label='Sharpe ratio', orientation = 'vertical', shrink = 0.25)
plt.title('Simulated portfolios', fontsize=20)
plt.xlabel('Threat (%)')
plt.ylabel('Return (%)')
plt.present() ## Graph with five-year ahead
# Graph simulation with precise portfolio return
plt.determine(figsize=(14,6))
plt.scatter(port_sim_2lv[:,1]*np.sqrt(12)*100, port_sim_2lv[:,0]*1200, marker='.', c=sharpe_2lv, cmap='Blues')
plt.plot(eff_risk_l*np.sqrt(12)*100,eff_ret_l*1200,'b--',linewidth=2)
plt.scatter(port_act['risk']*np.sqrt(12)*100, port_act['returns']*1200, c='pink', s=50) plt.colorbar(label='Sharpe ratio', orientation = 'vertical', shrink = 0.25)
plt.title('Simulated portfolios', fontsize=20)
plt.xlabel('Threat (%)')
plt.ylabel('Return (%)')
plt.present()

Leave a Reply

Your email address will not be published. Required fields are marked *