halo 的技术博客

返回

你大概率用过 GARCH。它把「昨天收益的平方」塞进今天的方差方程,于是波动率对冲击的反应永远是二次的:3% 的涨和 3% 的跌贡献一样,一个 8σ 的离群点会让波动率冲上天、久久不下来。这套假设在你回测里默默运作,你却很少问一句:凭什么波动的更新规则长得一定是二次函数?

这就是 GAS(Generalized Autoregressive Score,广义自回归得分)模型要回答的问题。它的核心思想一句话就能说清:用对数似然对波动参数的「得分」(score)来驱动波动更新,而不是用收益平方这个固定的、跟分布无关的量。换句话说,GARCH 是 GAS 在高斯分布下的一个特例;一旦你把收益分布从高斯换成重尾的 Student-t,波动率的更新规则会自动变形状——它不再是二次函数,而是有上界、会阻尼极端值的稳健函数。

本文用 numpy 从零实现 GAS(1,1) 模型,用 MLE 把模拟数据里的真实参数一个不差地还原回来,再回答两个最实际的问题:离群冲击下 GAS 到底比 GARCH 稳多少?1% 的 VaR 到底该用高斯分位数还是 t 分位数?

Student-t 重尾收益与 GAS 估计的波动率:真实 vs MLE

一、GARCH 的更新规则其实是被「高斯」锁死的#

先回顾 GARCH(1,1) 的方差方程:

σt2=ω+αyt12+βσt12\sigma_t^2 = \omega + \alpha\,y_{t-1}^2 + \beta\,\sigma_{t-1}^2

写成「波动率对数」的形式更清楚。设 ft=lnσtf_t = \ln\sigma_t,标准化的冲击 ut=yt/σtu_t = y_t/\sigma_t,那么 GARCH 等价于:

ft+1=ω+α(ut21)+(α+β)ftf_{t+1} = \omega + \alpha\,(u_t^2 - 1) + (\alpha+\beta)\,f_t

注意中间那一项 ut21u_t^2 - 1。它其实就是高斯分布下、对数似然对 ftf_t 的得分。我们来验证:设 yt=σtzty_t = \sigma_t z_tztN(0,1)z_t \sim \mathcal N(0,1),则对数密度为

t=12ln(2π)lnσt12ut2\ell_t = -\tfrac12\ln(2\pi) - \ln\sigma_t - \tfrac12 u_t^2

σt\sigma_t 求导(再乘 σt\sigma_t 换到 ff 的尺度上),得分正是

tft=ut21\frac{\partial\ell_t}{\partial f_t} = u_t^2 - 1

所以 GARCH 的更新项,本质上是「高斯得分」。一旦收益真实分布不是高斯,这个得分就选错了形状——而金融收益几乎从来不是高斯,它尾重、有偏、还会出现极端跳空。

二、GAS 的得分驱动机制#

GAS 模型的通用形式是:

ft+1=ω+αst+βft,st=It1tftf_{t+1} = \omega + \alpha\,s_t + \beta\,f_t,\qquad s_t = \mathcal I_t^{-1}\,\frac{\partial\ell_t}{\partial f_t}

其中 sts_t 是缩放后的得分,It\mathcal I_t 是信息量(用于标准化尺度)。当我们把创新分布从高斯换成标准化 Student-t(自由度 ν\nu)时,得分函数会变成:

s(u2)=(ν+1)u2(ν2)+u21s(u^2) = \frac{(\nu+1)\,u^2}{(\nu-2) + u^2} - 1

这个函数就是全文的主角。对比 GARCH 的 u21u^2-1

  • GARCH(高斯)s=u21s = u^2 - 1,二次发散,u2u^2 越大得分越大,没有天花板。
  • GAS-ts=(ν+1)u2(ν2)+u21s = \frac{(\nu+1)u^2}{(\nu-2)+u^2}-1,当 u2u^2 \to \inftysνs \to \nu存在上界

这意味着,一个 8σ 的离群收益在 GARCH 里会给出 641=6364-1=63 的巨大得分、把波动率瞬间推爆;而在 GAS-t(比如 ν=4\nu=4)里,得分最多被压到 44 附近。越重尾,阻尼越强——这恰恰符合直觉:极端的单日跳变不应该让我们相信波动率永久地翻了倍。

得分函数对比:GAS 有上界,GARCH 二次发散

三、从零实现 GAS(1,1) 并用 MLE 还原参数#

下面的代码分两步:先当「上帝」用真实参数模拟一条 Student-t 重尾收益序列,再用极大似然把参数估回来。

跑出来的结果很有意思:MLE 几乎一个不差地把 ω=0.12, α=0.08, β=0.95, ν=5\omega=-0.12,\ \alpha=0.08,\ \beta=0.95,\ \nu=5 全部还原。这说明 GAS-t 模型是可识别、可稳健估计的——你不需要担心它像某些复杂模型一样参数混在一起分不开。上面第一张图里,MLE 估计出的波动率路径(虚线)和真实路径(实线)几乎重合,肉眼难以分辨。

四、离群冲击下的稳健性对比#

真正拉开差距的是「离群点」这个场景。我们造一条平稳收益序列,在第 200 个时间点人为注入一个 8σ 的离群收益,然后分别用 GARCH 和 GAS-t 滤波,看它们的波动率反应:

离群冲击下的稳健性:GARCH 尖峰 vs GAS 阻尼

结果一目了然:GARCH 在离群点处冲出一个又高又尖的峰,然后缓慢衰减(β\beta 越大衰减越慢);GAS-t 的峰明显矮一截、也更圆润。这个差异在实战里有直接的含义——如果你用 GARCH 的输出做波动率目标仓位或风险预算,一个极端单日跳变会让你的仓位被错误地砍掉一大块、且好几天都回不来。GAS 的阻尼让仓位调整更平滑、更贴近真实的风险水平,而不是被一只「黑天鹅」单日数据牵着鼻子走。

五、VaR 回测:高斯分位数低估了尾部#

波动率模型最终要落到风险度量上。我们分别用「GAS 滤波出的 σt\sigma_t」配上两种分位数做 1% 的 VaR:一种是高斯分位数 2.3263-2.3263,一种是 Student-t(ν=5\nu=5)标准化后的分位数。回测统计超越率:

from scipy.stats import norm, t as tdist
q_t = tdist.ppf(0.01, 5.0) / np.sqrt(5.0 / 3.0)   # t 分位数
q_g = norm.ppf(0.01)                                # 高斯分位数
exc_t = (y < q_t * sig).mean()   # ≈ 0.0120
exc_g = (y < q_g * sig).mean()   # ≈ 0.0153
python

期望的 1% VaR 超越率应该是 0.01。结果是:t 分位数覆盖 1.20%,高斯分位数覆盖 1.53%。前者基本贴近目标,后者明显低估了尾部——用高斯分位数,你会以为 100 天只破 1 次,实际破了 1.5 次以上,相当于尾部风险被系统性低估了 50%。

1% VaR 回测:Student-t 覆盖更贴近 1%,高斯低估尾部

六、什么时候该上 GAS#

GAS 不是「更好的 GARCH」,而是「更诚实的一族模型」。我的建议是:

  • 收益明显重尾、有跳空(单只股票、crypto、新兴市场)→ 用 GAS-t 替代 GARCH,波动率估计更稳,VaR 覆盖更准。
  • 需要把分布形状和波动更新统一建模 → GAS 的好处在于得分由似然自动导出,你换一个分布(偏 t、GED、广义双曲)波动更新规则就自动跟着变,不用重新发明公式。
  • 只想要一个快速、稳定的波动率信号 → GARCH 依然够用,别为了炫技牺牲计算速度。

一句话总结:GARCH 的更新规则被高斯分布锁死成了二次函数,而真实收益的重尾要求一个会阻尼极端值的更新规则。GAS 让这个规则从数据里「长」出来,而不是由你拍脑袋定死。 附上的四张图都是真实计算的结果——参数还原、得分函数形状、离群稳健性、VaR 回测,每一个结论都能在代码里复现。

GAS 得分驱动波动率:为什么波动模型不该被固定形状绑架
https://blog.halo26812.eu.org/blog/score-driven-gas-volatility
Author halo
Published at 2026年8月31日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨