压力测试与 Regime 稳健性:你的策略能不能撑过 2027?
一条在 2010–2019 上 work 的策略可能在 2022 年崩盘。跨 regime、跨崩盘事件、合成扰动的压力测试,是部署前的最后一道防线。
在一段 regime 内的回测只告诉你策略在那段 regime 里怎么 work。压力测试告诉你它在下一段 regime 里可能怎么 work。大多数在实盘里炸掉的策略,不是因为回测错了。是因为回测只测了一段 regime,实盘碰上的是另一段。
三类压力测试加一个具体的动量例子,构成判断一条策略是否足够稳健、能不能部署的框架。
三类压力测试
压力测试分三个桶。每个桶抓的是不同的失败模式。
第一类:历史 regime 压力测试。 在特定历史时段上重跑你的回测:2008 GFC、2010 flash crash、2015–2016 中国贬值、2018 Q4 抛售、2020 COVID 崩盘、2022 利率冲击。如果你的 Sharpe 在其中任何一个时段崩了,你就知道类似事件再次发生时会发生什么。
第二类:合成扰动压力测试。 扰动你的输入数据,看策略怎么反应。Bootstrap 后的收益(有放回重抽样)、打乱的收益(打破时序结构)、扩大波动率(历史值的 1.5x 和 2x)、扩大价差(历史值的 1.5x 和 2x)、加随机游走的合成价格。
第三类:regime 切换压力测试。 最难的一类。你不知道未来 regime 长什么样,所以你构造可信的替代 regime。AFML 第 13 章用离散的 Ornstein-Uhlenbeck 过程开发了交易规则的合成数据校准;regime 条件模拟、对抗性 regime 是独立的扩展方法,不在 AFML 之内。
三类都必要。历史 regime 测已知事件。合成扰动测模型脆弱性。Regime 切换测未知的未知。
历史 regime 压力测试:危机里的动量
考虑一个动量策略的具体压力测试:做多 12 月收益头部十分位、做空尾部十分位、每月再平衡、等权。
基线回测(2010–2019,不含 2020): Sharpe 0.85,最大回撤 12%,年化收益 8%。
现在跨历史 regime 做压力测试:
2008 GFC(2008 年 1 月 – 2009 年 6 月): 动量崩了。策略买赢家、空输家,但在崩盘时赢家变成输家、输家破产。这段 Sharpe:-1.4。最大回撤:38%。
2010 Flash Crash(2010 年 5 月): 动量被反复打。Flash crash 是 5 分钟事件,但动量策略按月再平衡。5 月到 6 月的再平衡买了崩盘之后的反弹、卖了崩盘之前的赢家。结果:两周内 −3%。
2018 Q4 抛售(2018 年 10–12 月): 动量 work,但回撤抬高。这段 Sharpe:0.4。回撤:18%。策略扛住了,因为动量在 2019 年初快速恢复。
2020 COVID 崩盘(2020 年 2–3 月): 动量在最初崩盘后大幅走高。策略买到反弹。整年 2020 的 Sharpe:2.1。
2022 利率冲击(全年): 动量挣扎。债股齐跌、相关性飙升,策略的多空结构没提供预期的分散。2022 年 Sharpe:−0.3。
跨 regime 的总结: Sharpe 跨度 −1.4(2008)到 +2.1(2020)。策略的”平均”表现没意义。重要的是分布:它多久有效一次、最坏能坏到什么程度、坏的时候跟大盘相关性多高。
这正是 regime 压力测试的意义。基线 Sharpe 0.85、跨度 −1.4 到 +2.1 的策略,比基线 Sharpe 0.85、跨度 0.3 到 1.2 的策略风险大得多。后者跨 regime 稳健。前者 regime 依赖。
合成扰动压力测试
合成压力测试比历史 regime 测试便宜、抓的失败也不同。
Bootstrap 测试: 有放回地重抽样你的日收益,跑策略,算 Sharpe。重复 1000 次。如果 Sharpe 分布的宽(std dev > 均值的 30%),策略样本量脆弱。CPCV 也能抓这个,但 bootstrap 更快。
打乱收益测试: 随机打乱你的日收益,打破时间顺序。跑策略。Sharpe 应该掉到接近零(没有时间结构意味着没有 edge)。如果打乱后的 Sharpe 接近原始 Sharpe,你的策略实际上没用时间信息,你的 edge 值得怀疑。
波动率缩放测试: 把你的日收益乘 1.5x 和 2x。跑策略。Sharpe 是线性、次线性、还是反比缩放?如果波动率翻倍让 Sharpe 减半,你的策略有负凸性(在波动期亏钱)。这是个红旗。
价差扩大测试: 把交易成本乘 1.5x 和 2x。跑策略。Sharpe 会不会崩?稳健策略应该扛得住 1.5x 的成本。脆弱策略在 2x 时崩。
随机游走叠加: 用随机游走(均值和波动率跟原始序列相同)替换 10% 的价格序列。跑策略。Sharpe 大概掉 10%(你污染了 10% 的信号)。如果 Sharpe 掉了 50%,策略对噪声不稳健。
这五个测试几小时内能跑完。它们抓最常见的策略脆弱性:样本量敏感性、缺乏时间信号、负凸性、成本敏感性、噪声敏感性。
Regime 切换:难的那个问题
你不能直接对 regime 切换做压力测试,因为你不知道未来 regime 长什么样。但你可以做三件事。
构造合成 regime。 AFML 第 13 章(ISBN 978-1-119-48208-6)用离散的 Ornstein-Uhlenbeck 过程开发了交易规则的合成数据校准。多元 t-copula、GARCH、Markov 切换的扩展例子都是独立的扩展,不在 AFML 里。如果你用这些扩展,生成 1,000 条合成路径,算 Sharpe 的分布;分布宽表示对特定历史路径敏感。
测试 regime 条件表现。 把你的回测按 regime 切开(按波动率水平、趋势强度,或商业周期指标定义)。在每个 regime 里算 Sharpe。如果 Sharpe 在 80% 的 regime 为正、20% 为负,这个策略有一种你该知道的 regime 暴露。把它写下来。决定你能不能接受 20% 的失败率。
跑对抗性回测。 问自己:哪种 regime 会让这条策略崩?对一个动量策略,答案是”趋势急剧反转的 regime”(2008、2022)。构造一个趋势频繁反转的合成 regime。在上面测策略。如果 Sharpe 是负的,你得到一种已知的失败模式。把它写下来。决定这个失败模式能否接受。
诚实的框架:每个策略都有失败模式。问题是你是不是知道它们是什么、你能不能跟它们共处。
Arithmion SDK 用于 Regime 压力测试
如果你在用 Arithmion SDK,有几个原语对 regime 压力测试有帮助。
stress_test_historical 函数在用户指定的历史窗口(2008、2020、2022 等)上跑你的回测,返回每个窗口的 Sharpe、回撤和收益。你可以指定自己的窗口。
synthetic_regime_generator 构造具有用户指定的波动率、相关性和 regime 切换性质的合成收益序列。你可以生成 1000 条路径,在每条上跑策略。
regime_classifier 用隐马尔可夫模型或波动率阈值规则给每个历史日打一个 regime 标签(高波动、低波动、趋势、反转等)。然后你可以按 regime 过滤你的回测。
这些工具不会让你的策略变稳健。它们告诉你它有多稳健。这是部署的必要前提。
决策标准
跑完三类压力测试之后,你应该能回答这几个问题:
1. 策略在至少 3 个不同的历史 regime 里 work 吗? 如果它只在 2010–2019 work,在 2008、2020、2022 都失败,你拿到的是一条 regime 依赖策略。要么接受这个依赖,要么 pass。
2. 策略扛得住 1.5x 交易成本吗? 如果把成本估计翻倍就让 Sharpe 翻负,策略是成本脆弱的。Pass。
3. 跨合成路径的 Sharpe 分布窄不窄? 如果 1000 条合成路径上 Sharpe 的 std dev 大于均值的 30%,策略样本量脆弱。Pass 或者加强。
4. 策略的最坏情况回撤是多大? 跨所有压力测试,最大回撤是多少?如果它超过回测回撤的 3 倍,策略有尾部风险。Pass 或者对冲。
5. 你能不能描述策略的失败模式? “在剧烈趋势反转里亏钱” 是合法答案。“它有时候就是突然不 work 了” 不是。如果说不出来失败模式,你还没把策略理解透到能部署的程度。
如果对上面任何一个的答案是”我不知道”,部署之前你还有活干。
诚实的框架
压力测试不是一个 checkbox。它是一种生存方式。
每个严肃的量化机构都持续跑压力测试,不只是部署前。他们对照压力测试预期监控实盘表现。当实盘表现偏离预期分布,就去调查。
最常见的模式:
- 策略过了所有压力测试。
- 用小 AUM 部署。
- 实盘表现在 6 个月内匹配预期。
- 扩规模。
- Regime 切换。
- 实盘表现崩盘。
- 策略被关停。
第 6 步的崩盘不是压力测试失败。是有一种压力测试没涵盖的 regime。问题是这种 regime 是不是可预见的,以及策略是不是有限损的止损或对冲。
一条真正稳健的策略要满足:
- 在 5 个历史 regime 中的 4 个里 Sharpe 为正。
- 合成 Sharpe 分布的 std dev < 均值的 30%。
- 已知失败模式带止损。
- 容量至少为目标 AUM 的 3 倍。
- 文档化对波动率、成本和流动性的敏感性。
如果你的策略满足这五条,带着”方法靠谱”的信心去部署。未来的 regime 仍然不确定,但你已经做了能做的。
总结
回测告诉你什么是 work 过的。压力测试告诉你下一步什么可能 work。
跑历史 regime 测试抓已知事件。跑合成扰动测试抓模型脆弱性。跑 regime 切换测试抓未知未知。把失败模式写下来。给它们配上止损。按能在压力测试里观察到的最坏回撤下存活下来的 AUM 去部署。
如果你做了这些,你仍然会有失败的策略。但你不会有”策略会失败我不知道”那种失败。
参考文献:López de Prado, Advances in Financial Machine Learning, 第 13 章(Backtesting on Synthetic Data), ISBN 978-1-119-48208-6. Harris, Trading and Exchanges, 第 21 章(Market Impact and Transaction Costs), ISBN 978-0-19-514470-3. Ang, Asset Management, 第 9 章(Factor Timing and Regime Shifts), ISBN 978-0-19-995932-7.