第一步:逐条核对你的样本池
每条都按「你确实做到了」才勾。拿不准的一律留空——自查清单往乐观里填,等于给自己发了一张假合格证。
还没做到的 10 条,各自会怎么污染结果
退市的公司仍然留在样本里,退市前那段跌幅也照样计入收益。关键项
后果:退市股是幸存者偏差最直接的来源。它们通常在退市前经历了漫长而剧烈的下跌,把这批样本抹掉,等于把最差的那部分收益从分子里删掉,整条净值曲线会凭空抬升,而且回撤看起来还更小。
怎么补:拿一份含已退市证券的全量代码表,逐个核对你的池子里有没有它们;退市整理期的成交价要照实计入,不能用停牌前的价格一直挂到最后。
用到指数成分时,取的是「当时那一天的成分」,不是今天的成分表往回套。关键项
后果:这是最隐蔽的一类。拿今天的成分股名单回测十年前,等于提前知道了哪些公司熬过了十年还留在指数里——被调出指数的那批公司连同它们被调出前的跌幅一起消失了。表面上你测的是指数策略,实际上测的是「十年后的赢家组合」。
怎么补:找带生效日期的历史成分与权重表,回测里每个调仓日只允许看到那一天已经公布的成分;做不到就退一步,用可跟踪的指数基金净值代替自己合成的成分组合。
确认过数据源提供的是全历史证券,而不是只有「当前在市」的那一份列表。关键项
后果:很多免费接口给出的股票列 表天然就是「今天还能查到行情的那些」,退市的公司连代码都查不到。你以为自己做了全市场回测,实际上样本从第一行就已经被筛过一遍,而且这个筛选完全不可见。
怎么补:直接做个反向验证:随便找几只你确知已退市的代码去查,如果一条历史行情都取不到,那这个数据源做长周期回测就是不合格的,换源或者接受结论不可用。
暂停上市与长期停牌期间有明确处理规则,复牌后的补跌照实记入。
后果:停牌期间价格不动,很多回测直接把停牌日当成「零波动」跳过,复牌当天的跌停缺口就被吞掉了。更糟的处理是停牌即从样本剔除、复牌再加回来,等于系统性地跳过了最难看的那一段。
怎么补:写清楚三件事:停牌日的净值按什么价格计、停牌期间能不能调仓、复牌首日按什么价成交。三条里任何一条含糊,回测结果都不该拿去比较。
被吸收合并、私有化、换股退出的标的,按当时的对价折算进收益,而不是直接消失。
后果:并购退出的样本如果只是从池子里消失,那这部分资金在回测里就等于凭空蒸发或凭空归零,两种处理都会让结果失真。方向不一定是虚高,但一定是不可解释的偏差。
怎么补:把每一次退出都当成一次交易来记:现金对价按到账金额算,换股按换股比例转成新标的继续持有,找不到对价资料的就把这段样本单独标注出来,别混在总收益里。
剔除 ST 类标的时,用 的是「当时是否已被标记」,不是今天的名单一次性剔掉。
后果:拿今天的名单一次性剔除,等于在公司还正常的时候就提前知道了它未来会出问题。这既是幸存者偏差,也是典型的前视偏差:你用未来信息给过去的样本做了筛选。
怎么补:把标记与撤销标记都当成带日期的事件:在被标记之前照常持有,标记生效日之后再按规则处理,而不是从样本第一天起就当它不存在。
标的退出后的资金去向有明确规则,不会静默地从组合里消失。
后果:退出资金怎么处理,直接决定组合的分母。默认归入现金、按剩余标的等比再分配、还是维持空仓,三种做法的结果可以差出很多;如果代码里根本没写这条规则,往往就变成了「悄悄按剩余标的重算权重」,等于自动向幸存者集中。
怎么补:在策略里显式写出清算日、清算价与资金去向,并在净值曲线上标出每一次退出发生的时点,方便事后核对。
样本里如果有基金,已清盘或已转型的那些也留着,不是只统计仍在运作的。
后果:基金层面的幸存者偏差比股票更严重,因为业绩差的产品会被清盘或转型,从统计口径里彻底退出。只统计现存产品算出来的平均业绩,天然是一份「优等生名单」。
怎么补:统计区间内成立过的产品全部纳入,清盘的按清盘公告净值截止,转型的按转型日切段,并在结论里注明样本一共包含多少只、其中多少只中途退出。
新股上市之前的那段区间留空,没有用 0 收益或首日价格往前填。
后果:用 0 填充等于给样本凭空加了一段无风险的横盘,会压低波动率、抬高夏普;用首日价格前推则更糟,相当于把上市首日的定价当成上市前就存在的事实。
怎么补:上市前的日期一律置为空值,在计算等权或加权组合时按当日实际有效样本数归一化,而不是按固定的池子只数。
用样本只数随时间的变化做过交叉核对,早年的池子确实比今天小。
后果:这是最省力的一次体检。如果你的池子在样本期第一天就有和今天一样多的股票,那几乎可以断定名单是拿今天的列表往回套的——市场在扩容,早年的可交易证券数量本来就更少。
怎么补:把每个交易日的有效样本数画成一条曲线,看它是不是随时间自然增长;出现平直的一条横线,说明样本池根本没有按时间重建。
第二步:粗估这些漏掉的样本值多少个百分点
下面四栏都请按你自己样本的实际情况填,页面里的初始值只是为了让公式跑起来的演示假设, 不代表任何市场的实际退出率或跌幅。这一块是量级估算,不是精确修正——它的四条假设写在结果下方。
这个估算的四条假设
- 期初等权买入全部样本,中途不调仓、不再买入新标的。
- 幸存样本整体按你填的年化匀速增长,不考虑年度间的波动。
- 退出样本的价值在退出时定格在「期初的一减去平均跌幅」倍,此后不再变化,也不考虑清算残值。
- 退出在样本期内按恒定的年均退出率均匀发生,不考虑集中退市的年份。
这四条在真实数据里都不严格成立,所以结果只用来判断量级:是零点几个百分点,还是好几个百分点。 它不能当作修正值直接从你的回测年化里减掉。
风险提示
- 清单只覆盖常见的几类样本泄漏,全部勾上也不等于样本一定干净,更不等于策略有效。
- 把样本修干净只是让回测这份数据可信一点。回测不等于实盘,实盘还有滑点、成交不了以及临时改规则。
- 估算部分是简化模型,四条假设与真实市场有距离,结果仅供判断量级。
- 本工具只做核对与算术,不判断任何标的,不发出买卖信号,也不承诺任何收益。
教育演示:风险分 = 未做到条目的权重和 ÷ 权重总和,关键项另有单独的升级规则。 本工具仅为测算演示,不构成投资建议。
怎么用
6 步- 先想清楚样本池是怎么来的:在勾任何一条之前,先把你的股票池是从哪张表、按什么条件筛出来的说清楚。多数幸存者偏差不是算错了,而是在取数那一步就已经发生,后面再怎么调参数都补不回来。
- 逐条勾选,拿不准的一律留空:清单分三组:样本池怎么定、样本的生老病死怎么记、数据源本身干不干净。只有你确实做到了才勾,含糊的、想当然的都留空——自查往乐观里填,等于给自己发一张假合格证。
- 看风险分级和关键项:分级由未做到条目的权重和决定,同时有一条单独规则:三条关键项里任意一条没做到,等级至少是「中」,两条及以上直接判「高」。因为这三条各自都足以单独让整份回测失去参考价值,平均分再好看也没用。
- 照着「还没做到的几条」逐个补:每条没做到的条目下面都写了两件事:它会怎么污染结果、以及具体怎么补。按权重从高到低排,先修最上面那几条,改动最小、收益最大。
- 用第二块估个量级:填样本期长度、期间退出样本占比、退出前平均跌幅,以及你自己回测出来的年化,工具会算出全样本口径下的年化,两者之差就是虚高幅度。四栏都按你自己数据的实际情况填,页面初始值只是让公式跑起来的演示假设。
- 把假设读完再用这个数:估算基于四条简化假设,写在结果下方。它只回答「量级是零点几个百分点还是好几个百分点」,不能当成修正值直接从你的回测年化里减掉。
一份回测好不好看,先取决于样本里还剩谁
检验一个策略,多数人的第一反应是调参数、换指标、改止损。但在这些之前, 有一个更前置的问题决定了后面所有工作有没有意义:你测的这批样本, 是当年真实存在的那批,还是活到今天的那批?这两者的差别, 比任何参数调整带来的差别都大。
如果你的股票池是「今天还能查到行情的那些公司」,那么退市的、 被吸收合并的、被调出指数的样本已经全部消失了。它们消失的方式很安静: 代码查不到,接口不报错,代码照样跑得通,结果照样输出, 只是数字悄悄变好看了。剩下的全是熬过来的赢家, 于是历史成绩系统性虚高,而且这个虚高不会出现在任何一张回撤图上—— 因为最难看的那部分数据,压根就没进来过。
这就是幸存者偏差。它不是一个统计学名词那么抽象, 它是每一次「从行情接口拉一份股票列表」时都会发生的具体事故。 本页上半部分的清单,逐条列出了这个事故最常见的十个入口; 下半部分的估算,给这件事一个大致的量级感。
样本消失的三条路径
第一条是退市。 这是最直接的一类。公司走完退市流程后从行情列表里消失, 很多数据接口不再提供它的历史行情。而退市从来不是突然发生的, 它前面通常有一段漫长而剧烈的下跌,正是这段最该被计入的收益, 整段从样本里蒸发了。少掉它们,等于把最差的那部分从分子里删掉。
第二条是停牌与暂停上市。 停牌期间价格不动。如果回测把停牌日当成零波动直接跳过, 复牌当天的缺口就被吞掉了;如果处理成「停牌即剔除、复牌再加回」, 那更等于系统性地跳过了最难看的那一段。这条的关键不在于选哪种处理, 而在于必须显式地选一种,并且在结论里说明。
第三条是变身:借壳与重大重组。 代码还在,价格序列也连续,但代码背后已经换了一家公司。 回测看到的是「跌到谷底后强力反弹」,实际上前半段属于原来那家已经不存在的公司, 后半段属于新装进来的资产。把两段接起来当成同一只股票的收益, 在经济意义上是不成立的。这一类最难处理,因为数据完全正常, 只有对照公告才能发现。
最隐蔽的一类:指数成分调整
前面三条至少还留下痕迹——数据查不到、序列有缺口。指数成分调整不留任何痕迹。 你想测一个基于某指数成分股的策略,最自然的做法是拿一份成分名单, 去取这些股票过去若干年的行情。但这份名单是今天的名单, 而指数会定期调整成分:表现变差、市值缩水的公司被调出,新的公司被调进来。
用今天的名单回测多年前,等于你在多年前就提前知道了哪些公司能熬到今天还留在指数里。 被调出的那批公司,连同它们被调出之前那段下跌,一起消失了。 表面上你测的是指数策略,实际测的是「若干年后的赢家组合」: 收益虚高、回撤偏小、风险调整后的指标也跟着偏高,而一切看起来都很正常, 因为被调出的公司今天还在正常交易,数据要多少有多少。
正确的做法是使用带生效日期的历史成分与权重表, 让回测在每个调仓日只看到那一天已经公布的成分。这份数据不便宜也不好找, 拿不到时有个务实的退路:直接用可跟踪的指数基金净值代替自己合成的成分组合。 它粗糙,但它至少不会因为样本泄漏而系统性偏乐观。
虚高幅度大概是个什么量级
页面下半部分给的是一个刻意简化的算法:假设期初等权买入全部样本, 其中一部分在样本期内退出,退出样本的价值定格在「期初的一减去平均跌幅」倍, 剩下的幸存样本按你填的年化匀速增长。两部分按比例加权得到全样本口径的期末财富, 再开样本期长度次方还原成年化,与幸存口径的年化相减,差额就是虚高幅度。 图里两条曲线之间的那块阴影,就是被夸大的部分。
它的四条假设都不严格成立,这一点必须说在前面:退出样本在暴跌之前往往也涨过, 定格在初始值会低估它们的贡献;退市清算有时还有残值; 退出也不是均匀发生的,行情差的年份会集中出现。所以这个数字只用来判断量级: 是零点几个百分点,还是好几个百分点。前者说明样本泄漏对你的结论影响有限, 后者说明这份回测的绝对收益已经不能拿来做任何横向比较。 它不是一个可以直接从回测年化里减掉的修正值。
估算里的四栏输入,请一律按你自己样本的实际情况填。 页面上的初始值只是为了让公式能跑起来的演示假设, 不代表任何市场、任何时间段的实际退出率或跌幅,也不应被当成参考基准引用。
几个常见误用
把自查清单当成合格证。 十条全勾上,只说明这十类常见的口子你都堵上了,不代表样本一定干净, 更不代表策略有效。清单能覆盖的永远是已知的那些错误, 真正麻烦的往往是你数据链路里某个特有的处理方式。
先调参数,再补样本。 顺序反了。在一份泄漏的样本上做参数优化,优化出来的参数是拟合泄漏本身的, 样本补全之后这些参数基本要全部作废。样本这一关必须最先过。
用估算值去「修正」回测结果。 估出来两个百分点,就把回测年化减掉两个百分点当成真实水平, 这是把粗估当精确用。正确的用法是拿它判断「这份回测还值不值得继续讨论」, 而不是给它打个补丁接着用。
只查股票,不查基金与指数。 基金层面的幸存者偏差往往更严重,因为业绩差的产品会被清盘或转型, 从统计口径里彻底退出。只统计现存产品算出来的平均业绩, 天然是一份优等生名单。做同类比较时尤其要注意这一点。
把它和前视偏差混为一谈。 幸存者偏差问的是「样本是怎么来的」,前视偏差问的是「这条信息当时可得吗」。 两者常同时发生、方向一致地让结果偏乐观,但要分开查、分开修。
边界与本工具的假设
清单里的权重是相对的,只用于在同一份清单内部排序与分级, 不代表任何可外推的统计结论,也不对应任何市场的实测数据。 分级规则也是人为设定的:关键项另有单独的升级条款, 因为它们各自都足以单独让一份回测失去参考价值。 估算部分的四条假设与真实市场有距离,结果仅供判断量级。
风险提示:把样本修干净只是让回测这份数据可信一点,回测不等于实盘。 本工具仅为测算演示,不判断任何标的,不发出买卖信号,不构成投资建议,也不承诺任何收益。
常见问题
6 条幸存者偏差在 A 股具体长什么样?
为什么免费数据源尤其危险?
指数成分调整为什么是最隐蔽的一类?
第二块的估算是怎么算的,误差有多大?
做到什么程度才算样本干净?
幸存者偏差和前视偏差是一回事吗?
本工具仅为测算演示,不构成投资建议。计算结果受输入假设影响,实际情况请以官方规定与金融机构公布为准。