Fat Tails (Kurtosis) in Python
The tendency of financial return distributions to exhibit more frequent and severe extreme events than a normal distribution predicts.
Definition
Fat Tails, formally characterized by excess kurtosis (leptokurtosis), describe the empirical reality that financial returns are not normally distributed. Extreme events — crashes, flash crashes, liquidity crises — occur far more frequently than Gaussian models predict. A normal distribution has a kurtosis of 3 (excess kurtosis of 0). Daily equity returns typically exhibit excess kurtosis of 4–10, meaning tail events are exponentially more probable than standard models assume. This single statistical fact invalidates a vast proportion of academic portfolio theory when applied naively to live markets.
Quantitative Formula
Where is the number of observations, is the return at period , and is the mean return. Excess Kurtosis is defined as : a value of 0 indicates normality, positive values indicate fat tails (leptokurtic), and negative values indicate thin tails (platykurtic). Skewness complements kurtosis by measuring the asymmetry of the distribution.
Why It Matters in Backtesting
A backtesting framework that assumes normal returns will compute VaR, position sizes, and stop losses that are catastrophically too tight. The 2008 financial crisis produced daily moves that a Gaussian model would classify as '25-sigma events' — events that should occur once in the lifetime of the universe. In practice, a strategy must be stress-tested against fat-tail scenarios explicitly, and risk models should use Student-t or Pareto distributions for tail estimation instead of Gaussian assumptions.
Python Implementation
import numpy as np
import pandas as pd
from scipy import stats
def analyze_tail_risk(returns: pd.Series) -> dict:
"""
Analyzes distribution tail characteristics using kurtosis, skewness,
normality tests, and empirical tail event frequency.
"""
excess_kurtosis = stats.kurtosis(returns.dropna()) # Fisher definition (normal=0)
skewness = stats.skew(returns.dropna())
# Jarque-Bera normality test
jb_stat, jb_p_value = stats.jarque_bera(returns.dropna())
# Empirical tail frequency vs. Gaussian prediction
std = returns.std()
mean = returns.mean()
empirical_3sigma = (returns.abs() > 3 * std).mean()
gaussian_3sigma = 2 * (1 - stats.norm.cdf(3)) # ~0.27%
tail_ratio = empirical_3sigma / gaussian_3sigma if gaussian_3sigma > 0 else np.inf
return {
"excess_kurtosis": excess_kurtosis,
"skewness": skewness,
"is_leptokurtic": excess_kurtosis > 0,
"jarque_bera_statistic": jb_stat,
"normality_rejected_p005": jb_p_value < 0.05,
"empirical_3sigma_frequency": empirical_3sigma,
"gaussian_3sigma_frequency": gaussian_3sigma,
"tail_amplification_factor": tail_ratio # >1 = fatter than normal
}Test this in a live environment
Stop running Jupyter notebooks locally. Paste this Fat Tails (Kurtosis) code directly into Valetha's Strategy Lab and run a full historical backtest in seconds.
Open the Python Strategy Lab