EVT for Tail Risk: Fitting GPD to Financial Losses
Practical EVT for finance: tail index estimation with Hill and Moments, GPD fitting by MLE, return level confidence intervals, and the diagnostic plots.
Theory tells us the tail of a heavy-tailed distribution is GPD. Practice is messier. We have finite data, regime changes, a non-stationary volatility process, and the constant temptation to overfit. This article walks through the practical workflow for fitting GPD to financial losses: estimating the tail index , choosing the threshold, fitting by maximum likelihood, and reporting return levels with honest confidence intervals.
The techniques here work for any heavy-tailed financial series: equity returns, default losses, credit spreads, operational losses. The conditional on heavy tail is critical — if your data is thin-tailed, GPD fitting will give misleading answers and you should use normal-based methods instead.
Step 1: Is the Tail Heavy?
Before fitting GPD, we need to be sure the tail is heavy. Three diagnostic plots do this with no parametric assumption.
The log-scale histogram. Plot the histogram of losses on a log scale on both axes (log frequency vs. log loss value). For a normal tail, the histogram drops faster than any linear trend at the right edge. For a power-law tail , the complementary log-log plot vs. should be linear with slope .
The mean excess plot. Plot against . For a GPD with shape , the theoretical mean excess is , which is linear in . So a roughly linear segment in the mean excess plot is the signature of a GPD-shaped tail with (which is the case for finance, where typically).
The QQ plot. Sort the exceedances for , and plot against where is the fitted GPD. Departures from the diagonal diagnose tail behavior. If the largest points are above the diagonal, your shape is wrong; fit a heavier .
If all three diagnostics suggest a power tail, proceed to the tail index estimator.
Step 2: Estimating the Tail Index
The tail index is the most important number in the fit. Three estimators are widely used.
Hill Estimator (1975). Order the losses from largest to smallest: . For an upper order statistic , the Hill estimator is
Equivalently, . Asymptotic normality gives a standard error:
Hill is consistent for and easy to compute. Its main drawback is sensitivity to : too small gives high variance, too large gives bias from contaminating non-tail data. The “Hill plot” of vs. should show a stable region; pick in that region (usually around for well-behaved data, but practitioners plot and eyeball).
Moments Estimator (Dekkers-Einmahl-de Haan, 1989). Uses the second moment of the log-exceedances. For the same order statistics:
where . This is more robust to the choice of than Hill, and its asymptotic variance is smaller.
Pickands Estimator (1975). Uses the spacing between consecutive order statistics. For an upper-order-statistic index (with ), the estimator is
Equivalently, . Note that since order statistics are sorted in decreasing order, so both spacings in the ratio are non-negative. The estimator is consistent for but has very high variance in finite samples — the asymptotic variance is roughly five times that of the Hill estimator at the same (Drees et al., 2000). For most applications, Hill and Moments are preferred.
For S&P 500 daily returns 1980-2020, all three estimators give in the range 3-5 (so in the range 0.2-0.33), with Moments typically giving the most stable answer.
Step 3: Choosing the Threshold
Once you have a rough idea of from the tail index estimator, pick a threshold for the formal GPD fit. Three rules of thumb, in order of how I would use them:
-
Stability of : Fit GPD by MLE for thresholds at the 80th, 85th, 90th, 95th, 97.5th, 99th percentiles of the data. Plot vs. percentile. Look for the percentile above which is roughly constant. This is the asymptotic regime.
-
Stability of : The GPD scale parameter should satisfy approximately, so should be roughly constant. Plot this versus . The threshold region where it is flat is where the asymptotic theory holds.
-
95th percentile heuristic: If you have no other guidance, use at the 90th or 95th percentile. This gives you 5-10% exceedances, which is usually enough for stable MLE. Document this as a heuristic.
A subtle point: as increases, you have fewer exceedances and the MLE variance increases. So there’s a bias-variance tradeoff between “small = more data but more bias” and “large = less data but less bias.” Diagnostic plots show the sweet spot.
Step 4: Fit by Maximum Likelihood
The GPD has density (for )
for and . The log-likelihood for exceedances is
valid on .
The MLE exists for any when the support of the data exceeds the boundary. The standard errors come from the inverse observed Fisher information:
For small samples, the MLE can have severe finite-sample bias, particularly for near 0.5. Bootstrap or jackknife standard errors are more reliable than MLE standard errors for small .
When fitting GPD to financial losses in practice, follow this workflow:
import numpy as np
from scipy.stats import genpareto
from scipy.optimize import minimize
# Simulated financial losses. heavy-tailed with shape 0.25
np.random.seed(42)
xi_true = 0.25
sigma_true = 0.01
n_days = 5000
losses = genpareto.rvs(c=-1/xi_true, scale=sigma_true, size=n_days)
# Threshold at 95th percentile
u = np.quantile(losses, 0.95)
exceedances = losses[losses > u] - u
# Fit GPD by MLE
xi_hat, _, scale_hat = genpareto.fit(exceedances, floc=0)
# Return level for T = 250 days
T = 250
zeta_u = len(exceedances) / n_days
z_T = u + (scale_hat / xi_hat) * ((zeta_u * T) ** xi_hat - 1)
print(f"True shape: {xi_true}")
print(f"Estimated shape: {xi_hat:.3f}")
print(f"Estimated scale: {scale_hat:.5f}")
print(f"Threshold u: {u:.5f}")
print(f"Exceedance rate: {zeta_u:.4f}")
print(f"Return level for T=250: {z_T:.5f}")
Run this and you should get near 0.25. The return level will be substantially larger than the 95th percentile of the data — by design, because a 250-day return level is the worst we expect once every 250 days, which is much rarer than the worst 5% of days.
Step 5: Confidence Intervals via Profile Likelihood
A point estimate is not enough. We need a confidence interval.
The default Wald interval is wrong for small or when is near a boundary. Better is the profile likelihood interval:
For a target , find that maximizes the profile log-likelihood . The 95% profile likelihood interval is the set
(1.92 = 0.5 × ).
For GPD tail index, this gives intervals that are asymmetric and respect boundaries ( for heavy tails). Wald intervals do not.
Bootstrap is the most general approach. Resample the exceedances with replacement many times, fit GPD to each, and take the 2.5/97.5 percentiles. For bootstraps you get reasonably stable intervals, and you do not need to assume anything about the MLE distribution.
Step 6: Return Levels with Confidence Intervals
Combining everything: the -observation return level under POT is
For very large, — a power law in .
To compute a confidence interval on , use the delta method on the asymptotic joint normal distribution of (note: of the exceedance rate is approximately normal, not the rate itself). The variance of in the large- limit is
For 250-day return levels with exceedances (i.e., about 10 years of data with a 95th percentile threshold), the typical 95% CI is about of the point estimate. Wider when the data is shorter or the threshold is higher.
A Complete Example
Let me work through a synthetic example end-to-end. Generate 5 years of daily losses from a Student- distribution with degrees of freedom and scale 0.01. The tail index of Student- is for in the sense that the survival function (so ).
Step 1: Generate data. Step 2: Plot diagnostics. Step 3: Hill plot to find a stable . Step 4: Fit GPD at = 95th percentile. Step 5: Report 250-day return level with CI.
I will not include all the plots in this article, but the workflow is in the code block above. The Hill plot typically gives which is in line with the true . The GPD MLE gives , matching the true value. The 250-day return level comes out around 8-10x the standard deviation of the data, and the 95% CI is something like to .
Common Pitfalls
I have seen each of these bite real research projects.
Pitfall 1: Fitting too low a threshold. If you fit GPD at the 50th percentile, the asymptotic theory does not apply. The estimate is contaminated by non-tail data, and the tail index will be biased towards the central part of the distribution (typically larger , smaller ). Always use a diagnostic plot to pick a threshold in the stable region.
Pitfall 2: Treating GPD as a black box. genpareto.fit() will give you some answer for any data. If the data is normal, it will give you a small — which is approximately correct but not informative (you are trying to estimate the wrong distribution). Always check the diagnostics first.
Pitfall 3: Confusing GPD with GEV. The block maxima method fits GEV; the POT method fits GPD. They give related answers if the data is consistent, but they are different model classes. If you have block maxima, use GEV. If you have a continuous loss series, use GPD.
Pitfall 4: Ignoring time dependence. Daily losses are autocorrelated. The clustering of high-volatility days (GARCH effects) means exceedances are not independent. Most EVT software assumes independence. Either decluster first (extract “independent” exceedances) or use an EVT variant that accounts for clustering.
Pitfall 5: Return levels with too small. Return levels are most informative for large (annual, decadal). If you compute a 10-day return level, you are interpolating within the data, and EVT is unnecessary — empirical quantiles work fine. The reason to use EVT is precisely that you want to extrapolate beyond observed data.
The Practical Bottom Line
Use GPD when:
- Your data has clearly heavy tails (mean excess plot linear with positive slope, hill plot stable around ).
- You have at least 100 exceedances above your threshold.
- You are extrapolating beyond observed quantiles, e.g., return levels for larger than 1/(exceedance rate).
Do not use GPD when:
- The tail is normal (use Gaussian-based VaR / ES instead).
- The data is small (use empirical quantiles, with humility).
- The process is non-stationary without explicit time-varying models (e.g., GPD with time-varying scale).
Once you have a GPD fit, always report:
- The threshold and the choice rationale.
- with 95% CI.
- The return level with 95% CI for at least and .
- The diagnostic plots that justify the threshold choice.
If your risk report has a single number “the 99% VaR is USD 5M” without these diagnostics, you are looking at someone’s bad VaR estimate. If it has “EVT-based 250-day 99.5% VaR is USD 23M (95% CI [18M, 31M], , threshold at 95th percentile, exceedances)”, you are looking at a number that means something.
References
Balkema, A. A., & de Haan, L. (1974). Residual life time at great age. Annals of Probability, 2(5), 792-804.
Coles, S. (2001). An Introduction to Statistical Modeling of Extreme Values. Springer.
Dekkers, A. L. M., & de Haan, L. (1989). On the estimation of the extreme-value index and large quantile estimation. Annals of Statistics, 17(4), 1795-1832.
Hill, B. M. (1975). A simple general approach to inference about the tail of a distribution. Annals of Statistics, 3(5), 1163-1174.
McNeil, D., Frey, R., & Embrechts, P. (2010). Quantitative Risk Management. Princeton University Press. Chs. 5-6.
Pickands, J. (1975). Statistical inference using extreme order statistics. Annals of Statistics, 3(1), 119-131.