We are now ready to consider several portfolio designs and compare their performance (the underlying constraint is simply \(\mathbf{w}\ge\mathbf{0}\) and \(\mathbf{1}^T\mathbf{w}=1\)).
Recall the three heuristic portfolios we want to compare:
w_heuristic <- cbind("EWP" = w_EWP,
"QuintP" = w_QuintP[, "QuintP (mu/sigma)"],
"GMRP" = w_GMRP)
Now we stack the Markowitz-based portfolios we want to compare:
w_Markowitz <- cbind("MVP" = w_MVP,
"GMVP" = w_GMVP,
"IVP" = w_IVP,
"MSRP" = w_MSRP,
"MDP" = w_MDP,
"MDCP" = w_MDCP)
We can now compare the allocations of the portfolios:
w_all <- cbind(w_heuristic, w_Markowitz)
barplot(t(w_all), col = rainbow10equal[1:9], legend = colnames(w_all), beside = TRUE,
main = "Portfolio allocation", xlab = "stocks", ylab = "dollars")

The performance is (in-sample vs out-of-sample):
# compute returns of all portfolios
ret_all <- xts(X_lin %*% w_all, index(X_lin))
ret_all_trn <- ret_all[1:T_trn, ]
ret_all_tst <- ret_all[-c(1:T_trn), ]
# performance
t(table.AnnualizedReturns(ret_all_trn))
R>> Annualized Return Annualized Std Dev Annualized Sharpe (Rf=0%)
R>> EWP 0.0405 0.2059 0.1967
R>> QuintP 0.2518 0.1870 1.3461
R>> GMRP 0.2629 0.2638 0.9969
R>> MVP 0.2518 0.1719 1.4649
R>> GMVP 0.1873 0.1576 1.1886
R>> IVP 0.1386 0.1644 0.8434
R>> MSRP 0.2471 0.1669 1.4807
R>> MDP 0.0935 0.1886 0.4955
R>> MDCP -0.1027 0.3287 -0.3123
t(table.AnnualizedReturns(ret_all_tst))
R>> Annualized Return Annualized Std Dev Annualized Sharpe (Rf=0%)
R>> EWP 0.3397 0.2770 1.2265
R>> QuintP 0.0988 0.1748 0.5652
R>> GMRP 0.0375 0.2386 0.1572
R>> MVP 0.1196 0.1676 0.7139
R>> GMVP 0.1430 0.1779 0.8038
R>> IVP 0.2494 0.2110 1.1821
R>> MSRP 0.1033 0.1664 0.6207
R>> MDP 0.3146 0.2573 1.2229
R>> MDCP 0.4050 0.4246 0.9538
We can observe that:
- as expected, the MSRP achieves the maximum ex ante (in-sample) Sharpe ratio; however, this is not maintained ex post (out-of-sample);
- as expected, the EWP achieves the best ex post performance;
- the MVP performs poorly;
- other top performers include the IVP and MDP.
Let’s plot the wealth evolution (cumulative PnL) over the whole time:
{ chart.CumReturns(ret_all, main = "Cumulative return of portfolios",
wealth.index = TRUE, legend.loc = "topleft", colorset = rich10equal)
addEventLines(xts("training", index(X_lin[T_trn])), srt=90, pos=2, lwd = 2, col = "darkblue") }
and let’s zoom in the out-of-sample period:
chart.CumReturns(ret_all_tst, main = "Cumulative return of portfolios (out-of-sample)",
wealth.index = TRUE, legend.loc = "topleft", colorset = rich10equal)

Let’s look at the drawdown:
chart.Drawdown(ret_all_tst, main = "Drawdown of portfolios (out-of-sample)",
legend.loc = "bottomleft", colorset = rich10equal)
Clearly the MDCP and the GMRP have the worst drawdown and are unacceptable.
Finally, we can plot the (in-sample) return-risk scatter plot along with the efficient frontier:
# first, compute the efficient frontier
w_frontier_trn <- NULL
lmd_sweep <- exp(seq(-6, 6, by = 0.5))
for (lmd in lmd_sweep)
w_frontier_trn <- cbind(w_frontier_trn, MVP(mu, Sigma, lmd))
ret_frontier_trn <- xts(X_lin_trn %*% w_frontier_trn, index(X_lin_trn))
mu_frontier_trn <- table.AnnualizedReturns(ret_frontier_trn)[1, ]
sd_frontier_trn <- table.AnnualizedReturns(ret_frontier_trn)[2, ]
# plot in-sample sd-mu scatter plot
maxSR <- table.AnnualizedReturns(ret_all_trn[, "MSRP"])[3, ]
chart.RiskReturnScatter(ret_all_trn,
main = "Annualized Return and Risk (in-sample)",
symbolset = c(rep(21, 3), rep(22, 6)),
colorset = c(rep("darkred", 3), rep("darkblue", 6)),
bg = "black",
add.sharpe = maxSR)
lines(sd_frontier_trn, mu_frontier_trn)

Observe that this nice return-risk scatter plot totally deforms in an unpredictable way when we evaluate it in the out-of-sample set as we can see:
# compute the efficient frontier again but based on the test data
mu_tst <- colMeans(X_log_tst)
Sigma_tst <- cov(X_log_tst)
w_frontier_tst <- NULL
lmd_sweep <- exp(seq(-6, 6, by = 0.5))
for (lmd in lmd_sweep)
w_frontier_tst <- cbind(w_frontier_tst, MVP(mu_tst, Sigma_tst, lmd))
ret_frontier_tst <- xts(X_lin_tst %*% w_frontier_tst, index(X_lin_tst))
mu_frontier_tst <- table.AnnualizedReturns(ret_frontier_tst)[1, ]
sd_frontier_tst <- table.AnnualizedReturns(ret_frontier_tst)[2, ]
# plot out-of-sample sd-mu scatter plot
chart.RiskReturnScatter(ret_all_tst,
main = "Annualized Return and Risk (out-of-sample)",
symbolset = c(rep(21, 3), rep(22, 6)),
colorset = c(rep("darkred", 3), rep("darkblue", 6)),
bg = "black",
add.sharpe = NA,
ylim = c(0, 1))
lines(sd_frontier_tst, mu_frontier_tst)
Again this ex post return-risk scatter plot shows that the winners are EWP, IVP, and MDP.