import numpy as np
import pandas as pd
import scipy.stats as st
import matplotlib.pyplot as pltIntro to Risk Measures in Finance
This document is intended for educational purposes as part of my Risk Financial Management course at Tec de Monterrey. For any questions or suggestions, feel free to contact me at iguizar@tec.mx.
1 Intro
Risk measurement is a fundamental aspect of financial risk management. Two widely used measures are Value at Risk (VaR) and Expected Shortfall (ES). These measures help to quantify potential losses and inform risk management decisions. I introduce the two measures in this document.
2 Value at Risk (VaR)
Value at Risk (VaR) estimates the potential loss in value of an asset or a portfolio over a given time period for a specified confidence level. It answers the question:
What is the worst expected loss over a given time horizon at a specific confidence level?, in other words: What loss level is such that we are \(X\%\) confident it will not be exceeded in \(T\) business days?
VaR is a sigle number that can be derived from the probability distribution of returns (gains and losses) during time \(T\), by definition, however, it focuses on potential losses rather than gains.
Under Basel II, capital for credit risk and operational risk is based on a one-year 99.9% VaR. The capital required for market risk, comes from multiples of a 10-day horizon at a 99% level of confidence.
Under the simplified assumption that returns are normally distributed with mean \(\mu \ge0\), and standard deviation \(\sigma\), the VaR at \(X\%\) level of confidence is:
\[ VaR(X\%) = N^{-1}(1-X\%) \]
where \(N(\cdot)\) is the normal distribution with mean \(\mu\) and standard deviation \(\sigma\).
What is the same:
\[ VaR(X\%)= \mu + \sigma \cdot \Phi^{-1}(1-X\%) \] where \(\Phi(\cdot)\) is the standard normal standard distribution.
Example
Let’s assume a portfolio consisting of a single asset, the historical data of daily log returns have a mean of 2% and a standard deviation of 10%. Compute the 1-day 99% VaR.
Import the libraries
Visualize the distribution
mu = 0.02
sd = 0.10
# Generate synthetic daily returns to visualize the distribution
np.random.seed(123)
daily_returns = np.random.normal(loc = mu, scale = sd, size=5*252) # 252 trading days
# To plot the distribution
x_alt = np.linspace(min(daily_returns), max(daily_returns), 100)
pdf_alt = (1/(sd * np.sqrt(2 * np.pi))) * np.exp(-0.5 * ((x_alt - mu)/sd)**2)
plt.figure(figsize=(7, 5))
plt.hist(daily_returns, bins='auto', color = 'lightblue', alpha=0.75, density=True)
plt.plot(x_alt, pdf_alt, color='red', linewidth=2, label='distribution')
plt.legend()
plt.title("Daily log Returns of the Portfolio")
plt.xlabel("Returns")
plt.ylabel("Frequency")
plt.show()Calculate the VaR
X = 0.99 # Confidence level
VaR1 = st.norm.ppf(1-X,loc=mu, scale=sd)
VaR2 = mu + sd*st.norm.ppf(1 - X)
print(f"1-day 99% VaR: {-(np.exp(VaR1)-1):.2%}")
print(f"1-day 99% VaR: {-(np.exp(VaR1)-1):.2%}")1-day 99% VaR: 19.15%
1-day 99% VaR: 19.15%
Interpretation: We are 99% confident that the asset will not lose more than 19.15% over one day.
Please refer to the section A brief note on returns to clarify why a simple rate of return, \(R_t\), is calculated as: \(exp^{r_t}-1\), when \(r_t\) is the log return.
Plot the VaR
plt.figure(figsize=(7, 5))
plt.hist(daily_returns, bins='auto', color = 'lightblue', alpha=0.75, density=True)
plt.plot(x_alt, pdf_alt, color='red', linewidth=2, label='distribution')
plt.axvline(VaR1, color='red', linestyle='dashed', label='VaR 99%')
plt.legend()
plt.title("Daily log Returns of the Portfolio + VaR")
plt.xlabel("Returns")
plt.ylabel("Frequency")
plt.show()3 Expected Shortfall
Basel II faced criticism for underestimating tail risks and failing to account for extreme market conditions, as seen during the 2008 financial crisis. To address these issues, Basel III introduced several enhancements, including Expected Shortfall. The Expected Shortfall (ES), also known as conditional VaR or tail loss, measures the expected loss in the worst-case scenario beyond the VaR threshold. It provides a more comprehensive risk measure than VaR by accounting for tail risks.
Expected shortfall answers the question: If things do get bad, what is the expected loss?
It indicates the expected loss during time \(T\) conditional on the loss being greater than the \(Xth\) percentile of the loss distribution.
While VaR is the loss level that will not be exceeded with a specified probability, the Expected shortfall is the expected loss given that the loss is greater than the VaR level.
Under the simplified assumption that returns are normally distributed with mean \(\mu \ge0\), and standard deviation \(\sigma\), the ES at \(X\%\) level of confidence is:
\[ ES(X\%) = \mu - \sigma \cdot \frac{\phi \Big(\Phi^{-1}(1-X\%)\Big)}{1-X\%} \]
Example
Let’s assume a portfolio consisting of a single asset, the historical data of daily log returns have a mean of 2% and a standard deviation of 10%. We’ll compute the 1-day 99% expected shortfall.
Expected Shortfall Calculation
z = st.norm.ppf(1-X)
ES1 = mu - sd * st.norm.pdf(z) / (1-X)
print(f"The Expected Shortfall (ES) is: {-(np.exp(ES1)-1):.2%}")The Expected Shortfall (ES) is: 21.85%
Interpretation: If the VaR (19.15%) is exceed over one day, the average loss would be of 21.85%.
plt.figure(figsize=(7, 5))
plt.hist(daily_returns, bins='auto', color = 'lightblue', alpha=0.75, density=True)
plt.plot(x_alt, pdf_alt, color='red', linewidth=2, label='distribution')
plt.axvline(VaR1, color='red', linestyle='dashed', label='VaR 99%')
plt.axvline(ES1, color='orange', linestyle='dashed', label='ES 99%')
plt.legend()
plt.title("Daily log Returns of the Portfolio, VaR & ES")
plt.xlabel("Returns")
plt.ylabel("Frequency")
plt.show()Note: We could also use the fact that we have simulated the historic returns to approximate the ES as the mean beyond the VaR as follows:
ES2 = daily_returns[daily_returns <= VaR1].mean()
print(f"The Expected Shortfall (ES) is: {-(np.exp(ES2)-1):.2%}")The Expected Shortfall (ES) is: 21.97%
4 Application
Install the library pandas-datareader that will help us get access to data from the Federal Reserve (FRED). You only have to do it once.
!pip install pandas-datareaderImport the library
import pandas_datareader.data as webObtain and clean data
# Fetch the data
symbol = 'SP500'
start_date = '2021-01-01'
end_date = '2025-01-01'
SP = web.DataReader(symbol, 'fred', start=start_date, end=end_date)
SP = SP.dropna()
# Convert index to datetime and rename columns
SP.index = pd.to_datetime(SP.index)
SP.rename(columns={symbol: 'Price'}, inplace=True)
SP.head(10) # show the first 10 rows| Price | |
|---|---|
| DATE | |
| 2021-01-04 | 3700.65 |
| 2021-01-05 | 3726.86 |
| 2021-01-06 | 3748.14 |
| 2021-01-07 | 3803.79 |
| 2021-01-08 | 3824.68 |
| 2021-01-11 | 3799.61 |
| 2021-01-12 | 3801.19 |
| 2021-01-13 | 3809.84 |
| 2021-01-14 | 3795.54 |
| 2021-01-15 | 3768.25 |
Plot the time series
plt.figure(figsize=(7,5))
plt.plot(SP.index, SP['Price'], color = 'steelblue', label='SP500 Index')
plt.xlabel("Date")
plt.ylabel("Index Value")
plt.title("SP500 Market Index")
plt.legend()
plt.show()Calculate and plot daily log returns
SP['Return'] = np.log(SP['Price']).diff()
SP.dropna(inplace=True)
# Plot daily returns
plt.figure(figsize=(7,5))
plt.plot(SP.index, SP['Return'], color = 'steelblue', label="Log Returns")
plt.xlabel("Date")
plt.ylabel("Daily log Return")
plt.title("Daily Log Returns of the SP500 Market Index")
plt.legend()
plt.show()Compute the mean (\(\mu\)) and standard deviation (\(\sigma\))
mu = SP['Return'].mean()
sd = SP['Return'].std()
print(f"The mean of the daily log returns is: {mu:.4%}")
print(f"The standard deviation of the daily log returns is: {sd:.4%}")The mean of the daily log returns is: 0.0461%
The standard deviation of the daily log returns is: 1.0396%
Calculate the Value-at-risk at a 95% confidence level
X = 0.95 # Confidence level
VaR = mu + sd*st.norm.ppf(1 - X)
print(f"1-day 95% VaR: {-(np.exp(VaR)-1):.2%}")1-day 95% VaR: 1.65%
Calculate the Expected Shortfall
z = st.norm.ppf(1-X)
ES = mu - sd * st.norm.pdf(z) / (1-X)
print(f"The Expected Shortfall (ES) is: {-(np.exp(ES)-1):.2%}")The Expected Shortfall (ES) is: 2.08%
If USD 1.45mill were invested in this asset, the monetary VaR and ES, would be estimated as:
K = 1.45
VaR_Mon = K*(np.exp(VaR)-1)
ES_Mon = K*(np.exp(ES) - 1)print(f"Daily 95% VaR: ${-1000000*VaR_Mon:,.2f}")
print(f"Daily 95% Expected Shortfall: ${-1000000*ES_Mon:,.2f} ")Daily 95% VaR: $23,925.32
Daily 95% Expected Shortfall: $30,106.65
A brief note on returns
Let \(P_t\) denote the price of an asset in time \(t\). The simple or discrete net rate of return on an investment in this asset, between date \(t-1\) and \(t\), is defined as:
\[\begin{equation*} R_t = \frac{P_t-P_{t-1}}{P_{t-1}} = \frac{P_t}{P_{t-1}}-1 \end{equation*}\]
The gross rate of return is: \[\begin{equation*} R_t +1 = \frac{P_t-P_{t-1}}{P_{t-1}}+1 = \frac{P_t}{P_{t-1}} \end{equation*}\]
But \(R_t\) is not symmetric. It will never be less than 1 (never lose more than 100%), but could take any positive value, which motivates the use of log returns.
Recall, Taylor’s rule: \[\begin{equation*} e^x = 1 + x +\frac{x^2}{2!} + \frac{x^3}{3!}+.... \end{equation*}\]
So that, for \(x\) small: \(e^x \approx 1 + x\)
In the previous approximation, let \(x\) be the net rate of return at time \(t\), \(R_t\), so that \(e^{R_t} \approx 1 + R_t \approx 1+ \Big[\frac{P_t}{P_{t-1}}-1\Big]\)
Then,
\[\begin{equation*} R_t \approx ln\Big(\frac{P_t}{P_{t-1}} \Big) \end{equation*}\]
the rate of return, \(ln\Big(\frac{P_t}{P_{t-1}}\Big)\), is the log or continuously compounded rate of return between date \(t-1\) and \(t\), to avoid confusion called it \(r_t\)
Compounded return
From continuously compounded to simple rates of net return.
Since \(r_t\) is the log rate of return:
\[\begin{equation*} e^{r_t} = 1 + R_t \end{equation*}\]
The simple rate of return is: \[\begin{equation*} R_t = e^{r_t} - 1 \end{equation*}\]
Multi-period returns
Let \(r_t\) be the monthly log rate of return. To calculate the compounded anual rate of return, \(r(12)\):
\[\begin{equation*} r(12) = r_{12} + r_{11} + \cdots + r_1 \end{equation*}\]
More generally, \[\begin{equation*} r(n) = r_n + r_{n-1} + \cdots + r_{1} \end{equation*}\] and \[\begin{equation*} R(n) = exp(r_n + r_{n-1} + \cdots + r_{1}) -1 \end{equation*}\]