Skip to content
All library documents

Computing Modified Expected Shortfall with Coskewness and Cokurtosis

Article Quant Q&A · Author: Ram Ahluwalia

Summary

The document addresses slow computation of modified expected shortfall, also called modified CVaR, for a weighted portfolio using the PerformanceAnalytics package. The question compares Gaussian and modified estimation in a component-risk workflow. The response explains that the modified component decomposition requires coskewness and cokurtosis estimates in addition to the mean and covariance inputs used for Gaussian expected shortfall. Estimating those higher-order co-moment matrices is the costly step.

A suggested workaround is to calculate the third- and fourth-order co-moment matrices separately, then pass them into the expected-shortfall function instead of having the function estimate them during the call. The question’s update highlights the memory burden: these matrices scale with the asset count raised to the third and fourth powers, making the approach impractical for sufficiently large universes. The cited implementation uses internal package functions, so availability and behavior may depend on package version. The discussion explains a computational bottleneck and a reuse strategy; it does not establish that the resulting risk estimates are statistically reliable or suitable for every portfolio.

Key ideas

  • Modified component expected shortfall requires coskewness and cokurtosis estimates as well as mean and covariance.
  • Estimating the higher-order co-moment matrices can dominate runtime.
  • Precomputing those matrices and supplying them to the calculation can avoid repeated estimation.
  • Third- and fourth-order matrices grow rapidly with the number of assets and can demand substantial memory.
  • The workaround relies on internal package functions, whose availability may vary across versions.

Tags

Full text
# How to compute modified-CVaR in the PerformanceAnalytics package?


# How to compute modified-CVaR in the PerformanceAnalytics package?












My objective is to measure the modified-CVAR for a portfolio given its weights and matrix of security returns. Luckily the wonderful package PerformanceAnalytics has an ES() function that does just this.

The issue I am having is that modified-CVAR takes minutes to compute, when according to this paper (by the same authors) the algorithm should only take seconds: "...we provide a long but explicit formula for computing the derivative of mES. Although the resulting formulae are rather complex, they lend themselves to efficient translation into a simple algorithm that computes in less than a second mES and component mES, even for portfolios with a very large number of assets." (page 14)

I re-produce code from a vignette which works fine when using `method = "gaussian"` but not `method = "modified"`. I have also reviewed the CRAN reference for the PerformanceAnalytics package although it is not as clear as the paper (linked above).

```
library(PerformanceAnalytics)

tickers = c( "VNO" , "VMC" , "WMT" , "WAG" , "DIS" , "WPO" , "WFC" , "WDC" ,
 "WY" , "WHR" , "WMB" , "WEC" , "XEL" , "XRX" , "XLNX" ,"ZION" ,"MMM" ,
 "ABT", "ADBE" , "AMD" , "AET" , "AFL" , "APD" , "ARG" ,"AA" , "AGN" ,
 "ALTR" , "MO" , "AEP" , "AXP" , "AIG" , "AMGN" , "APC" ,"ADI" , "AON" ,
 "APA", "AAPL" , "AMAT" ,"ADM" , "T" , "ADSK" , "ADP" , "AZO" , "AVY" ,
 "AVP", "BHI" , "BLL" , "BAC" , "BK" , "BCR" , "BAX" , "BBT" , "BDX" ,
 "BMS" , "BBY" , "BIG" , "HRB" , "BMC" , "BA" , "BMY" , "CA" , "COG" ,
 "CPB" , "CAH" , "CCL" , "CAT" , "CELG" , "CNP" , "CTL" , "CEPH", "CERN" ,
 "SCHW" , "CVX" , "CB" , "CI" ,"CINF" ,"CTAS" , "CSCO" , "C" , "CLF" ,
 "CLX", "CMS" , "KO" , "CCE" , "CL" , "CMCSA" ,"CMA" , "CSC" , "CAG" ,
 "COP" , "ED" , "CEG" ,"GLW" , "COST" , "CVH" , "CSX" , "CMI" , "CVS" ,
 "DHR" , "DE")

 library(quantmod)
 getSymbols(tickers, from = "2000-12-01", to = "2010-12-31")
 P <- NULL; seltickers <- NULL
 for(ticker in tickers) {     
tmp <- Cl(to.monthly(eval(parse(text=ticker))))
 if(is.null(P)){ timeP = time(tmp) }
 if( any( time(tmp)!=timeP )) next
 else P<-cbind(P,as.numeric(tmp))
 seltickers = c( seltickers , ticker )
 }

 P = xts(P,order.by=timeP)
 colnames(P) <- seltickers
 R <- diff(log(P))
 R <- R[-1,]
 dim(R)

 mu <- colMeans(R)
 sigma <- cov(R)

 obj <- function(w) {
 if (sum(w) == 0) {
 w <- w + 1e-2
 }
 w <- w / sum(w)
 CVaR <- ES(weights = w,
 method = "gaussian",
 portfolio_method = "component",
 mu = mu,
 sigma = sigma)
 tmp1 <- CVaR$ES
 tmp2 <- max(CVaR$pct_contrib_ES - 0.05, 0)
 out <- tmp1 + 1e3 * tmp2 
 return(out)
 } 

 N <- ncol(R)
 minw <- 0
 maxw <- 1
 lower <- rep(minw,N)
 upper <- rep(maxw,N)

w<-rep(100/120 , 100)

# works
CVaR1 <- ES(weights = w, method = "gaussian",  portfolio_method = "component", mu = mu, sigma = sigma)

# takes too long
date()
CVaR4 <- ES(R = R , weights = w, method = "modified" , portfolio_method = "component" , clean = "boudt")
date()
```

Update:

It turns out that if you want to estimate m3 and m4 (skewness and kurtosis) you need to construct matrices with dimension (number of assets) raised to the 3rd and 4th powers. Therefore for large matrices such as the S&P 500, the memory demands are significant - my back of the envelope calculations are 25Gb. So this procedure suffers from the curse of dimensionality.

## Answer by Joshua Ulrich (score 8, accepted)

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

The "Component ES" section of `?ES` says:

> For the decomposition of Gaussian ES, the estimated mean and covariance matrix are needed. For the decomposition of modified ES, also estimates of the coskewness and cokurtosis matrices are needed.

The estimate of the coskewness and cokurtosis matrices are what take such a long time. You can calculate them beforehand and pass them to `ES`. `?ES` says:

> The matrices can be estimated through the functions ‘skewness.MM’ and ‘kurtosis.MM’.

but I do not see those functions in the version of PerformanceAnalytics installed on my system. `ES` itself uses the unexported functions `M3.MM` and `M4.MM`, so you could call them explicitly:

```
m3 <- PerformanceAnalytics:::M3.MM(R)
m4 <- PerformanceAnalytics:::M4.MM(R)
CVaR4 <- ES(R=R , weights=w, method="modified", portfolio_method="component",
  clean="boudt", m3=m3, m4=m4)
```

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.