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)
Example 25. This example demonstrates the construction and comparison of optimal portfolios using two risk measures: variance and CVaR. Historical daily price for four assets (Tesla, Meta, Microsoft, and Pfizer) are considered from Yahoo Finance and converted into return series. A mean–variance (MV) efficient frontier is then computed, showing the set of optimal portfolios that offer the smallest risk level (measured by variance or standard deviation) for a given expected return. Key portfolios, including the minimum variance and tangency portfolios, are extracted and their weights, expected returns, risks levels, and Sharpe ratios are analyzed. The same process is repeated using CVaR at the 5\% probability, generating a CVaR–efficient frontier and corresponding optimal portfolios.
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
assets <- c("TSLA", "META", "MSFT", "PFE")
getSymbols(assets, src = "yahoo", from = as.Date("2021-01-01"), to = as.Date("2024-12-31"))

# Compute daily returns
A <- cbind(
  dailyReturn(Cl(TSLA)),
  dailyReturn(Cl(META)),
  dailyReturn(Cl(MSFT)),
  dailyReturn(Cl(PFE))
)
A <- as.timeSeries(A)
colnames(A) <- c("Tesla", "Meta", "Microsoft", "Pfizer")

# Set risk-free rate
risk_free_rate <- 0.00011733

# Use default spec and modify with setters
spec_mv <- portfolioSpec()
setType(spec_mv) <- "MV"
setOptimize(spec_mv) <- "minRisk"
setRiskFreeRate(spec_mv) <- risk_free_rate
setNFrontierPoints(spec_mv) <- 50

# Generate efficient frontier
efficient_mv <- portfolioFrontier(A, spec_mv, constraints = "LongOnly")

# 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
tangency_mv <- tangencyPortfolio(A, spec_mv, constraints = "LongOnly")
minrisk_mv  <- minriskPortfolio(A, spec_mv, constraints = "LongOnly")

# 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
sharpe_mv <- (getTargetReturn(tangency_mv)["mean"] - risk_free_rate) / getTargetRisk(tangency_mv)["Sigma"]
sharpe_mv

# CVaR efficient frontier
spec_cvar <- portfolioSpec()
setType(spec_cvar) <- "CVaR"
setSolver(spec_cvar) <- "solveRsymphony"
setAlpha(spec_cvar) <- 0.05
setRiskFreeRate(spec_cvar) <- risk_free_rate

efficient_cvar <- portfolioFrontier(A, spec_cvar, constraints = "LongOnly")

# 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
tangency_cvar <- tangencyPortfolio(A, spec_cvar, constraints = "LongOnly")
minrisk_cvar  <- minriskPortfolio(A, spec_cvar, constraints = "LongOnly")

# 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)
sharpe_cvar <- (getTargetReturn(tangency_cvar)["mean"] - risk_free_rate) / getTargetRisk(tangency_cvar)["CVaR"]