4、历史情景构建:基于历史极端事件

做压力测试,最怕什么?

怕你构造的场景不够「狠」。我见过太多团队,自己编的场景跑起来风平浪静,结果市场一波动,系统直接崩了。说白了,你编的场景再花哨,也不如真实发生过的事件有说服力。

所以这一章,咱们聊聊怎么用历史极端事件来构建情景。1987年股灾、2008年金融危机,这些都是绝佳的素材。

4.1 为什么要用历史事件?

我个人习惯,做压力测试第一件事就是翻历史。为什么?因为历史事件包含了真实的市场行为——恐慌、踩踏、流动性枯竭。这些是数学模型很难模拟出来的。

举个例子,1987年10月19日,道琼斯指数一天跌了22.6%。你想想看,这种级别的波动,你写代码模拟的时候,敢不敢设这么大的参数?但历史告诉你,它就是发生了。

核心原则:历史情景不是让你预测未来,而是验证你的系统在最坏情况下能不能扛住。

4.2 构建历史情景的步骤

嗯,这里要注意,不是把历史数据直接扔进去就完事了。你得做几步处理。

  1. 数据清洗——去掉停牌、异常跳空、数据缺失的部分
  2. 时间对齐——不同品种的交易时间不一样,得统一到同一时间轴
  3. 波动率缩放——把历史波动率映射到当前市场环境
  4. 相关性调整——历史的相关性结构可能已经变了,需要修正

我曾经在项目中遇到过一个问题:直接把2008年的数据拿来用,结果发现当时很多品种的流动性跟现在完全不是一个量级。跑出来的结果,系统显示没事,但我知道那是假的。

4.3 1987年股灾情景构建

1987年股灾有个特点:它是由程序化交易引发的。说白了,就是机器在互相踩踏。这个场景对现在的量化系统特别有参考价值。

具体怎么构建?我建议这样做:

  • 提取1987年10月19日到10月20日的分钟级价格数据
  • 计算当时的波动率曲线和相关性矩阵
  • 把价格序列按比例缩放到当前市场水平
  • 加入当时的成交量冲击模型

小技巧:1987年股灾中,标普500期货的跌幅比现货还大。如果你做期现套利,这个场景必须测。

4.4 2008年金融危机情景构建

2008年跟1987年不一样。它不是一天暴跌,而是持续几个月的流动性枯竭。这对系统的考验更大——不是瞬间崩盘,而是慢慢失血。

我个人习惯把2008年分成三个阶段:

阶段 时间 特征
第一阶段 2008年1月-3月 波动率上升,相关性开始变化
第二阶段 2008年6月-9月 流动性急剧下降,价差扩大
第三阶段 2008年10月-12月 全面恐慌,所有资产一起跌

构建情景时,我建议把这三个阶段的数据都提取出来。每个阶段对系统的压力点不一样。第一阶段考验风控的预警能力,第二阶段考验订单执行系统,第三阶段考验资金管理。

注意:2008年很多市场的涨跌停板制度跟现在不一样。直接套用历史数据,可能会触发当前系统的风控规则。一定要做规则适配。

4.5 核心逻辑框架

下面这张图,是我做历史情景构建时用的核心流程。你看一眼就明白了。

历史情景构建核心流程 历史事件选择 数据提取与清洗 波动率缩放 相关性调整 流动性映射 规则适配 生成压力测试情景 验证与回测

你看,整个流程是串行的。每一步都不能跳过。我见过有人图省事,直接拿历史数据跑,结果相关性没调整,跑出来的结果完全失真。

4.6 代码示例:提取历史事件数据

下面这段代码,是我常用的历史数据提取逻辑。你拿去改改就能用。

def extract_historical_event(start_date, end_date, symbols):
    """
    提取历史事件期间的数据
    """
    data = {}
    for symbol in symbols:
        # 从数据库或文件读取
        raw = load_data(symbol, start_date, end_date)
        
        # 清洗:去掉停牌和异常值
        clean = raw[raw['volume'] > 0]
        clean = clean[clean['close'] > 0]
        
        # 计算收益率
        clean['return'] = clean['close'].pct_change()
        
        # 计算波动率
        clean['volatility'] = clean['return'].rolling(20).std()
        
        data[symbol] = clean
    
    return data

提示:提取数据时,记得把当时的市场状态也记录下来——比如涨跌停板、熔断机制、交易时间。这些信息在后续的规则适配中会用上。

4.7 避坑指南

做历史情景构建,有几个坑我踩过,你注意一下:

  • 不要直接复制历史价格——市场结构变了,价格水平也变了,必须做缩放
  • 注意市场微观结构的变化——比如2008年还没有高频交易,现在的市场环境完全不同
  • 相关性不是固定的——危机期间,所有资产的相关性都会趋向1,这个要单独处理

我曾经在项目中直接用了2008年的相关性矩阵,结果跑出来的情景显示风险对冲效果很好。但我知道这是假的——因为2008年后期,所有对冲策略都失效了。后来我加了一个「相关性漂移」的修正,才得到真实的结果。

4.8 小结

历史情景构建,说白了就是让历史重演一次。但你不能原封不动地搬过来,得做适配、做调整。1987年股灾和2008年金融危机是两个经典案例,一个测瞬时冲击,一个测持续压力。

我个人建议,每个季度至少更新一次历史情景库。市场在变,你的系统也在变,历史情景也得跟着迭代。

记住:历史不会简单重复,但它的韵律会再次响起。你的系统能不能听懂这个韵律,就看压力测试做得到不到位了。

专注资料整理