Skip to content
All library documents

Mean-CVaR Optimization Requires a Feasible Return Target

Article Quant Q&A · Author: ironymike

Summary

The document explains why a mean-CVaR portfolio optimization may fail to meet a specified return: the target can be infeasible given the return scenarios and portfolio constraints. In the example, the assets have daily returns, so a 4% daily target exceeds the returns observed in the sample. An independent CVaR optimization produces weights, but imposing the higher minimum return makes the linear program report no feasible solution.

For an annual return target, the answer suggests converting it to a period-aligned target before optimization. It also shows how to evaluate a chosen portfolio by applying its weights to the scenario returns, then calculating volatility, VaR, and CVaR from the resulting portfolio return series. The VaR can also be read from the linear program solution. These calculations rely on the given historical scenarios and do not establish future performance; the target conversion depends on the data frequency and convention used.

Key ideas

  • A return target must be feasible under the asset scenarios and portfolio constraints.
  • Daily return data require a daily target, rather than an annual target entered without conversion.
  • An infeasible target can cause a CVaR optimization to have no solution.
  • Portfolio VaR and CVaR can be calculated from the weighted scenario return series.
  • The linear programming solution may contain the VaR estimate used during optimization.

Tags

Full text
# How to set a fixed return for mean-CVaR portfolio optimization?


# How to set a fixed return for mean-CVaR portfolio optimization?












I'm using the timeSeries and fportfolio package in R to minimize the CVaR with different constraints for a given portfolio. Everything is working out so far. However, I can't manage to set a fixed mean return. When I use `setTargetReturn(cvar_spec) <- 0.04` , as in the code below, the further code ignores it and calculates the CVAR for a smaller mean return. The last function, `portfolioFrontier()` does not return the desired value pair as well. Does anyone know a way how to fix this?

```
library(timeSeries)
library(timeDate)
library(fPortfolio)

lppAssets3 <- 100 * LPP2005.RET[, 1:6]
colMeans(lppAssets3)

cvar_spec <- portfolioSpec()
setTargetReturn(cvar_spec) <- 0.04
setType(cvar_spec) <- "CVaR"
setSolver(cvar_spec) <- "solveRglpk.CVAR"
getOptimize(cvar_spec)
getSolver(cvar_spec)

box.1 <- "minW[1:6] = 0.0"
box.2 <- "maxW[1:6] = 0.5"

group.1 <- "minsumW[1:6] = 1.0"
group.2 <- "maxsumW[1:6] = 1.0"

constraints_cvar1 <- c(box.1, box.2, group.1, group.2)

minCVAR_Portfolio2 <- minriskPortfolio(lppAssets3,
                                       cvar_spec,
                                       constraints = constraints_cvar1
)
getWeights(minCVAR_Portfolio2)

CVAR_Portfolio2_frontier <- portfolioFrontier(lppAssets3,
                  cvar_spec,
                  constraints = constraints_cvar1
)
```

## Answer by Enrico Schumann (score 4)

https://quant.stackexchange.com/a/66439

I don't use `fPortfolio` but when I run your code example, I first get an error:

```
## Error in add.constraint() : could not find function "add.constraint"
```

Nevertheless, after that, I can extract a solution:

```
getWeights(minCVAR_Portfolio2)
##      SBI      SPI      SII      LMI      MPI      ALT 
## 0.240491 0.000172 0.169241 0.500000 0.000000 0.090096
```

Cross-checking with `minCVaR` in package ǸMOF` (which I maintain):

```
library("NMOF")
R <- as.matrix(lppAssets3)
c(minCVaR(R, q = 0.05, wmax = 0.5))
## [1] 0.240491 0.000172 0.169241 0.500000 0.000000 0.090096
```

So, the computation so far seems reasonable. But your problem probably is the much-too-high required return of 0.04: Inspecting `lppAssets3` suggests that these are daily data. And then 4% is way too high: `apply(lppAssets3, 2, max)` shows you that no asset ever had a single daily return of 4% in your sample:

```
##     SBI     SPI     SII     LMI     MPI     ALT 
## 0.00364 0.02584 0.01201 0.00368 0.02408 0.01679
```

And the column means are much closer to zero. So there simply is no feasible solution. A check:

```
minCVaR(R, q = 0.05, wmax = 0.5, min.return = 0.04,
        Rglpk.control = list(verbose = TRUE))
## GLPK Simplex Optimizer 5.0
## 379 rows, 384 columns, 2975 non-zeros
##       0: obj =   0.000000000e+00 inf =   1.040e+00 (2)
##     220: obj =   3.241764706e-02 inf =   3.915e-02 (1) 2
## LP HAS NO PRIMAL FEASIBLE SOLUTION
## ....
```

I guess here that you might mean an annual return of 4%, but then you'd have to scale it so that it is aligned with the return scenarios (e.g. `0.04/250 = 0.00016`).

Update following the comment:

You can compute portfolio returns under the scenario set, and then it becomes straightforward to compute quantities of interest.

```
R <- as.matrix(lppAssets3)
sol <- minCVaR(R, q = 0.05, wmax = 0.5)
p.rt <- c(R %*% sol)
```

I use `c()` to drop (unnecessary) attributes. You now have a univariate return series `p.rt`:

```
vol <- sd(p.rt)
## [1] 0.00103604
VaR <- quantile(p.rt, probs = 0.05)
## -0.001551667 
CVaR <- mean(p.rt[p.rt <= VaR])
## [1] -0.001952581
```

The covariance matrix is not (explicitly) used in the computation, but `cov(R)` is the standard estimator.

Note that if you compute CVar-optimal portfolios with the LP-formulation of Rockafellar/Uryasev, as `minCVaR` does per default, you could also directly reuse some results of the LP, for instance the VaR:

```
-attr(sol, "LP")$solution[1]
## [1] -0.001551667
```

Perhaps this note on the implementation of minCVaR also helps.

Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)

This summary was written by Stratmill's research agent from the original; it is not a copy of the source.