6.3 CVaR in porfolio optimization
Mean–Variance (MV) portfolio optimization concept was introduced by Harry Markowitz, focusing on minimizing portfolio risk (measured by variance) for a given return or maximizing return for a given risk
Finding optimal weights (vector w) when minimizing the risk of portfolio for a given returns is optimization problem of quadratic programming (QP) with linear constraints
min
Linear constraint \mathbf{1}^\top w = 1 ensures that portfolio is never empty, i.e. \sum^k_{i=1}w_i=1
Linear constraint w_i \geq 0 ensures no short selling (mathematically negative weights are forbidden)
Keep in mind that \boldsymbol{w} is a vector of portfolio weights, \boldsymbol{\mu} is a vector of expected returns, \Sigma is a covariance matrix of asset returns, and \boldsymbol{1} is a vector of ones
Optimization problem in (6.7) can be adopted for minimizing the risk of portfolio measured by CVaR or Expected Shortfall (measures the expected loss in the worst–case scenarios – beyond the Value–at–Risk threshold)
\begin{equation} \begin{aligned} \min_{w, \nu, z_i} \quad & \nu + \frac{1}{(1 - \alpha)N} \sum_{i=1}^{N} z_i \\ \text{subject to} \quad & z_i \geq -w^\top r_i - \nu, \quad \\ & z_i \geq 0, \quad \\ & w^\top \mu = \mu_p \\ & \mathbf{1}^\top w = 1 \\ & w_i \geq 0 \quad \end{aligned} \tag{6.8} \end{equation}
- Why CVaR? It is coherent risk measure, it captures tail risk better then VaR, and it is suitable when returns ar non–normally distributed (asymmetric and heavy tails)
Solution
Copy the code lines below to the clipboard, paste them into an R Script file, and run them.# Load required packages
install.packages("fPortfolio")
# Load libraries
library(fPortfolio)
library(quantmod)
library(timeSeries)
# Download data
<- c("TSLA", "META", "MSFT", "PFE")
assets getSymbols(assets, src = "yahoo", from = as.Date("2021-01-01"), to = as.Date("2024-12-31"))
# Compute daily returns
<- cbind(
A dailyReturn(Cl(TSLA)),
dailyReturn(Cl(META)),
dailyReturn(Cl(MSFT)),
dailyReturn(Cl(PFE))
)<- as.timeSeries(A)
A colnames(A) <- c("Tesla", "Meta", "Microsoft", "Pfizer")
# Set risk-free rate
<- 0.00011733
risk_free_rate
# Use default spec and modify with setters
<- portfolioSpec()
spec_mv setType(spec_mv) <- "MV"
setOptimize(spec_mv) <- "minRisk"
setRiskFreeRate(spec_mv) <- risk_free_rate
setNFrontierPoints(spec_mv) <- 50
# Generate efficient frontier
<- portfolioFrontier(A, spec_mv, constraints = "LongOnly")
efficient_mv
# Plot the efficient frontier (Mean-Variance)
plot(efficient_mv, c(1, 2, 3), ylab = "", xlab = "", main = "Mean-Variance Efficient Frontier")
legend("bottomright",
legend = c("Efficient portfolios", "Minimum variance portfolio", "Tangency portfolio"),
col = c("black", "red", "steelblue"), bty = "n")
# Extract tangency and minimum-risk portfolios
<- tangencyPortfolio(A, spec_mv, constraints = "LongOnly")
tangency_mv <- minriskPortfolio(A, spec_mv, constraints = "LongOnly")
minrisk_mv
# Print results for Mean-Variance portfolios
print(getWeights(tangency_mv))
print(getTargetReturn(tangency_mv))
print(getTargetRisk(tangency_mv))
print(getWeights(minrisk_mv))
print(getTargetReturn(minrisk_mv))
print(getTargetRisk(minrisk_mv))
# Compute Sharpe ratio
<- (getTargetReturn(tangency_mv)["mean"] - risk_free_rate) / getTargetRisk(tangency_mv)["Sigma"]
sharpe_mv
sharpe_mv
# CVaR efficient frontier
<- portfolioSpec()
spec_cvar setType(spec_cvar) <- "CVaR"
setSolver(spec_cvar) <- "solveRsymphony"
setAlpha(spec_cvar) <- 0.05
setRiskFreeRate(spec_cvar) <- risk_free_rate
<- portfolioFrontier(A, spec_cvar, constraints = "LongOnly")
efficient_cvar
# Plot the CVaR-efficient frontier
plot(efficient_cvar, c(1, 2, 3), ylab = "", xlab = "", main = "CVaR Efficient Frontier")
legend("bottomright",
legend = c("Efficient portfolios", "Minimum CVaR portfolio", "Tangency portfolio"),
col = c("black", "red", "steelblue"), bty = "n")
# Extract tangency and minimum-CVaR portfolios
<- tangencyPortfolio(A, spec_cvar, constraints = "LongOnly")
tangency_cvar <- minriskPortfolio(A, spec_cvar, constraints = "LongOnly")
minrisk_cvar
# Print results for CVaR portfolios
print(getWeights(tangency_cvar))
print(getTargetReturn(tangency_cvar))
print(getTargetRisk(tangency_cvar))
print(getWeights(minrisk_cvar))
print(getTargetReturn(minrisk_cvar))
print(getTargetRisk(minrisk_cvar))
# Compute Sharpe ratio for CVaR (note: "Sigma" is not used; use targetRisk() output directly if meaningful)
<- (getTargetReturn(tangency_cvar)["mean"] - risk_free_rate) / getTargetRisk(tangency_cvar)["CVaR"] sharpe_cvar