第四节:极值理论(EVT)入门

各位同学,今天咱们聊聊极值理论。说实话,这玩意儿在风控圈里属于“压箱底”的功夫。平时你可能用不上,但一旦市场出现极端波动——比如2008年、2020年那种——你就知道它有多重要了。

我刚开始做风控那会儿,总觉得正态分布能解决一切问题。直到有一次,我负责的债券组合在一天之内跌了7个标准差……嗯,从那以后,我再也不敢小看“尾部”了。

4.1 为什么需要极值理论?

传统统计模型,比如正态分布,对中间数据拟合得很好。但尾部呢?说白了,它根本不管。你想想看,正态分布的尾部衰减是指数级的,而真实市场的尾部往往是幂律分布——厚尾、不对称、有聚集效应。

举个例子:你用正态分布去算VaR,99%置信度下可能给出2.3%的损失。但真实历史数据告诉你,同样置信度下实际损失可能是5.8%。这差距,足以让一家机构一夜破产。

核心观点:极值理论不关心数据的“身体”,只关心数据的“尾巴”。它专门用来建模那些极小概率、极大影响的事件。

4.2 两大主流方法:Block Maxima vs. POT

EVT里有两个经典流派。我个人习惯把它们比作两种捕鱼方式:

  • Block Maxima(块极大值法):把时间切成等长的块,每块只取最大值。比如每天取一个日收益率最大值,然后对这些“块最大值”建模。
  • POT(峰值超过阈值法):设定一个阈值,超过这个阈值的所有数据点都留下来。比如只关注收益率低于-3%的那些日子。

我在项目中遇到过一个问题:用Block Maxima时,块大小怎么选?选大了,样本太少;选小了,块内最大值可能不“极值”。后来我干脆两种方法都跑一遍,对比结果再决策。

4.3 Block Maxima方法详解

Block Maxima的理论基础是Fisher-Tippett定理。简单说:当块大小足够大时,块最大值的分布会收敛到三种极值分布之一——Gumbel、Fréchet、Weibull。实际中我们常用广义极值分布(GEV)来统一表示。

GEV的分布函数长这样:

G(z) = exp{ -[1 + ξ(z - μ)/σ]^(-1/ξ) }

其中μ是位置参数,σ是尺度参数,ξ是形状参数。ξ的正负决定了尾部厚度:ξ>0是厚尾(Fréchet型),ξ=0是指数尾(Gumbel型),ξ<0是有界尾(Weibull型)。

实战技巧:我建议你先用MLE(最大似然估计)拟合GEV参数。如果样本量小(比如少于100个块),可以考虑用L-矩估计,更稳健。

4.4 POT方法详解

POT方法更灵活,因为它不浪费数据。你设定一个阈值u,然后只关注超过u的那些“峰值”。根据Pickands-Balkema-de Haan定理,当u足够大时,超过阈值的部分近似服从广义帕累托分布(GPD)。

GPD的分布函数:

H(y) = 1 - (1 + ξy/σ)^(-1/ξ)

这里y = x - u,表示超过阈值的部分。σ是尺度参数,ξ还是形状参数——和GEV里的ξ是同一个东西。

阈值怎么选?嗯,这里要注意。阈值太低,GPD拟合不好;阈值太高,样本太少。我常用的方法是画“平均超出量函数图”(Mean Excess Plot),找曲线开始线性变化的那个点。

避坑指南:我曾经在某个项目中,为了追求样本量,把阈值设得太低。结果GPD拟合出来的尾部厚度严重偏大,导致VaR高估了30%。后来我改用“阈值稳定性图”来辅助判断,才把问题解决。

4.5 两种方法的对比

维度 Block Maxima POT
数据利用率 低(只取块最大值) 高(所有超过阈值的数据)
参数估计 GEV(3个参数) GPD(2个参数)
阈值选择 块大小(主观性较强) 阈值u(有统计方法辅助)
适用场景 有明确周期(如日、周、月) 连续数据,无固定周期
尾部推断 直接给出块最大值的分布 可推断任意分位数

我个人更偏爱POT方法,因为它对数据更“友好”。但Block Maxima在监管报告里更常见——比如巴塞尔协议里用的就是块最大值法。

4.6 代码实战:用Python拟合尾部

下面给一段我常用的代码。注意,这不是玩具代码,是我在实盘回测中反复用过的。

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import genextreme as gev
from scipy.stats import genpareto as gpd

# 模拟厚尾数据(学生t分布,自由度3)
np.random.seed(42)
data = np.random.standard_t(df=3, size=10000)

# ---------- Block Maxima ----------
# 按100个数据点分块
block_size = 100
n_blocks = len(data) // block_size
block_max = [np.max(data[i*block_size:(i+1)*block_size]) 
             for i in range(n_blocks)]

# 拟合GEV
params_gev = gev.fit(block_max)
print(f"GEV参数: μ={params_gev[0]:.3f}, σ={params_gev[1]:.3f}, ξ={params_gev[2]:.3f}")

# ---------- POT ----------
# 设定阈值(95%分位数)
threshold = np.percentile(data, 95)
excesses = data[data > threshold] - threshold

# 拟合GPD
params_gpd = gpd.fit(excesses)
print(f"GPD参数: σ={params_gpd[0]:.3f}, ξ={params_gpd[1]:.3f}")

# 计算99.9%分位数(极端VaR)
p = 0.999
# 用POT反推
n_exceed = len(excesses)
n_total = len(data)
zeta = n_exceed / n_total  # 超过阈值的比例
var_pot = threshold + (params_gpd[0]/params_gpd[1]) * (( (1-p)/zeta )**(-params_gpd[1]) - 1)
print(f"POT估计的99.9% VaR: {var_pot:.3f}")

# 对比真实值
true_var = np.percentile(data, p*100)
print(f"历史模拟的99.9% VaR: {true_var:.3f}")

运行这段代码,你会发现POT估计的VaR和历史模拟值非常接近。而如果用正态分布去算,结果会小得多——这就是尾部风险被低估的典型例子。

4.7 核心知识体系

下面这张图是我自己画的,把EVT的核心逻辑串起来了。你仔细看一遍,应该能对本章内容有个整体把握。

极值理论(EVT)核心知识体系 极值理论 EVT Block Maxima 方法 POT 方法 Fisher-Tippett定理 GEV分布拟合 块大小选择 Pickands定理 GPD分布拟合 阈值选择 尾部风险量化 VaR / CVaR 压力测试

你看,从EVT出发,两条路径最终都指向尾部风险量化。Block Maxima适合有固定周期的数据,POT更灵活。实际工作中,我建议你两种都试试,然后对比结果——如果差异很大,说明你的数据或阈值选择可能有问题。

本章小结:极值理论不是万能的,但它是在极端事件面前最可靠的统计工具之一。记住:尾部风险不是“黑天鹅”,而是“灰犀牛”——它一直在那里,只是你平时没去看它。

专注资料整理