Common Probability Distributions in Finance › Fat-Tailed Distributions
Quantitative FinanceAll chapters Common Probability Distributions in Finance › Fat-Tailed DistributionsOne section · Sections in this chapter5 / 8 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
A normal distribution is only one possible model for returns. When an observed or simulated return distribution places more probability in sufficiently remote tails than a fitted normal model, normal tail calculations can misstate extreme-event frequencies and downstream risk measures. The examples below use a seeded Student's t sample to show how to diagnose that mismatch without presenting synthetic observations as market data.
Evidence of Fat Tails
Here, "fat tails" means slower remote-tail decay than a specified normal benchmark. The comparison requires a common location/scale convention and sufficiently large thresholds; it does not order every finite-threshold probability. For models without a finite mean, tail behavior must be described relative to another location parameter rather than an undefined mean. Two useful diagnostics follow:
Kurtosis: The normal distribution has a kurtosis of 3 (or excess kurtosis of 0). Kurtosis is the fourth central moment divided by the variance squared. A higher value signals more weight on large standardized deviations overall, but it does not by itself order every tail probability or identify where probability moved between the center and shoulders.
Tail exponents: For power-law-tailed distributions, the probability of extreme events decays polynomially rather than exponentially. The tail exponent characterizes how fast this decay occurs. A smaller means slower polynomial decay and fatter tails, while a larger means faster polynomial decay and thinner tails within the power-law family. For every finite , however, the asymptotic tail remains heavier than a normal tail.
Simulated Daily Returns (Heavy-Tailed, t-distribution df=4) ================================================== Number of observations: 6,000 Mean daily return: 0.0079% Daily volatility: 1.3944% Skewness: 0.086 Excess Kurtosis: 5.719 Extreme Event Frequency -------------------------------------------------- Event Observed Expected (Normal) Ratio -------------------------------------------------- |r| > 3σ 80 16.2 4.9x |r| > 4σ 30 0.4 78.9x |r| > 5σ 9 0.0 2616.4x
The seeded sample was generated from a heavy-tailed distribution, so its departure from the normal benchmark is expected rather than empirical evidence about markets. For this seed, absolute moves beyond four sample standard deviations occur 30 times, compared with about 0.38 expected in 6,000 independent normal draws, a ratio of about 79. Nine observations exceed five sample standard deviations, compared with about 0.0034 under that same normal benchmark. The exercise demonstrates how a known heavy-tailed data-generating process changes extreme-event counts; it does not estimate their frequency in an observed market.
The Student's t Distribution
The Student's t distribution provides a simple way to model fat tails while retaining many convenient properties of the normal distribution. William Sealy Gosset published small-sample work under the pseudonym "Student" while working as an experimental brewer at Guinness. In finance, a location-scale t model is one candidate for forecasting or fitting heavy-tailed returns; its suitability still needs to be checked.
A probability distribution with heavier tails than the normal distribution, characterized by its degrees of freedom parameter . As , it converges to the normal distribution. For small , it assigns higher probability to extreme events.
The probability density function of the standard t distribution with degrees of freedom is:
This formula may look complex, but its structure shows the key difference between the t distribution and the normal distribution. While the normal distribution uses the exponential function which decays very rapidly, the t distribution uses a power function which decays much more slowly. This slower decay is precisely what produces the heavier tails.
Each component:
- : the value at which we evaluate the density
- : degrees of freedom parameter (controls tail thickness; lower means fatter tails)
- : the gamma function, generalizing the factorial to non-integer values ( for positive integers)
- : a normalization constant ensuring the density integrates to 1
- : the core term that produces polynomial rather than exponential tail decay
The polynomial decay versus the normal's exponential decay is why the t distribution has heavier tails. To understand this intuitively, consider what happens as becomes large. For the normal distribution, doubling quadruples the magnitude of the exponent because , so the density decays extremely rapidly. For the t distribution, the density is asymptotically proportional to , so doubling a large threshold reduces the density by about . Its one-sided survival probability is proportional to , so doubling a large threshold reduces that probability by about . As , the polynomial term converges to the exponential, and the t distribution approaches the normal.
Key properties of the t distribution:
- Degrees of freedom (): Controls tail thickness. Lower values mean fatter tails.
- Convergence: As , the t distribution approaches the standard normal.
- Variance: For , the variance is , which is always greater than 1. For , the mean exists but the variance is infinite. For , the mean and therefore the variance are undefined. The second raw moment diverges throughout .
- Kurtosis: For , excess kurtosis is , always positive and decreasing in . For , the kurtosis is undefined because the fourth moment does not exist.
When fitting returns, the degrees of freedom must be estimated or otherwise justified for the dataset and model; there is no universal range for financial returns. Values near 4 illustrate the family's moment boundary: for , the fourth moment diverges, while for it is finite. The seeded example uses deliberately.


The log-scale plot shows density heights, not probabilities beyond a threshold. At , the unit-variance t distribution with 3 degrees of freedom has about 633 times the normal density. Integrating beyond 5 gives a different comparison: its one-sided survival probability is about 5,650 times the normal survival probability. The normal probability is about 1 in 3.5 million observations; the scaled t probability is about 1 in 600. For independent daily draws and 252 trading days per year, the expected waiting times are roughly 13,900 trading years and 2.4 trading years. These are model-based averages, not event schedules.
Fitting the t Distribution to Simulated Returns
We can fit a location-scale t distribution to the seeded heavy-tailed sample and compare the log-likelihoods evaluated at the returned numerical fits. This does not establish a global maximum for the unrestricted t likelihood. Because the sample was generated from a t distribution, it is a reproducibility check and model-comparison demonstration, not evidence about observed market returns. For , the t standard deviation is , where is its scale parameter; scale itself is not the standard deviation. For , no finite standard deviation exists.
import numpy as np
from scipy import stats
# Fit a scaled t distribution to the simulated returns
# The t distribution has location, scale (not SD), and degrees of freedom.
# Use the returns array from the fat-tails-evidence cell
# Ensure returns is available and convert to numpy array
# Regenerate data to ensure availability (matching fat-tails-evidence cell)
np.random.seed(42)
n_days = 6000
daily_returns = np.random.standard_t(df=4, size=n_days) * 0.01 + 0.0003
returns_array = daily_returns
# Numerical likelihood fitting; no global-maximization guarantee.
t_params = stats.t.fit(returns_array)
t_nu, t_loc, t_scale = t_params
# Fit normal for comparison
norm_loc, norm_scale = stats.norm.fit(returns_array)
# Calculate log-likelihoods
t_loglik = np.sum(stats.t.logpdf(returns_array, t_nu, t_loc, t_scale))
norm_loglik = np.sum(stats.norm.logpdf(returns_array, norm_loc, norm_scale))Distribution Fitting Results ================================================== Normal Distribution: Location (μ): 0.000079 Scale (σ): 0.013944 Log-likelihood: 17,123 Student's t Distribution: Degrees of freedom (ν): 4.23 Location: 0.000055 Scale: 0.010172 Log-likelihood: 17,526 Log-likelihood improvement: 403 The t distribution provides a substantially better fit to the data.
For this seed, the returned t fit has about 4.23 degrees of freedom and a log-likelihood about 403 higher than the fitted normal model. That difference is expected because the sample was generated from a t distribution. Exponentiating it gives a likelihood ratio evaluated at those fits, not posterior odds; posterior model odds require priors and marginal likelihoods.


Power-Law Tails
Power-law notation provides a general way to describe polynomial tail decay. Student's t distributions already have power-law tails, but other regularly varying models can use a different exponent or slowly varying factor:
This asymptotic relationship describes the right-tail survival function for large thresholds. It includes the polynomial right tail of a Student's t distribution as a special case. For a nonnegative variable, the exponent controls positive moments; for a signed variable, existence of a full moment also depends on the left tail, which this one-sided relationship does not specify.
The components of this relationship are:
- : the probability that the random variable exceeds value (the survival function)
- : a large threshold value
- : the tail exponent, which controls how fast probabilities decay. Some authors also call a tail index; in another common extreme-value-theory convention, the tail index is
- : denotes asymptotic equivalence. The ratio of the left side to approaches 1 as
A larger means faster polynomial decay and a smaller means slower decay. As an illustration, if and the asymptotic approximation is appropriate at both thresholds, doubling a sufficiently large threshold reduces its exceedance probability by approximately . This is much slower than the exponential falloff of normal tails.
For comparison, the one-sided standard-normal survival probability falls by a factor of about from 4σ to 8σ, roughly eleven orders of magnitude. Under the illustrative cubic law, the corresponding asymptotic reduction is only a factor of 8. Which approximation is appropriate must be established from a specified model or dataset rather than inferred from this contrast alone.
A distribution where the probability of observing a value greater than decays as a power of : . The tail exponent determines how fat the tails are. Lower means fatter tails.

The implications of power-law tails are serious for risk management:
- Moment thresholds require both tails: For and a nonnegative variable with , the right-tail contribution to is finite for and diverges for . For a signed return, the displayed right-tail relation alone cannot guarantee a full mean or variance because the left tail is unspecified. If both tails have such power-law asymptotics with exponents and , absolute moments exist for and diverge at or above that minimum. In particular, when both exponents lie strictly between 2 and 4, the mean and variance are finite, while the fourth moment is not.
- Slow convergence: Under i.i.d. sampling with finite variance ( in this tail model), the Central Limit Theorem applies, but its normal approximation can remain poor at practically available sample sizes.
- Tail concentration and dependence: With power-law marginal tails, a small number of observations can dominate a sample risk estimate. Diversification may be weaker when those tails combine with strong common or tail dependence, but marginal tail thickness alone does not determine diversification benefits.
Implications for Risk Management
Fat tails change how we should think about risk:
VaR model error: A fitted normal model can underestimate sufficiently extreme heavy left-tail quantiles, but it need not underestimate VaR at every confidence level. The direction and magnitude depend on the fitted distributions, skewness, and confidence level. The seeded example below slightly overestimates 95% VaR and underestimates 99% VaR.
Expected shortfall: Under the continuous-loss convention used here, expected shortfall is the mean loss conditional on being at or beyond the VaR threshold. Terminology such as "Conditional VaR" varies across sources, and distributions with atoms require a quantile-integral definition to handle the boundary consistently. For continuous heavy-tailed models, ES can be substantially larger than VaR.
The code treats the sample as an empirical distribution with equal probability on each observation. VaR is its inverse-CDF loss quantile. ES averages exactly the worst probability mass, using a fractional boundary weight when necessary rather than including every loss tied at VaR. For example, losses at 50% confidence give VaR and ES , not the full-sample mean . Finite-sample VaR depends on the quantile convention; the inverse-CDF convention here differs from a linearly interpolated percentile. The ratio ES/VaR is undefined when VaR is zero.
import numpy as np
from scipy import stats
def calculate_var_es(returns, confidence_levels=(0.95, 0.99)):
"""
Empirical loss VaR and quantile-integral Expected Shortfall.
VaR uses the inverse empirical CDF. ES averages exactly the upper
(1-confidence) probability mass, including fractional boundary weights.
Returns:
Dictionary with VaR and ES for each confidence level
"""
returns = np.asarray(returns, dtype=float)
if returns.ndim != 1 or returns.size == 0 or not np.all(np.isfinite(returns)):
raise ValueError("returns must be a nonempty, finite one-dimensional sample")
losses = -returns
descending_losses = np.sort(losses)[::-1]
results = {}
for cl in confidence_levels:
if not (np.isfinite(cl) and 0 < cl < 1):
raise ValueError("Confidence levels must lie strictly between 0 and 1")
# Integer arithmetic preserves the supplied float's exact CDF rank.
numerator, denominator = float(cl).as_integer_ratio()
rank = (len(losses) * numerator + denominator - 1) // denominator
var = descending_losses[len(losses) - rank]
tail_mass = len(losses) * (1 - cl)
weights = np.clip(tail_mass - np.arange(len(losses)), 0, 1)
# Scale before averaging to avoid overflowing a finite weighted mean.
loss_scale = np.max(np.abs(descending_losses))
if loss_scale == 0:
es = 0.0
else:
scaled_losses = descending_losses / loss_scale
scaled_mean = np.dot(weights / tail_mass, scaled_losses)
# Roundoff cannot move a weighted mean outside the sample range.
scaled_mean = np.clip(scaled_mean, scaled_losses.min(), scaled_losses.max())
es = scaled_mean * loss_scale
cancellation_scale = np.dot(weights / tail_mass, np.abs(scaled_losses))
if cl < 1e-8 or abs(scaled_mean) < 1e-8 * cancellation_scale:
# Rare cancellation-sensitive tails: retain exact atom weights
# and input floats, then round the final bounded mean once.
from fractions import Fraction
mass_numerator = len(losses) * (denominator - numerator)
whole, remainder = divmod(mass_numerator, denominator)
exact_total = sum(
(Fraction.from_float(float(x)) for x in descending_losses[:whole]),
Fraction(0),
)
if remainder:
exact_total += Fraction(
remainder, denominator
) * Fraction.from_float(float(descending_losses[whole]))
es = float(exact_total / Fraction(mass_numerator, denominator))
# A zero VaR has no defined ES/VaR ratio.
results[cl] = {"VaR": var, "ES": es, "ES/VaR": es / var if var != 0 else np.nan}
return results
# Regenerate data to ensure availability
np.random.seed(42)
n_days = 6000
returns_array = np.random.standard_t(df=4, size=n_days) * 0.01 + 0.0003
norm_loc, norm_scale = stats.norm.fit(returns_array)
# Compare the simulated sample with a fitted normal model
simulated_risk = calculate_var_es(returns_array)
# Normal assumption
norm_var_95 = -stats.norm.ppf(0.05, norm_loc, norm_scale)
norm_var_99 = -stats.norm.ppf(0.01, norm_loc, norm_scale)
# For normal (reported as a positive loss), ES = -mu + sigma * phi(z) / alpha where phi is the pdf
def normal_es(alpha, mu, sigma):
"""Signed normal tail loss; alpha is return-tail mass, not confidence.
The scaled tail ratio avoids forming tiny pdf/CDF terms separately.
Double-precision quantile rounding still limits accuracy when the mean and
tail terms nearly cancel. A nonfinite calculation after the affine fallback
is reported as a numerical range failure, not proof about an exact residual.
"""
from scipy.special import erfcx
if not (np.isfinite(alpha) and 0 < alpha < 1):
raise ValueError("alpha must lie strictly between 0 and 1")
if not (np.isfinite(mu) and np.isfinite(sigma) and sigma >= 0):
raise ValueError("mu must be finite and sigma nonnegative and finite")
z = stats.norm.ppf(alpha)
# phi(z)/Phi(z) through a scaled error function: neither tiny term is formed.
tail_ratio = np.sqrt(2 / np.pi) / erfcx(-z / np.sqrt(2))
with np.errstate(over="ignore", invalid="ignore"):
es = -mu + sigma * tail_ratio
if not np.isfinite(es):
scale = max(abs(mu), sigma)
es = (-(mu / scale) + (sigma / scale) * tail_ratio) * scale
if not np.isfinite(es):
raise FloatingPointError(
"Normal ES calculation remains nonfinite after scaling"
)
return es
norm_es_95 = normal_es(0.05, norm_loc, norm_scale)
norm_es_99 = normal_es(0.01, norm_loc, norm_scale)Risk Measure Comparison: Simulated Sample vs Normal Assumption ================================================================= Measure Simulated Normal Ratio ----------------------------------------------------------------- 95% VaR 2.1177% 2.2856% 0.93x 95% ES 3.1541% 2.8682% 1.10x 99% VaR 3.6797% 3.2358% 1.14x 99% ES 5.0384% 3.7084% 1.36x ----------------------------------------------------------------- The simulated 95% VaR is lower than the normal estimate, while ES and the 99% measures are higher for this seed.
The table does not show uniform underestimation. For this seed, the simulated 95% VaR is about 7% lower than the fitted-normal estimate, while simulated 95% ES is about 10% higher. At 99%, simulated VaR is about 14% higher and simulated ES about 36% higher. The example therefore supports checking each risk measure and confidence level separately; it does not establish a universal multiplier or a claim about regulatory capital.
