4、假设情景分析:人为设定极端参数变动进行压力测试

说实话,做量化投资这几年,我见过太多「看起来很美」的策略。

回测曲线漂亮得像教科书,实盘一跑就崩。为什么?因为市场从来不会按剧本走。你想想看,2020年疫情、2022年美联储暴力加息、2024年日本央行突然转向——这些黑天鹅事件,哪个是历史数据能预测的?

所以,假设情景分析就成了压力测试里最硬核的一环。说白了,就是你自己当导演,编一出最惨的戏,看看你的投资组合能不能扛住。

4.1 什么是假设情景分析?

假设情景分析,英文叫Scenario Analysis。它的核心逻辑很简单:

  • 设定极端参数——比如利率突然飙升500个基点(bp),或者股市一天暴跌30%
  • 计算组合损益——在这些极端条件下,你的持仓会亏多少钱
  • 评估风险承受力——亏了之后,你还能不能活下来

我个人习惯把这种分析叫做「末日测试」。嗯,名字有点中二,但确实管用。

核心要点:假设情景分析不是预测未来,而是检验组合的「抗揍能力」。你设定的情景越极端,测试结果越能暴露潜在风险。

4.2 常见的极端情景设定

我在项目中遇到过不少客户,上来就问:「能不能帮我测一下,如果明天股市跌20%会怎样?」

当然可以。但真正专业的压力测试,需要更系统化的情景设计。下面是我常用的几类:

情景类型 参数变动 典型场景
利率冲击 利率上升500bp 美联储激进加息、信用危机
股市崩盘 股指暴跌30% 2008年金融危机、2020年疫情
汇率波动 本币贬值20% 新兴市场货币危机
商品价格 原油暴涨100% 地缘政治冲突、供给中断
信用利差 信用利差扩大300bp 企业违约潮、评级下调

小技巧:设定情景时,不要只盯着一个参数。真实的市场往往是多因子共振——利率上升的同时,股市也在跌,汇率也在崩。我建议你至少设计3-5个复合情景。

4.3 实战:用Python实现利率上升500bp的压力测试

光说不练假把式。咱们直接上代码。

假设你持有一个债券组合,包含国债、信用债和可转债。现在要测试:如果利率突然上升500bp,组合会亏多少?

import numpy as np
import pandas as pd

# 模拟债券组合数据
portfolio = pd.DataFrame({
    'bond_type': ['国债', '信用债', '可转债'],
    'face_value': [1000000, 500000, 300000],  # 面值
    'coupon_rate': [0.03, 0.05, 0.02],        # 票面利率
    'maturity': [5, 3, 2],                     # 剩余期限(年)
    'yield_rate': [0.025, 0.045, 0.035]       # 当前到期收益率
})

# 定义利率冲击:上升500bp = 5%
shock = 0.05

# 计算久期近似损失
def calculate_loss(row):
    # 简化版:用修正久期估算价格变动
    duration = row['maturity']  # 近似久期
    modified_duration = duration / (1 + row['yield_rate'])
    price_change = -modified_duration * shock
    loss = row['face_value'] * price_change
    return loss

portfolio['loss'] = portfolio.apply(calculate_loss, axis=1)

print("=== 利率上升500bp压力测试结果 ===")
print(portfolio[['bond_type', 'face_value', 'loss']])
print(f"\n组合总损失: {portfolio['loss'].sum():,.2f} 元")
print(f"损失占比: {portfolio['loss'].sum() / portfolio['face_value'].sum() * 100:.2f}%")

运行结果会告诉你:这个组合在利率飙升500bp时,大概会亏掉多少钱。

我曾经帮一家私募做过类似的测试,结果发现他们重仓的长期信用债在利率冲击下亏损超过40%。客户当时脸都绿了——但还好提前发现了,及时调整了久期敞口。

注意:上面的代码用了简化久期模型,实际生产中建议使用全估值法(Full Revaluation),特别是对于含权债券或结构化产品。简化模型可能会低估损失。

4.4 股市暴跌30%的情景模拟

股票组合的压力测试,逻辑类似但参数不同。核心是看Beta暴露和流动性风险。

# 假设股票组合
stock_portfolio = pd.DataFrame({
    'stock': ['贵州茅台', '宁德时代', '招商银行', '中国平安'],
    'weight': [0.3, 0.25, 0.25, 0.2],
    'beta': [0.8, 1.2, 1.1, 1.0],  # Beta系数
    'current_price': [1800, 220, 35, 48]
})

# 设定股市暴跌30%
market_shock = -0.30

# 计算个股预期跌幅(CAPM模型简化)
stock_portfolio['expected_return'] = stock_portfolio['beta'] * market_shock
stock_portfolio['loss_pct'] = stock_portfolio['expected_return'] * 100
stock_portfolio['loss_amount'] = stock_portfolio['weight'] * stock_portfolio['expected_return']

print("=== 股市暴跌30%压力测试 ===")
print(stock_portfolio[['stock', 'weight', 'beta', 'loss_pct', 'loss_amount']])
print(f"\n组合总损失: {stock_portfolio['loss_amount'].sum() * 100:.2f}%")

你想想看,如果组合里全是高Beta的成长股,这一下可能就亏掉40%以上。但如果你配了低Beta的防御股,损失会小很多。

4.5 知识体系:假设情景分析的核心逻辑

下面这张图,是我自己总结的假设情景分析框架。每次做压力测试前,我都会先过一遍这个流程。

假设情景分析核心流程 情景定义 利率+500bp / 股市-30% 参数映射 久期 / Beta / 汇率敏感度 估值计算 全估值 / 久期近似 结果汇总 组合损失 / 风险敞口 阈值判断 是否超过风险限额 决策输出 调整仓位 / 对冲 / 减仓 反馈循环:根据结果调整情景参数

4.6 避坑指南:我踩过的几个坑

做假设情景分析这么多年,我犯过不少错误。分享几个典型的,你遇到了可以绕开走。

  • 情景太单一——我曾经只测了利率上升,没考虑汇率同时波动。结果实盘遇到「股债汇三杀」,组合直接崩了。现在我做压力测试,至少会设计5个复合情景。
  • 忽略流动性——极端行情下,很多资产根本卖不掉。你算出来的账面亏损可能只有20%,但实际想平仓得打骨折价。嗯,这个坑我吃过两次。
  • 相关性假设失效——正常市场里股票和债券是负相关,但危机时可能变成正相关。我建议你在情景分析里加入「相关性突变」这个参数。
  • 过度依赖历史数据——历史回测只能告诉你「过去发生过什么」,但黑天鹅往往是「从未发生过的事」。所以,我习惯在历史情景之外,再加一些「纯虚构」的极端情景。

我的经验:假设情景分析最忌讳「自我安慰」。很多人设计情景时,潜意识里会避开那些真正致命的场景。记住,压力测试的目的不是证明组合安全,而是找到它最脆弱的地方。

4.7 小结

假设情景分析,说白了就是给投资组合做一次「极限体检」。

你设定的参数越极端,暴露的问题越真实。利率上升500bp、股市暴跌30%——这些数字听起来吓人,但历史上都发生过,未来也一定会再发生。

我个人建议,每个季度至少做一次完整的假设情景分析。别等到市场真的崩了,才发现自己的组合不堪一击。


公众号:蓝海资料掘金营,微信deep3321