Skip to content

第27章:数据口径与信息时间 ​

前面七章的因子看起来各不相同——价值看便宜、质量看回报、动量看涨跌、事件看公告——但落到工程上,它们做的是同一件事:在"某只股票 × 某个交易日"这个格子里填一个数。

这一章不讲新因子。它讲那张表本身:这些数字是从哪里来的,它们属于哪一天,以及你最早能在哪一天合法地使用它们。这是第六部分"因子研究方法"的第一章,也是后面三章的地基——第28章的预处理、第29章的单因子检验、第30章的伪因子识别,怀疑的对象全都是这张表。

为什么必须现在讲。第26章末尾留下了一个没有解决的问题:从数据库里查到的"历史",是经过后续修订的版本,不是当时市场看到的版本。那只是数据口径问题中的一种。你还会遇到:同一张表里既有交易日又有自然日,一只股票改过简称也改过代码,一次分红把整段历史价格重算了一遍,一个财务指标在一半公司上是空的——而这些问题没有一个会让程序崩溃,它们只会让回测变好看。

本章回答三个问题:每条数据应该贴哪一个"可用日期";应该保存"当时看到的那一版"还是"今天修订后的版本";以及同一只股票怎样在整条时间轴上保持身份和价格的连续。 本章讲的是做因子研究时脚下的地板,它对个股和 ETF 同样成立,ETF 多出来的那几类字段放在倒数第二节。

每一条数据都要贴一个"可用日期" ​

数据表上一定有一列日期。问题在于,这一列日期表示的到底是什么——是数据描述的时期,还是数据进入市场的时刻?把前者当成后者,就是最典型的一种前视偏差:拿当时还看不到的信息去做当时的决策。

自然日、工作日、交易日是三把不同的尺子 ​

现象。 你在配置里写下"财务数据滞后 90 天"。这个 90 是 90 个自然日、90 个工作日,还是 90 个交易日?答案差得很远:90 个自然日大约只相当于 60 个交易日,因为一年里只有约三分之二是开市日。

A 股的数据里同时存在三种时间单位,它们各自出现在不同的场合:

  • 自然日:日历上撕掉的页数。年报和一季报的披露截止日 4 月 30 日、半年报 8 月 31 日、三季报 10 月 31 日,都是自然日。
  • 工作日:自然日去掉周末和法定节假日,但加上调休上班的周末。那些日子你要上班,股市却不开门——所以工作日和交易日并不相等。
  • 交易日:交易所真正开市的日子。2024 年上交所全年有 242 个交易日,近年沪深两市大致在 240—245 天之间,大约是一年的三分之二。
说法用的尺子典型例子用在哪
"4 月 30 日前"自然日年报与一季报的披露截止日披露时限
"季度结束后 15 个工作日内"工作日公募基金季报的披露时限披露时限
"过去 20 个交易日"交易日动量因子的形成期、解禁前的压力窗口信号窗口与持有期

为什么要分成三栏看:因为互相换算时的误差是有方向的,而且不会被程序发现。 把"季度结束后 15 个工作日"当成 15 个自然日,你会提前一周多就用上这份数据——这正是前视偏差;反过来,把"过去 20 个交易日"实现成"过去 20 天",窗口从大约 28 个自然日缩到 20 个,动量因子捕捉的其实是另一段时间。

落到决策: 时间参数写进配置文件时必须带上单位,lag: 90 这种写法本身就是 bug 的温床。同时,交易日历必须是数据集的一部分,它每年由国务院的节假日安排和交易所的休市通知决定,不能靠"周一到周五"推算。

拿不到公告日时,用法定截止日而不是固定滞后 ​

现象。 很多数据源只给了报告期(2024-12-31),没有给你公告日。于是常见的补救办法是"往后推 3 个月"或者"推 90 天"。这个做法看起来保守,实际误差是双向的。

先说它在多数情况下离真相不远。 A 股的年报披露极为集中:2024 年度报告中有 82% 落在 4 月,其中 4 月最后一周(4 月 25—30 日)就占了 43.6%,最高的一天(4 月 29 日)单日披露了 773 家。所以"报告期 + 4 个月"对绝大多数公司都是安全上界,对相当一部分公司也不算离谱。

但它同时在两个方向上出错。

  • 对早披露的公司太保守。 2024 年度报告里有 17.8% 在 3 月就披露完毕,另有二十几家在 1—2 月就交卷。这些公司的信息,用"报告期 + 4 个月"去取,就白等了大约一到三个月。
  • 对晚披露的公司不够保守。 有 8%—9% 的公司会延后披露。更麻烦的是延期不是随机的:业绩差的公司拖得更晚。 有券商统计,2022 年报中业绩低于预期、把披露拖到 4 月最后一周的比例是 36.3%,高于业绩改善公司的 30.4%。

能不能用一个更"科学"的固定天数? 不能。公告日与报告期之间的间隔,在早披露公司和晚披露公司之间可以差三个月以上,任何单一滞后天数都只是在两个方向的误差之间选一个位置。

落到决策,按优先级排:

  1. 有公告日字段 → 直接用公告日,并顺延到下一个交易日(下一小节);
  2. 只有报告期 → 用法定截止日:年报与一季报取 4 月 30 日,半年报取 8 月 31 日,三季报取 10 月 31 日。截止日是监管强制的上界,用它你最多损失信息,不会用上未来信息;
  3. 用报告期本身 → 绝对不可以。那是数据"属于"哪段时期的标记,不是信息可以获取的时刻。

一个容易被忽略的规则细节: 一季度报告的披露时间不得早于上一年度年报的披露时间。所以 4 月底"年报和一季报一起发布"不是巧合,而是规则允许范围内的最早时点——你在一季报里看到的年度数据,和它同时在年报里出现。

边界。 法定截止日也不是万能。① 规则本身改过,用今天的截止日回看十年以前的数据,会制造出跨年份的口径断裂;② 确实有公司延期,极端情况下会被停牌——未按期披露年报或半年报的,股票自期限届满次一交易日起停牌,停牌不超过两个月,这段停牌在你的收益序列里是空洞;③ 用截止日会把好公司和差公司的信息同时推迟,抹掉的恰好是"早报喜、晚报忧"这部分真实差异。

公告日和你能用上它,中间还隔着入库日 ​

现象。 你在 4 月 30 日看到公告,但你的数据表 5 月 3 日才更新完。回测在 5 月 1 日就买进去了。

财务数据的完整链条上有三个时刻,第26章从事件因子的角度区分过它们,这里补上落地的那一段:

  • 公告时间:公司把信息发到市场上的时刻,精确到分钟;
  • 入库时间:这条记录进入你的数据库的时刻。第三方数据商通常晚于公告,你自己的抓取任务还可能因为失败重跑而再晚一步;
  • 你的取数时刻:你跑回测的那一刻。前两个是数据的属性,这一个是你自己的习惯——而它决定了你看到的是哪一版(下一节)。

把规则写成一个式子,其中 tannounce 是公告时刻、tingest 是入库时刻、N(⋅) 表示"顺延到不早于该时刻的第一个可成交时点"(若本身处在交易时段内,就是当天):

tusable=N(max(tannounce,tingest))

取两者的较晚值,是因为公告了但你还没拿到,等于没拿到。落到决策: 财务与事件记录的表结构里至少留两列——announce_time 存 tannounce,ingest_time 存 tingest——所有信号的可用日都从它们推出,不允许人工填写。

顺延这一条不能省。 盘后和节假日发布的公告要顺延到下一个交易日(第26章的规则),而这件事发生的频率比想象中高:2024 年度报告里有 22.1% 是在周末披露的,也就是每五份年报就有一份的"公告日"根本不是交易日。

保存"当时看到的那一版",而不是今天修订后的版本 ​

上一节解决的是"哪一天能用",前提是那条记录一直没变。但记录本身会变——而且是往你知道结局的方向变。这一节先看它怎么变,再看表结构需要多什么才能挡住它。

数据库里的历史会被追溯调整悄悄改写 ​

现象。 你今天从数据表里查某公司 2024 年的归母净利润,拿到一个数;但如果回到 2025 年 4 月,市场当时看到的是另一个数。

为什么会不一样。 上市公司被认定会计处理有差错时,要走追溯重述——视同差错从未发生过,把以前年度的报表重新编一遍。这类更正并不罕见:有一类统计显示,2022 年以来的会计差错更正公告涉及两百多家公司,其中约三分之一最终收到监管措施。幅度也不小——有公司被证监局现场检查后,一次性把上一年度的归母净利润调减了 84.91%;另一家公司在 2024 年 4 月的更正公告里调减了 2020 年归母净利润约 3.06 亿元,占更正前金额的 26%。

关键在于多数数据库的处理方式是"覆盖"。 更正后的值写回同一个格子,旧值不再保留。于是你今天查到的 2024 年净利润,答案里已经包含了"这家公司后来被查出问题"这一信息。用它去做 2024 年的决策,等于提前知道了两年后的检查结果。

偏差的方向尤其值得警惕。 会计差错更正整体偏向利润被调减——被纠正的是虚增,少数才是调增。也就是说,用修订后的数据做回测,你会在历史时点上"成功避开"一批后来出事的公司,而当时它们的报表看起来一切正常。修订不是随机噪声,它是带着符号的噪声。

每条记录要带两个时间戳,而不是一个 ​

上面说的是问题:修订会盖掉历史。要让它盖不掉,表结构上只需要多做一件事——别再假设"一个报告期只有一个数"。

定义。 能回答"某一天市场看到的是什么"的数据,叫 point-in-time(时点还原) 数据。它的做法不复杂:给每条记录两个时间戳,而不是一个。

  • 有效期(valid time):这个数字描述的是哪一段时期,也就是报告期。写"2024 年度"。
  • 知悉期(knowledge time):这一版数字是什么时候被公开、或是进入你的数据库的。写公告时间或入库时间。

有了两个时间戳,取数就变成一次按知悉期筛选的操作:要看 2025 年 6 月 10 日那天市场能看到什么,就在有效期等于目标报告期、且知悉期不晚于该日的所有记录里,取知悉期最晚的那一条。 这个操作在数据工程里叫 as-of 连接,是因子研究里最重要的一次连接——它的作用是把"现在知道什么"换成"当时知道什么"。

一个直观的结果是:同一个报告期会有好几条记录,它们按知悉期排队,每条只在自己被下一条取代之前"生效"。

同一个报告期有四份记录,回测在每一天只能看到覆盖那一天的那一份

读图:横轴是时间(示意),四根颜色不同的横条首尾相接,是同一个报告期(2024 年度)在数据库里留下的四条记录,每根条从它被公告的那天开始生效,到下一条记录出现为止。最左边是业绩预告,只有区间;接着是业绩快报,给了具体数字但未经审计;中间最长的一段是年报,审计口径,这一版"生效"了将近一年;最右边是次年的追溯调整公告,把年报里的数字改掉了。紫色虚线是某个回测日:它落在哪一根条上,那天能用的就是那一条——这里落在年报上。图要说明的是:修订不是覆盖,而是追加一条新版本;区别在于你的数据库有没有把旧版本保留下来。

拿不到时点还原数据时,至少要承认偏差的方向 ​

先说现实。 真正的 point-in-time 数据需要数据商专门维护,历史覆盖通常比普通数据短,价格更高;很多公开数据源根本不提供。所以在没有它的时候,你要做的是退守,而不是假装问题不存在。

三条退守办法,按可信度从高到低:

  1. 换指标。 最容易出问题的是那些一旦出错就要大改的科目——收入确认、成本归集、减值计提、商誉。做长期回测时优先选择变动小、口径稳定的指标,等于绕开了修订最密集的区域;
  2. 把修订本身变成信号,而不是负担。 更正公告的知悉日是明确的、当时可见的,所以"这家公司在某个时点发布了会计差错更正"可以当作事件使用(第26章)——它比"用修订后的历史数字做因子"要诚实得多;
  3. 用修订值,但承认方向。 如果你只有覆盖型数据,就在结论里写清:由于用的是修订后数据,含风险公司的历史表现在回测中被系统性低估,因此因子在财务风险维度上的有效性会被高估。这句话不解决偏差,但它让读者知道自己看的是哪个版本的世界。

边界:修订后的值也不是"正确值"。 它只是又一个版本,只不过你误以为它是终点。真正的差别不在"哪个数对",而在"哪一天能看到哪一个数"。

让同一只股票在整条时间轴上保持连续 ​

时间对齐解决的是"哪一天能用",版本对齐解决的是"用哪一版"。还有第三个问题:表里的这一行,从头到尾真的都是同一只股票吗?

股票简称会变,证券代码也可能变 ​

现象。 你按股票简称匹配历史数据,某公司被实施风险警示以后简称前面多了"ST",然后你的价格序列在那一天断掉了;再过一年它更名了,序列又断一次。

  • 简称是不稳定的。 风险警示加"ST"或"*ST"、公司更名、进入退市整理期时加"退"字,都会改简称。按简称做匹配键,等于在时间轴上给自己埋雷。
  • 代码也不是永远不变。 重组后变更代码的公司并不少见。

落到决策: 用证券代码 + 交易所做当日标识,另外维护一张"代码—名称—生效区间"的映射表,而不是一张"当前代码—当前名称"的快照表——后者会把今天的名称套到十年前。如果还要做跨期的公司级连接(比如同一家公司先在 A 股上市、后来发行 H 股),就需要数据商提供的永久证券标识,也就是一个不随代码变更而改变的 ID,因为代码和名称都不承担这个职责。

退市不是一天,而是一段流程 ​

现象。 一只股票从决定退市到彻底离开你的视野,中间要走好几个阶段,每一阶段的交易规则和代码都不同。

  • 退市整理期:交易所作出终止上市决定后,股票通常先进入为期 15 个交易日的整理期,名称带"退"字标识,仍在原来那个交易所交易;
  • 摘牌:整理期结束,股票终止上市、摘牌;
  • 转入退市板块:摘牌后转入全国股转系统管理的"两网公司及退市公司板块"挂牌转让,通常在摘牌后 45 个转让日内开始。代码换成 400 开头——某公司退市前是 002618,退市后是 400133;另一家退市前是 002750,退市后是 400270。那里每周只转让 1 次、3 次或 5 次(按公司财务与披露情况区分),涨跌幅 5%,还需要另行办理确权并开通权限。

对数据的影响有两层。 第一层,同一家公司在时间轴上先后有两个完全不同的代码,按代码连接会把它的结局丢掉;第二层,退市板块的行情大多数免费数据源根本没有采集,所以数据表里这条序列是突然结束的。

处理方式: 在退市日给序列一个明确的终止标记和终止原因(退市、被合并、主动摘牌),并在回测里把退市之前那段真实成交的价格当作可实现的退出价。这是幸存者偏差最喜欢藏身的地方(第18章、第30章):如果样本里只剩今天还在交易的公司,那些一路跌到退市的公司就凭空消失了,而它们恰恰是亏损的主要来源。

另一个同类问题在序列的开头。 上市首日没有前收盘价,那一天的涨跌幅基准是发行价而不是上一交易日的收盘价;上市初期的次新股,波动率和换手率都显著高于常态。所以股票池的过滤规则里通常有一条"上市满若干个月"(第32章)——它是为了去掉一段和后面不可比的数据,不是在判断公司好坏。

前复权价格会变,后复权价格不会 ​

现象。 你今天拉出一只股票 2020—2024 年的前复权价格,和半年前拉出来的同一段,数字不一样。而用后复权拉,两次完全一致。

两种复权各自锚在哪里(第3章已给出除权参考价的算法,这里只关心序列的稳定性)。 先说清要用到的那个工具:把每一次除权换算成一个乘数,叫复权因子;从上市到现在把所有的乘到一起,叫累计复权因子。

  • 前复权以最新价格为基准,向前调整历史价格,使最新价等于实际成交价;
  • 后复权以上市首日的价格为基准,向后调整。

两者的关系很干净。记 PtF 为前复权价、PtB 为后复权价:

PtB=c⋅PtF

其中 c 是一个与日期 t 无关、但与你取数那天有关的常数(等于取数日所对应的累计复权因子)。这个式子说明两件事:第一,两者的收益率序列完全相同,因为常数 c 在相除时被约掉——所以复盘历史涨跌用哪一种都行;第二,价格水平不同,而且 c 随取数日变化——所以前复权序列不是时点稳定的。

前复权价格会随之后的每一次除权重算,后复权不会

读图:两幅图画的都是同一段 2020—2024 年的历史价格(示意),区别在于分段取数。左图是前复权:以最新价为基准,只要之后又发生一次分红或送转,最新价一变,整段历史都要重算,所以 2024 年取和 2025 年取得到两条不同的线。右图是后复权:以上市首日为基准,已经发生过的历史不再变动,两次取数得到的线完全重合。图要说明的是:前复权的基准在未来,后复权的基准在过去;只有后者是"当时看到的那个数字"。

这会带来什么实际错误。 单纯算收益率不会出错。出问题的是把价格水平本身当输入的场合:

  • 用"股价低于 10 元"筛选股票、用绝对价格做分组、把股价和某个金额直接比较——这些做法在前复权序列上,读到的价格里已经含了未来的除权信息;
  • 更隐蔽的一种:不同时点取出的两条前复权序列不能互相比较。你三个月前算好的因子值和今天重算的因子值,价格基准不同,混在一起就是两种尺度。

落到决策: 存储原始成交价和复权因子,需要价格水平时用后复权价现算,只在向人展示时用前复权。把复权因子单独存下来,是这一节唯一必须记住的动作——它让"当时看到的价格"永远可以重建。

缺失、异常和重复不能按同一套规则清洗 ​

上两节管的是"对不对齐",这一节管的是"格子里那个数本身"。这三种问题看起来都像"数据不干净",但成因完全不同——用一句"把空值填 0、把极端值去掉、把重复行删掉"统一处理,是比问题本身更常见的错误来源。

缺失值要先分清是哪一种缺失 ​

现象。 一家净资产为负的公司,PB 算不出来。你的清洗脚本把这一格填成 0,于是它在排序里成了全市场"最便宜的价值股",被送进组合。

同一列里的空值,至少有三种完全不同的含义:

  • 不适用:这个概念在这家公司身上不成立。净资产为负的公司没有有意义的 BP,亏损公司的 PE 是无意义的比值。它需要的不是填补,而是被排除在这个因子的分母之外。
  • 未披露:数据存在,这家公司没说。比如没有业绩预告的季度、未单独列示的科目。缺失本身可能就是信息(第26章:不发预告可能是业绩平稳,也可能是该发不发),所以不能一律当噪声丢掉。
  • 抓取失败或口径不匹配:两边都没错,但字段没对上,例如同一指标一个取的是母公司口径、另一个取的是合并口径。

处理顺序是:先判断属于哪一种,再决定排除、填值、还是保留成一个显式的"缺失标记"。 第二类和第三类的区别尤其重要——前者代表公司的选择,后者代表你的工程问题,而这两种缺失在数值上一模一样。

异常值先判断是错误,还是事实 ​

现象。 某只股票某天的收益是 0,它可能是停牌,也可能只是不涨不跌;某只股票的换手率突然变成平时的 20 倍,可能是流通股本刚变过,也可能是真的一天换了手;某家公司的净利率是行业平均的十倍,可能是一次性资产处置,也可能是数据错了。它们在数值上都是"极端值",但性质完全不同。

现象是错误还是事实该怎么处理
停牌日的收益事件本身没有价格,收益是未定义的显式标记为停牌,不要填 0;填 0 会系统性低估波动率(第25章)
一字涨停、跌停事实保留。它真实地表示"这个价格买不到",是该被约束的(第3章、第24章)
换手率、Amihud 突然爆表多数是构造问题分母(流通股本、成交额)过小造成的,应在指标构造层面处理,而不是删掉极端点
财务比率出现几倍于同业的数值需要先解释先查是口径不同、分母为负,还是真的一次性损益(第9章),解释不了再当异常

一条原则:先能解释,再决定动不动。 一个说不清来源的极端值,删掉它只是把问题藏起来——而它很可能正是你要找的那家公司。真正的极值处理(把极端值压到某个分位数上、再做标准化)属于预处理,放在第28章。

重复记录通常来自"同一件事的多个版本" ​

现象。 某只股票在某一天出现了两行记录。你以为只是导入重复了,删掉一行之后却发现,两行的数字并不一样。

重复数据有三种常见来源:同一个报告期的多条记录(初始值、快报、更正值);同一只股票同一天的多条行情(不同数据源或不同市场);同一张表被重复导入两次。

判断的唯一依据是主键。 财务数据的主键是"证券 + 报告期 + 知悉期",行情数据的主键是"证券 + 交易日 + 来源"。主键里少了知悉期,重复数据就没法区分,你只能在"去重后丢掉真实的历史版本"和"不去重导致同一天出现两行"之间选一个——而这两件事都会让回测出错,只是错法不同。

ETF 的数据多一层"产品自己" ​

个股和 ETF 的数据表结构不同,这不是细节,而是会直接改变结论的差别。

少了一整类字段。 ETF 没有公司公告、没有业绩预告、没有增持减持,也没有通常意义上的三张报表(第2章、第26章)。所以价值、质量、成长这些公司特征因子不能直接算在 ETF 上,必须穿透到成分股、按权重合成,再单独评价基金工具本身。

多了几类必须区分开的序列:

  • 净值与交易价格是两条序列,还有第三条盘中参考净值(IOPV)。净值是基金按持仓算出来的,价格是二级市场成交出来的,两者的差就是折溢价(第18章)。用哪一条算收益,会直接影响夏普比率和跟踪误差;
  • 份额与规模:份额变动带来申赎现金流,和价格涨跌无关。把份额增长当成"资金看好"之前,先分清是申购还是净值上涨;
  • 分红与复权:ETF 分红同样要复权,而且基金净值序列与指数序列的复权口径必须一致,否则跟踪误差会被算出一个不存在的水位;
  • 成分与持仓的时间差:指数成分名单的公告日和生效日之间有一段提前量(第18章),ETF 的实际持仓还要考虑复制方式和现金留存。

最常见的三个口径错误: 用季末的成分名单回测当季(名单在季末还没公布,第18章);用不复权净值计算长期收益(漏掉分红);把上市不满一年的 ETF 放进长期比较(样本期短,首日基数还异常)。

放回研究流程:把这份清单放在因子检验之前 ​

上面几节是分开讲的,但真正麻烦的地方在于:这些问题会互相掩盖。用了报告期当可用日,和用了修订后的数据,症状是一样的——回测都变得更好看。

所以把它落成一张过一遍就能用的表,位置在因子检验之前,而不是发现问题之后:

检查项要问的问题出错时的典型症状
时间单位这个滞后量是自然日、工作日还是交易日?持有期比设定长或短;"15 个工作日"被当成 15 天
可用日用的是报告期、公告日还是入库日?1 月就用上了年报数据;回测收益好得离谱
顺延盘后和周末的公告顺延到下一个交易日了吗?用公告日当天的收盘价买入了盘后发布的公告
版本这条数字是初值,还是被追溯调整后的值?因子在历史上"恰好"避开了后来出事的公司
身份用代码还是名称匹配?改过名、改过码吗?一只股票的历史序列在戴上 ST 帽子那天断掉
退市退市和摘牌的样本还在表里吗?回测收益异常地好,因为亏损的公司已经不在样本里了
价格口径用原始价、前复权还是后复权?用前复权价做价格阈值筛选,结果随取数时间改变
缺失空值是"不适用"、"没披露"还是"没抓到"?填 0 之后,负净资产公司变成了"最便宜的价值股"

这张表的价值在于它检查的都是"不报错的错"。 一个会崩溃的 bug 是好事,你当天就会修;一个把夏普比率从 0.5 悄悄改成 1.5 的 bug 才是灾难,因为它给你的是"我想看到的结果"(第30章)。在因子研究里,让回测变好看的改动永远需要多一层怀疑。

本章小结 ​

  • 本章不讲新因子,讲的是所有因子共用的那张表:数字属于哪一天、用的是哪一版、这一行是不是同一只股票。
  • 时间有三把尺子——自然日、工作日、交易日——参数必须带单位,交易日历必须是数据集的一部分。财报数据的可用日不是报告期:有公告日用公告日并顺延到下一交易日;没有就用法定截止日(年报与一季报 4 月 30 日、半年报 8 月 31 日、三季报 10 月 31 日),而不是"报告期 + 固定天数"——后者的误差是双向的,而且业绩差的公司拖得更晚。
  • 可用日取公告时间和入库时间的较晚值。这不是小事:2024 年度报告有 22.1% 在周末披露。
  • 修订不是覆盖,而是追加一条新版本。point-in-time 数据给每条记录两个时间戳:有效期(报告期)和知悉期(公告或入库);取数时按知悉期取最晚的那一条(as-of 连接)。
  • 会计差错更正并不罕见,幅度可以很大(有公司一次性把上一年归母净利润调减 84.91%),而且方向整体偏向调减利润。用覆盖型数据回测会系统性高估财务风险类因子的有效性——至少要在结论里承认这个方向。
  • 股票简称会因 ST、更名、退市整理而改变,代码也可能变,退市后更是换成 400 开头的新代码。用代码加交易所做当日标识,给退市序列一个明确的终止标记——这是幸存者偏差最容易藏身的地方。
  • 前复权以最新价为基准,会随之后的每一次除权重算;后复权以上市首日为基准,历史值不再变动。两者只差一个常数,收益率相同,但价格水平不同且随取数日变化——所以要存原始价和复权因子,只在展示时用前复权。
  • 缺失值分"不适用""未披露""抓取失败或口径不匹配"三种,异常值要先判断是错误还是事实,重复记录靠主键区分且主键里必须包含知悉期——这三类不能用同一套规则清洗。
  • ETF 的数据少了公司公告,多了净值、价格、IOPV、份额和成分名单几类必须分开的序列,还要注意成分公告日与生效日的时间差、分红复权口径,以及上市时间过短带来的样本问题。
  • 所有这些问题有一个共同点:它们不会让程序崩溃,只会让回测更好看。 所以这份检查要放在因子检验之前。

下一章回到这张表上做加工:极值怎么处理、标准化用哪种、排名和分位数各适合什么场合、行业与市值中性化之后因子还表不表达原来的逻辑。数据本身干净了,才有资格谈"因子的含义有没有被预处理改掉"。