The estimation of Value at Risk and Expected Shortfall

[This article was first published on Portfolio Probe » R language, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

An introduction to estimating Value at Risk and Expected Shortfall, and some hints for doing it with R.


“The basics of Value at Risk and Expected Shortfall” provides an introduction to the subject.

Starting ingredients

Value at Risk (VaR) and Expected Shortfall (ES) are always about a portfolio.

There are two basic ingredients that you need:

  • The positions within the portfolio
  • A history of prices for the assets involved

With these you can derive two less basic ingredients:

  • The portfolio weights come from the positions and the current prices
  • The asset return history can be found from the price history

These can be used to estimate market risk.  There are other risks — such as credit risk — that may not be included in the price history.

Multivariate estimation

VaR and ES are each a single risk number at the portfolio level while we are starting at the asset level.  One approach is to estimate a variance matrix of the asset returns and then use the portfolio weights to collapse to the portfolio variance.

This is most likely to be done when it is desired to see the sources of risk rather than just have a single number.

Univariate estimation

Estimation is simpler with a single time series of returns for the portfolio — the portfolio as it is now.

We can get this by matrix-multiplying the matrix of simple returns of the assets in the portfolio by the portfolio weights.  In R notation this is:

R1 <- assetSimpRetMatrix %*% portWts

or safer would be:

R1 <- assetSimpRetMatrix[, names(portWts)] %*% portWts

Note that this is similar to the computation that was warned about in “An easy mistake with returns”.  But in this case we don’t want the returns of a real portfolio — we want the hypothetical returns of our portfolio as it now exists.

The R1 object computed above holds the (hypothetical) simple returns of the portfolio.  Modeling is often better with log returns.  You can transform from simple to log returns like:

r1 <- log(R1 + 1)

There are additional choices, of course, but some common methods are:

  • historical (use the empirical distribution over some number of the most recent time periods)
  • normal distribution (estimate parameters from the data) and use the appropriate quantile
  • t-distribution (usually assuming the degrees of freedom rather than estimating them)
  • fit a univariate garch model and simulate ahead

R Implementations

Here is an incomplete guide to VaR and ES in the R world.

My search for R functionality was:


This package has functions VaR and ES.  They take a vector or matrix of asset returns.  Component VaR, marginal VaR and component ES can be done.  Distributions include historical, normal and a Cornish-Fisher approximation.

Here are some examples where spxret11 is a vector of the daily log returns of the S&P 500 during 2011.  So we are getting the risk measure (in returns) for the first day of 2012.

> VaR(spxret11, method="historical")
VaR -0.02515786
> VaR(spxret11, method="gaussian")
VaR -0.0241509
> VaR(spxret11, method="gaussian", p=.99)
VaR -0.03415703
> ES(spxret11, method="historical")
ES -0.03610873
> ES(spxret11, method="gaussian")
ES -0.03028617

If the first argument is a matrix, then each column can be thought of as an asset within the portfolio.  This is illustrated with some data from the package:

> data(edhec)
> VaR(edhec[, 1:5], portfolio_method="component")
no weights passed in, assuming equal weighted portfolio
[1,] 0.02209855

Convertible Arbitrage            CTA Global 
         0.0052630876         -0.0001503125 
Distressed Securities      Emerging Markets 
         0.0047567783          0.0109935244 
Equity Market Neutral 

Convertible Arbitrage            CTA Global 
          0.238164397          -0.006801916 
Distressed Securities      Emerging Markets 
          0.215252972           0.497477204 
Equity Market Neutral 

Package actuar

This package also has a VaR function that works with a special form of distribution objects.

Doing it yourself

There is not very much functionality available in R for Value at Risk and Expected Shortfall probably because it is extremely easy to do whatever you want yourself.

Warning: none of the functions given below have been tested.  There is a reasonably high probability of bugs.

The functions are placed in the public domain — you are free to copy them and use them however you like.


Here is a definition of a simple function for historical estimation of Value at Risk:

VaRhistorical <- function(returnVector, prob=.05, 
    notional=1, digits=2) 
  if(prob > .5) prob <- 1 - prob
  ans <- -quantile(returnVector, prob) * notional
  signif(ans, digits=digits)

This is used for a 13 million dollar portfolio like:

> VaRhistorical(spxret11, notional=13e6)

The expected shortfall is barely more complicated:

EShistorical <- function(returnVector, prob=.05, 
    notional=1, digits=2) 
  if(prob > .5) prob <- 1 - prob
  v <- quantile(returnVector, prob)
  ans <- -mean(returnVector[returnVector <= v]) * 
  signif(ans, digits=digits)

This can be used like:

> EShistorical(spxret11, notional=13e6)
[1] 470000

So the Value at Risk is $330,000 and the Expected Shortfall is $470,000.

normal distribution

There’s a better (in a statistical sense) version later, but here is a simple approach to getting Value at Risk assuming a normal distribution:

VaRnormalEqwt <- function(returnVector, prob=.05, 
    notional=1, expected.return=mean(returnVector), 
  if(prob > .5) prob <- 1 - prob
  ans <- -qnorm(prob, mean=expected.return, 
    sd=sd(returnVector)) * notional
  signif(ans, digits=digits)

This is used like:

> VaRnormalEqwt(spxret11, notional=13e6)
[1] 310000
> VaRnormalEqwt(spxret11, notional=13e6, 
+     expected.return=0)
[1] 310000

Computing the Expected Shortfall in this case is slightly complicated because we need to find the expected value of the tail.  Numerical integration works fine for this.

ESnormalEqwt <- function(returnVector, prob=.05, 
    notional=1, expected.return=mean(returnVector), 
  if(prob > .5) prob <- 1 - prob
  retsd <- sd(returnVector)
  v <- qnorm(prob, mean=expected.return, sd=retsd) 
  tailExp <- integrate(function(x) 
      x * dnorm(x, mean=expected.return, sd=retsd), 
      -Inf, v)$value / prob
  ans <- -tailExp * notional
  signif(ans, digits=digits)

The result for our example with this is:

> ESnormalEqwt(spxret11, notional=13e6)
[1] 390000

A much better approach that is still quite simple is to use exponential smoothing to get the volatility (as the original RiskMetrics did):

VaRnormalExpsmo <- function(returnVector, prob=.05, 
     notional=1, expected.return=mean(returnVector), 
     lambda=.97, digits=2)
  if(prob > .5) prob <- 1 - prob
  retsd <- sqrt(tail(pp.exponential.smooth(
     returnVector^2), 1))
  ans <- -qnorm(prob, mean=expected.return, sd=retsd) *
  signif(ans, digits=digits)

where pp.exponential.smooth is taken from “Exponential decay models”.

> VaRnormalExpsmo(spxret11, notional=13e6)
[1] 340000

t distribution

The tricky bit with the t distribution is remembering that it doesn’t have 1 as its standard deviation:

VaRtExpsmo <- function(returnVector, prob=.05, 
    notional=1, lambda=.97, df=7, digits=2)
  if(prob > .5) prob <- 1 - prob
  retsd <- sqrt(tail(pp.exponential.smooth(
     returnVector^2), 1))
  ans <- -qt(prob, df=df) * retsd * sqrt((df - 2)/df) *
  signif(ans, digits=digits)

The result of this one is:

> VaRtExpsmo(spxret11, notional=13e6)


There are several choices for garch estimation in R.

extreme value theory

There are also several choices of packages for extreme value theory.  See, for instance, the Finance task view.


What have I missed in the R world?

Are there any bugs in my functions?

To leave a comment for the author, please follow the link and comment on their blog: Portfolio Probe » R language. offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)