因子投资-08-股票池复权财报与时间对齐

QUANT RESEARCH NOTE LESSON 08

回测最危险的错误通常不是公式,而是“在过去使用了后来才知道的信息”。今天下载的价格、财报、指数成分和公司状态往往是最终修订版本。点时研究要求在每个决策日重建:当时有哪些股票、哪些数据已经公开、哪些价格可成交。

类型核心课程
模块研究方法
阅读约 8 分钟
材料10 节 · 1 段代码

本节解决什么问题

回测最危险的错误通常不是公式,而是“在过去使用了后来才知道的信息”。今天下载的价格、财报、指数成分和公司状态往往是最终修订版本。点时研究要求在每个决策日重建:当时有哪些股票、哪些数据已经公开、哪些价格可成交。

前置知识与学习目标

需要第 01 讲收益口径和基本表格操作。学完后你应该能:

  • 设计 prices、fundamentals、universe 三张点时核心表;
  • 区分报告期、公告日、生效日和交易日;
  • 正确处理历史股票池、复权、停牌、涨跌停、ST、新股和退市;
  • 画出信号形成、下单、成交、持有和收益计量的时间轴;
  • 用断言阻止未来信息进入特征。

直觉与手算

某公司一季报报告期为 3 月 31 日,但 4 月 28 日收盘后才公告净利润。研究者今天能在数据表看到“2026-03-31 净利润”,不代表 3 月 31 日投资者已经知道它。

若公告在 4 月 28 日盘后:

  • 3 月 31 日至 4 月 28 日的信号不能使用该数字;
  • 最早可把它用于 4 月 29 日开盘后的决策;
  • 若策略只在月末调仓,可能在 4 月 30 日收盘后形成信号、5 月首个可交易时点成交;
  • 收益必须从成交之后开始计量。

把 report_period 直接与月末收益连接,相当于提前约一个月知道财报。这样的回测可以很漂亮,但现实中无法执行。

定义与公式

三张核心点时表

价格表 prices(date, asset, close, adj_factor)

定义与公式 4 行 × 3 列
字段 含义 关键约束
date 交易日期 date、asset 联合唯一
asset 永久证券标识 不依赖简称,处理代码复用
close 当日未复权收盘价 元/股,正数或有明确缺失原因
adj_factor 截至数据版本的复权因子 记录供应商、下载日和方向

研究价格可定义为 close×adj_factor,但总回报应与分红送转事件交叉核对。成交模拟仍需要未复权价格、涨跌停价和最小交易单位。

财报表 fundamentals(report_period, announce_date, asset, field, value)

定义与公式 5 行 × 3 列
字段 含义 关键约束
report_period 会计期间结束日 不能作为市场可得日
announce_date 首次公开日期时间 决策时必须已发生
asset 永久证券标识 与公司行动映射一致
field 指标名及合并/母公司口径 有数据字典
value 原始数值 保留单位、币种和修订版本

若同一报告期多次修订,严格点时库还要保存 revision_time 和版本。任意决策日 d 使用的数据必须满足:

等号能否使用取决于公告和决策的日内顺序,只有日期而无时间时应采取保守滞后。

股票池表 universe(date, asset, eligible)

eligible 是在 date 时是否满足策略可投资规则,而不是今天是否仍上市。建议同时保存 reason 列,例如上市不足、ST、停牌、涨停不可买、跌停不可卖、板块不在范围或数据不足。

一条无歧义时间轴

数据公开 → 信号形成 → 下单 → 成交 → 持有 → 收益结束

每一步都应有时间戳。月末收盘特征若包含当日收盘价,最早只能在收盘后形成;默认用同一收盘价成交就是未来函数。

Python 最小实验

下面在决策日只选择已经公告的最新财报。

PYTHON 可复现实验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pandas as pd

fundamentals = pd.DataFrame({
"asset": ["A", "A", "B", "B"],
"report_period": pd.to_datetime([
"2025-12-31", "2026-03-31", "2025-12-31", "2026-03-31",
]),
"announce_date": pd.to_datetime([
"2026-03-20", "2026-04-28", "2026-03-25", "2026-05-05",
]),
"value": [10.0, 12.0, 8.0, 11.0],
})
decision_date = pd.Timestamp("2026-04-30")

available = fundamentals.loc[
fundamentals["announce_date"] <= decision_date
].sort_values(["asset", "announce_date"])
latest = available.groupby("asset", as_index=False).tail(1)

assert (latest["announce_date"] <= decision_date).all()
assert latest.set_index("asset").loc["A", "value"] == 12.0
assert latest.set_index("asset").loc["B", "value"] == 8.0
print(latest[["asset", "report_period", "announce_date", "value"]])

B 的一季报在 5 月 5 日才公告,所以 4 月 30 日只能使用年报值 8。这个“看起来旧”的值才是当时真实信息集。

A 股实现注意事项

  1. 历史股票池。 每日重建上市、退市、板块、ST 和指数成分,不能用当前证券列表回看历史。
  2. 复权。 保存原始价、公司行动和复权因子版本。前复权序列会随未来分红改变历史数值,适合展示但不天然是点时数据。
  3. 公告日。 以首次公告时间为可得边界;报告期末、预约披露日和数据库入库日都不能互相替代。盘后公告至少滞后到下一可交易时点。
  4. 停牌。 持仓估值可按规则沿用旧价,但买卖能力为零;复牌跳跃必须进入收益。不能删除停牌期后只保留顺利成交样本。
  5. 涨跌停。 根据板块和日期应用 5%、10%、20%、30% 等不同制度。触及价格不必然无法成交,一字板、成交量和订单方向要另行判断。
  6. ST。 是否排除 ST 是投资规则,不是数据清洗。使用历史 ST 生效与解除日期,并报告排除造成的选择效应。
  7. IPO 等待期。 新股上市初期价格限制、无历史特征和高换手会造成特殊分布。等待 60、120 或 180 个交易日应在研究前规定并做敏感性。
  8. 退市收益。 退市股票不能在最后正常交易日无损消失。应纳入退市整理期、现金补偿或保守损失假设,并报告缺失处理。
  9. 代码与公司映射。 公司重组、换代码和借壳会让“证券”“上市公司”“经济实体”不是同一 ID;因子定义要选择正确主键。
  10. 财报口径。 累计利润需转换单季时注意上一版本;TTM、合并报表、币种、单位和负分母必须有数据字典。

常见错误与边界

  • 用 2026 年仍上市股票回测 2010 年,制造幸存者偏差。
  • 以 report_period 连接当期收益,提前使用财报。
  • 用今天的前复权历史价格直接当作当时可见价格。
  • 收盘信号用同一收盘价成交,没有任何延迟或滑点。
  • 把停牌价格前向填充后允许每天自由换仓。
  • 删除涨跌停、退市和负权益股票,却不报告删除规则。
  • 使用当前指数成分和行业分类回溯历史。
  • 对全样本计算去极值阈值和标准化参数。

点时数据也不能保证数据正确。供应商可能漏公告、错误映射公司行动或回填退市收益。应以样本抽查、跨源对账、事件计数和会计恒等式做独立验证。

原书与论文

原书第 5 章(PDF 文件页 192–223)集中讨论因子实践问题,第 6 章(224–290)进入中国市场实证。这里把散落的实现风险整理为可执行数据模型。

Hou、Xue 与 Zhang(2020)复现大量异象时强调微盘、样本和实现选择对结论的影响:DOI 10.1093/rfs/hhy131。McLean 与 Pontiff(2016)区分样本外与发表后衰减,也要求严格定义时间边界:DOI 10.1111/jofi.12365。

练习

  1. 画出“月末收盘计算价值信号、次日开盘成交、持有一个月”的完整时间轴。
  2. 给 fundamentals 加 revision_time,同一报告期有初始值和修订值;写查询返回决策时最新可得版本。
  3. 设计 universe 的 reason 编码,至少覆盖未上市、已退市、ST、停牌、涨停不可买、跌停不可卖和 IPO 等待期。
  4. 对一只发生分红送转的股票,用未复权价加现金流与复权价两种方法计算总回报并对账。
  5. 给出退市末端价格缺失的乐观、中性、保守三种假设,说明策略结论是否敏感。

最低验收断言应包括:键唯一、日期有序、价格为正、announce_time 早于 decision_time、收益日期晚于信号日期、每次股票池变化有原因。

小结与下一步

点时研究不是“给财报滞后几个月”这一条规则,而是完整保留当时可得的数据版本、历史股票池和交易状态。prices、fundamentals、universe 三张表加一条明确时间轴,是后续所有回测的地基。

下一讲将在这个地基上做投资组合排序:把截面信号变成高组、低组和多空因子收益。


因子投资-08-股票池复权财报与时间对齐
https://www.polarishaw.top/2026/07/17/因子投资-08-股票池复权财报与时间对齐/
作者
Polaris
发布于
2026年7月17日
许可协议