跳到主要内容

压力测试与情景分析

直觉

VaR/CVaR 描述的是「常态分布的尾部」,但真正让机构破产的,是常态之外的极端事件——2008、2020、2022 这类相关性突然趋同、所有资产一起跌的危机。压力测试故意跳出历史分布,直接问:「如果 2008 重演,我会亏多少?」「如果股债同跌、商品暴涨,组合扛得住吗?」它分两类:情景分析(代入一组极端但合理的资产冲击,算确定损失)和蒙特卡洛压力(把分布的均值/相关性往坏处推,重算尾部风险)。

情景损失与压力分布

情景分析:给定一组资产冲击 s=(s1,,sn)s=(s_1,\dots,s_n),组合损失直接为:

Lscenario=iwisiL_{\text{scenario}} = -\sum_i w_i\, s_i

蒙特卡洛压力:用历史数据估均值 μ\mu 与协方差 Σ\Sigma,做 Cholesky 分解 Σ=LL\Sigma=LL^\top 生成相关随机样本 r=Lz+μr=Lz+\mu;压力版本把均值压低(μμkσ\mu\to\mu-k\sigma)或抬高相关性,重算 CVaR。

「人话」解释:为什么要「跳出历史分布」?

VaR 用的是「过去发生过的最坏 5%」。可危机的特征恰恰是「过去没怎么发生、但一旦发生就致命」——平时股债负相关(债券能对冲股票),危机时相关性翻正(股债齐跌),对冲瞬间失效。 情景分析就是「人为设定一个噩梦剧本」(比如股 −34%、债 −2%、商品 −25%),直接算组合在这个剧本下亏多少,不依赖概率分布;蒙特卡洛压力则是「把分布往坏处拧」(均值下移、波动放大、相关性趋同),看尾部风险膨胀到什么程度。两者互补:一个定方向,一个定概率尾部。

可运行案例:情景损失 + 蒙特卡洛压力

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('/data/multi_asset_daily.csv', parse_dates=['date']).set_index('date')
assets = list(df.columns); w = np.array([0.25]*4)
rets = df.pct_change().dropna()

# 1) 情景分析: 代入极端资产冲击, 算确定损失
scenarios = {
  'Risk-off(2020式)': {'equity': -0.34, 'bond': +0.03, 'commodity': -0.25, 'reit': -0.20},
  '通胀冲击(2022式)': {'equity': -0.12, 'bond': -0.10, 'commodity': +0.20, 'reit': -0.08},
  '股债齐跌(相关性翻正)': {'equity': -0.15, 'bond': -0.06, 'commodity': +0.05, 'reit': -0.10},
}
print("情景损失(组合):")
for name, sh in scenarios.items():
  loss = -sum(w[i]*sh[assets[i]] for i in range(4))
  print(f"  {name:18}: {loss:+.2%}")

# 2) 蒙特卡洛压力: 拟合均值/协方差, Cholesky 生成相关样本
mu = rets.mean().values; cov = rets.cov().values
Lc = np.linalg.cholesky(cov)
rng = np.random.default_rng(0); N = 100000
def sim(mean_vec):
  z = rng.standard_normal((N, 4))
  return (z @ Lc.T + mean_vec) @ w
base = sim(mu)
stressed = sim(mu - 2*np.sqrt(np.diag(cov)))              # 各资产均值压低 2σ
def vc(x, a=0.05):
  q = np.quantile(x, a); return -q, -x[x <= q].mean()
b_var, b_cvar = vc(base); s_var, s_cvar = vc(stressed)
print(f"\n基准 1日  VaR95={b_var:.2%}  CVaR95={b_cvar:.2%}")
print(f"压力 1日  VaR95={s_var:.2%}  CVaR95={s_cvar:.2%}  ← 均值下移, 尾部膨胀")

plt.figure(figsize=(9, 3.4))
plt.hist(base, bins=80, alpha=0.5, label='基准', color='steelblue')
plt.hist(stressed, bins=80, alpha=0.5, label='压力(均值-2σ)', color='crimson')
plt.axvline(-b_cvar, color='navy', ls='--', lw=1.4); plt.axvline(-s_cvar, color='darkred', ls='--', lw=1.4)
plt.title('组合日收益: 基准 vs 压力分布'); plt.xlabel('日收益'); plt.legend(fontsize=9)
plt.tight_layout(); plt.show()

小结

  • 情景分析:代入极端但合理的资产冲击,算确定的组合损失,不依赖概率;
  • 蒙特卡洛压力:把分布的均值/相关性往坏处推,用 Cholesky 生成相关样本,重算尾部;
  • VaR 管常态尾部,压力测试管「黑天鹅」——两者缺一不可。