1. 幸存者偏差:回测中的隐形杀手
做量化的人,谁没被幸存者偏差坑过?
我入行第三年就栽过一个大跟头。当时跑了一个多因子策略,夏普比高达3.2,回撤不到5%。我兴奋得差点直接上实盘。还好团队里的老大哥拦住了我,他说:「你数据里是不是只有现在还活着的股票?」
我一查,果然。那些退市的、ST的、暴跌90%的股票,全被我过滤掉了。策略在回测里风光无限,真上了实盘,估计一个月就亏光。
幸存者偏差,说白了就是:你只看到了活下来的,却忽略了死掉的。在因子选股里,这个陷阱尤其隐蔽。
什么是幸存者偏差?
想象一下:你统计了100个交易员的业绩,发现平均年化收益30%。你很羡慕,觉得这行真赚钱。但你没看到的是——另外900个亏光离场的人,根本没出现在你的样本里。
回测也是一样。如果你只用当前还在交易的股票做测试,就等于自动排除了那些已经退市、被ST、或者暴跌到无人问津的股票。而这些「死掉」的股票,恰恰是策略最可能亏钱的地方。
一个真实的案例
我记得有个朋友,做小市值因子策略。他用的是2023年底的股票池,回测了2015到2023年的数据。结果年化收益25%,最大回撤只有12%。
他觉得自己发现了圣杯。我问他:「你2015年的股票池里,有没有包含那些后来退市的壳公司?」
他愣住了。回去一查,2015年A股有2800只股票,到2023年只剩2500只。那消失的300只里,大部分是小市值公司。他的策略在回测里躲过了这些「炸弹」,但实盘里可不会。
修正之后,他的策略年化收益从25%掉到了9%,最大回撤扩大到35%。这才是真实水平。
如何检测幸存者偏差?
嗯,这里有几个我常用的方法:
- 检查股票数量变化:回测期内,股票池数量是否稳定?如果逐年减少,大概率有幸存者偏差。
- 对比全样本 vs 幸存样本:分别用「所有曾经存在的股票」和「当前存活的股票」做回测,看差异有多大。
- 查看退市股票的表现:如果退市股票在你的策略里普遍亏损,那幸存者偏差的影响就很大。
代码示例:如何避免幸存者偏差
下面这段代码,展示了如何用Python构建一个「无幸存者偏差」的股票池。核心思路是:在每一个回测时间点,只使用当时存在的股票。
import pandas as pd
import numpy as np
from datetime import datetime
def build_universe_without_survivorship_bias(start_date, end_date):
"""
构建无幸存者偏差的股票池
思路:在每个月底,只保留当时在交易的股票
"""
# 假设我们有一个包含所有股票历史状态的数据集
# 字段:stock_id, date, is_alive (是否在交易), market_cap, etc.
# 生成每月末的时间序列
dates = pd.date_range(start=start_date, end=end_date, freq='M')
universe = {}
for date in dates:
# 获取该时间点所有存活的股票
alive_stocks = all_stocks_data[
(all_stocks_data['date'] == date) &
(all_stocks_data['is_alive'] == True)
]
# 记录该月的股票池
universe[date] = alive_stocks['stock_id'].tolist()
# 注意:这里要包含那些即将退市的股票
# 它们虽然还活着,但可能已经ST或濒临退市
# 如果你把它们排除,就引入了新的偏差
return universe
# 使用示例
universe = build_universe_without_survivorship_bias('2015-01-01', '2023-12-31')
print(f"2015年1月股票数量: {len(universe['2015-01-31'])}")
print(f"2023年12月股票数量: {len(universe['2023-12-31'])}")
幸存者偏差的三种常见形式
| 类型 | 描述 | 影响程度 |
|---|---|---|
| 退市偏差 | 只包含当前存活的股票,忽略已退市的 | 高 |
| IPO偏差 | 回测中使用了尚未上市的股票数据 | 中 |
| 重组偏差 | 忽略被借壳、重组后改名的股票 | 中 |
你想想看,这三种偏差叠加在一起,回测结果能有多离谱?我见过一个策略,修正前夏普比2.8,修正后直接变成0.6。说白了,那2.2的夏普比全是偏差贡献的。
避坑指南
我曾经在做一个多因子模型时,发现某个因子在回测里表现特别好。仔细一查,原来这个因子对「小市值+高波动」的股票打分很高,而这些股票里有很多后来退市了。回测时它们被排除在外,因子自然显得很厉害。
后来我养成了几个习惯:
- 每次回测前,先跑一个「全样本+无未来信息」的基准。如果基准收益明显低于你的策略,那就要警惕了。
- 对退市股票做单独分析。看看你的策略在退市股票上表现如何。如果普遍亏损,说明策略可能过度依赖「幸存者」。
- 使用「滚动股票池」。每个时间点只使用当时存在的股票,而不是用一个固定的股票列表。
- 做压力测试。假设退市率提高一倍,你的策略还能赚钱吗?
知识体系图:幸存者偏差的核心逻辑
这张图把幸存者偏差的来龙去脉讲清楚了。你从「原因」出发,顺着「影响」看到后果,最后找到「解决方案」。我个人建议把它打印出来贴在工位上,每次做回测前看一眼。
好了,这一章就到这里。记住:回测里没有幸存者偏差,就像做饭不放盐——看着还行,吃起来全完蛋。