halo 的技术博客

返回

风控问你:「如果 2008 再来一遍,我们组合会亏多少?」

传统做法有两种,各有硬伤:

  • 拍脑袋设情景:直接假设「股票 −40%、债券 +5%」。问题——这组数字从哪来?凭什么不是 −30%?情景之间的相关性呢?你凭空编了一个联合分布。
  • 直接重演历史:把 2008 那个月的收益原样搬过来。问题——历史只有一条路径,你永远在测「已知的那次」,测不出「下一次以不同方式崩」。

熵池化(Entropy Pooling, Meucci 2008)走第三条路:你有一整套历史模拟出的情景(先验),你只想说一句观点——「我觉得下季度股票崩 −12% 以上的概率,要从历史的 1.3% 抬到 22%」。然后让算法在「满足这个观点」的所有分布里,挑离先验最近的那个2008 再来不是一个凭空编的数字,而是对历史分布的一次最小手术

本文用 3 资产(股/债/金)、4000 个历史模拟情景,把整套逻辑从对偶推导跑到可读的压力 VaR/CVaR。

一、问题:观点怎么「织」进概率分布#

你有 K 个历史模拟情景 x_k(每只情景是「股/债/金」三维月度收益),先验等权 p_k = 1/K。这是你的先验——它天然带着历史里所有的相关性、肥尾、联动。

现在你要加一个观点,写成对情景的线性期望约束

E_q[f_i(X)] = μ_i     即   Σ_k q_k · f_i(x_k) = μ_i
plaintext

对压力测试,最自然的 f指示函数——「情景落在某灾难区域 A 里」:

f(x_k) = 1{ x_k ∈ A }        # 该情景是否算「灾难」
目标: Σ_k q_k · 1{x_k ∈ A} = 0.22     # 灾难概率 = 22%
plaintext

这比「拍脑袋设 −40%」强在哪?强在 q_k 是定义在所有情景上的完整概率分布,它自动继承了历史里「股票崩的时候债券往往涨、黄金往往涨」的相关性结构。你没破坏联合分布,只是把它的质量重新分配。

二、熵池化:最小相对熵的「最小手术」#

在所有满足约束的 q 里,我们挑相对熵(KL)最小的:

min_q   Σ_k q_k · ln(q_k / p_k)
s.t.   Σ_k q_k = 1
       Σ_k q_k · f_i(x_k) = μ_i
plaintext

直觉:相对熵衡量「后验 q 相对先验 p 扭了多远」。最小化它 = 只做必要的最小扭曲去满足观点,其余一切尽量保持历史原样。这是「不轻易推翻历史经验」的数学表达。

对偶:把约束藏进指数#

引入拉格朗日乘子 λ,对偶目标:

g(λ) = λ·μ − ln Σ_k p_k · exp(−λ·f(x_k))
plaintext

最优后验有闭式

q_k ∝ p_k · exp(−λ·f(x_k))
plaintext

λ 就是那把「手术刀」的力度:λ 越大,为了压到目标概率,你对先验的扭曲越狠。求 λ 只需让梯度 ∇g = μ − E_q[f] 归零——一个一维求根(单约束时)或阻尼牛顿(多约束时)就能解。

三、三种历史压力情景,量化「抬了多少」#

我们不对「凭空编」的情景测,而是对历史上真发生过的三类压力施加观点,看熵池化如何把尾部重新分配:

跑出来的关键数字:

2008 GFC(股灾):  λ=-3.104  P(灾难) 1.3%->22.0% | VaR95 -4.4%->-9.6% | CVaR -6.5%->-16.2%
2020 新冠(急跌):  λ=-2.450  P(灾难) 0.9%->10.0% | VaR95 -4.4%->-8.9% | CVaR -6.5%->-13.5%
2022 利率冲击(债跌): λ=-2.483  P(灾难) 1.8%->18.0% | VaR95 -4.4%->-4.9% | CVaR -6.5%->-7.3%
plaintext

一句话解读:一个「股灾概率抬到 22%」的观点,把组合的 95% VaR 从 −4.4% 推到 −9.6%、CVaR(平均尾部损失)从 −6.5% 推到 −16.2%——尾部风险翻了一倍多。而「债券跌」的观点对组合冲击小(组合只配 30% 债),这正说明熵池化如实继承了历史相关性:股票崩时债券往往对冲,所以纯股灾对组合更狠。

熵池化:一个「股灾概率 22%」的观点把股票收益左尾显著抬高(后验密度红 vs 先验灰)

上图:灰色是先验(历史分布),红色是施加「股灾概率 22%」后的后验。你能直接看到红色把 −12% 以左的尾巴整体抬高——它不是只在 −15% 一个点加质量,而是把整个灾难区域的相对概率都重新配重。

组合收益 CDF:压力后验把 5% 分位(VaR)明显左移

上图:CDF 曲线越往右,同样收益分位越高。三条彩色曲线(三种压力后验)在左尾都明显比灰色先验更靠左——意味着「5% 最坏情形」的收益更低,即 VaR 恶化。

同一组合,三种历史压力情景下的 95% VaR 抬升

上图:同一 60/30/10 组合,灰柱是先验 VaR(−4.4%),彩柱是三种压力后验 VaR。股灾情景把 VaR 推得最狠(−9.6%),债跌最温和(−4.9%),和组合的资产配置结构一致。

四、为什么它比「拍脑袋」强#

方法联合分布哪来相关性可解释性
拍脑袋情景凭空编 −40%/+5%易漏、需手动设数字无来源
重演历史只有一条老路径真实但单一只测已知危机
熵池化从历史先验派生自动继承历史相关λ/KL 量化「扭曲多大」

最妙的是最后一项:熵池化自带「代价函数」KL(q||p) 度量你对先验扭了多远。观点越极端,λ 越大、KL 越大——你可以在报告里写「这个压力情景相对历史扭了 KL=0.3,属于中度调整」,而不是「我觉得应该测一下这个」。

五、三类真实陷阱(不写这些就是美化风险)#

陷阱 1:离散约束的数值不稳定#

本文的压力观点 f = 1{灾难区域}阶跃函数——它关于 λ 的梯度在 λ→∞ 时行为很差,朴素牛顿法会一头扎到 λ=-80 的极端解(我们第一版就翻车了:P(灾难) 直接从 1.3% 跳到 100%)。 对策:单约束用 brentq 一维求根(稳),多约束用阻尼牛顿;并对 λ 设边界。本文最终用 brentq 才拿到合理的 λ≈-3

陷阱 2:过拟合观点(Garbage In, Garbage Out)#

熵池化绝不生产新信息——它只是把你塞进去的观点,按最小扭曲铺开。如果你的观点本身错(「我觉得股灾概率 80%」只是恐慌),后验就是一场精确的自欺。 对策:观点要来自可辩护的来源——宏观团队的衰退概率模型、期权隐含的尾部概率、历史分位数。并且永远并列展示「先验 VaR vs 后验 VaR」,让决策者看到「扭了多大」。

陷阱 3:灾难区域是主观的#

「股灾」到底定义为 股票月跌 > 12% 还是 > 15%?边界一挪,先验里「算灾难」的情景比例就从 1.3% 变 0.5%,同样的目标概率 22% 对应的 λ 和尾部形状完全不同。 对策:对灾难阈值做敏感性扫描(12%/15%/20% 各跑一遍),报告 VaR 对阈值的定义域,而不是只报一个点。

六、落地路径(从演示到风控流程)#

  1. 建先验:用更长窗口(5~10 年日/月收益)做历史模拟,生成 K=10000+ 情景;或结合 GARCH 把波动聚集也编进去。
  2. 定观点:从期权隐含分布 / 宏观模型 / 专家判断抽 1~3 个可辩护的矩约束(灾难概率、某资产期望、相关性偏移)。
  3. 解后验:单约束 brentq、多约束阻尼牛顿,全程 log 空间防溢出。
  4. 读风险:用后验 q 重算组合收益分布,输出 VaR/CVaR、回撤、甚至优化后对冲权重。
  5. 控陷阱:报 KL(q||p) 量化扭曲;对灾难阈值、观点强度做敏感性扫描。
  6. 进流程:把「先验 vs 各压力后验」做成风控委员会的标准材料一页纸。

小结:熵池化把「压力测试」从「编故事」升级成「对历史分布做可量化的最小手术」。它的诚实在于——既告诉你观点把尾部推到了哪(VaR/CVaR 抬升),也告诉你你为此扭了先验多远(KL)。但记住:它只忠实铺开你给的观点,观点错了,再优雅的分布也是自欺

最后更新:2026-07-18

熵池化压力测试:把先验观点与历史分布融合成压力情景
https://blog.halo26812.eu.org/blog/entropy-pooling-stress
Author halo
Published at 2026年7月18日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨