By considering the same risk measure, $\varrho$, applied to two or more portfolios (credit loss distributions, profit-and-loss distributions, etc.) one desires to have a subadditivity property in place:

$$

\varrho(X_1 + X_2) \le \varrho(X_1) + \varrho(X_2)

$$ i.e. meaning that two combined portfolios should never be more risky than the sum of the risk of two portfolios separately. Unfortunately, the **Value-at-Risk** risk measure does not obey this rule. In my previous post I addressed that case with a practical example.

To overcome the conceptual deficiencies of the VaR related to non-subadditivity, many risk managers prefer the use of the **Expected Shortfall** (ES). Given VaR defined as:

$$

VaR_{\beta}(X) = \pm F^{-1}(\beta)

$$ depending on distribution $F$, where for the case of positively-described $F$, $\beta$ is the confidence level ($\beta = 1 – \alpha$; $\alpha$ denotes the significance level; $\alpha < \beta$). One defines the ES as follows:
$$
ES_{\beta}(X) = \frac{1}{1-\beta} \int_{0}^{1-\beta} VaR_u(X) du
$$ which inherits the properties of translation invariance, monotonicity, and homogeneity from VaR. However and furthermore, it is also subadditive what makes ES the *coherent* measure of risk.

In this short post you will find a Python code showing how to make a switch between VaR and ES such that $ES_{\beta’}(X) = VaR_{\beta}$ what requires solving for new $\beta’$. Since there is no close formula for getting $\beta’$, a numerical procedure does the job. Such calibration appears to be pretty handy when it comes to the problem of **ES allocation** for a portfolio of assets or credit loans.

**1. VaR and ES for Normal Distribution**

For $X$ to be normally distributed, $X\sim N(\mu, \sigma)$, the VaR can be quickly found by

$$ VaR_{\beta}(X) = \mu \pm \sigma \Phi^{-1}(\beta)

$$ where $\Phi(x)$ is the standard normal cumulative distribution. In Python we get the same by:

1 2 3 4 5 6 | alpha = 0.01 # confidence level beta = 1- alpha # significance level mu, sigma = 0, 1 # ~N(0,1) VaR = mu - sigma * stats.norm.ppf(alpha) print(VaR) |

2.32634787404 |

It can be shown that for $X\sim N(\mu, \sigma)$, the corresponding ES is:

$$ ES_\alpha(X) = \mu + \frac{\sigma}{\alpha} \int_{0}^{\alpha} \Phi^{-1} (1-u) du \\

= \mu + \frac{\sigma}{\alpha} \int_{1-\alpha}^{1} \Phi^{-1} (u) du

$$

By changing variables, setting the percent point function (inverse of CDF) $q=\Phi^{-1}(u)$, and integrating by substitution we get:

$$

= \mu + \frac{\sigma}{\alpha} \int_{\phi^{-1}(1-\alpha)}^{\infty} q\phi(q) dq \\

= \mu + \frac{\sigma}{\alpha}\left[ -\frac{1}{2\pi} \exp(-q^2/2) \right]_{\Phi^{-1}(1-\alpha)}^{\infty} \\

= \mu + \frac{\sigma}{\alpha}\left[ \frac{1}{2\pi} \exp(-q^2/2) \right]_{\infty}^{\Phi^{-1}(1-\alpha)}

$$ i.e.

$$

ES_\alpha(X) = \mu + \frac{\sigma}{\alpha} \phi\left( \Phi^{-1} (1-\alpha) \right)

$$ where $\phi$ denotes the standardized normal density function, what in Python takes form of:

8 | mu + sigma * stats.norm.pdf(stats.norm.ppf(1-alpha))/alpha |

2.665214220345808 |

In practice, we work more often with empirical data that can display distributions not exactly normal. It is good to have a quick recipe for estimation VaR and ES in any case.

**2. Estimation of VaR and ES using Order Statistics**

Suppose that a sample of $X_1, …, X_n$ of some recorded losses (profits) is available (discrete distribution of $X$’s) and we aim to find the corresponding VaR and ES at $\beta$ confidence level. We create a sample that is ordered in an increasing fashion, $X_{(1)} < X_{(2)} < ... < X_{(n)}$. The number of elements that we need to retain for further calculations is $\lfloor n\beta \rfloor$ which is the integer part of $n\beta$. Therefore, the data-based estimator of VaR and ES is: $$ \widetilde{VaR(X)} = X_{(\lfloor n\beta \rfloor])} $$ and $$ \widetilde{ES(X)} = \frac{ \sum_{i=[n\beta]}^n x_{(i)} } { n\alpha + 1 } $$ respectively. Again, in Python, for a sample of $n=10^6$ random variables $X\sim N(0,1)$, we derive both estimators as follows:

10 11 12 13 14 15 16 17 18 19 | n = int(1e6) rvs = np.hstack([stats.norm.rvs(size=n)]) x = np.sort(rvs) estVaR = x[int(n*beta)] estES = np.sum(x[int(n*beta) : n+1]) / (int(n*alpha) + 1) print(estVaR) print(estES) |

2.32995588245 2.66350868108 |

to be in a very good agreement with the “analytical” values (see above).

**3. Finding Expected Shortfall to match Value-at-Risk**

Eventually, addressing the main problem of solving for new $\beta’$ such to satisfy $ES_{\beta’}(X) = VaR_{\beta}$ requires a few extra lines of code, for instance:

21 22 23 24 25 26 | for newbeta in np.arange(0.50, 1, step=0.0001): var = x[int(n*newbeta)] es = np.sum(x[int(n*newbeta) : n+1]) / (int(n*(1-newbeta)) + 1) if(es > estVaR): print(beta, newbeta, VaR, es, np.percentile(rvs, newbeta*100)) break |

0.99 0.9746 2.32634787404 2.33263505863 1.95517826448 |

where for our exemplary set of data $X \sim N(0,1)$ at $n=10^6$ and the confidence level of $\beta = 0.99$ we find $ES_{\beta’}(X)$ equal $VaR_{\beta}$ for $\beta’ = 0.9746$.

It is easy to check that $VaR_{\beta’} < VaR_{\beta}$ as expected and $VaR_{\beta}(X) \cong ES_{\beta'}(X) \cong 2.33$.