财务与公告数据:时点正确性
报告期 ≠ 公告日
Section titled “报告期 ≠ 公告日”财务数据的两个时间戳:
- 报告期(period end):数字所属的季度末;
- 公告日(announcement date):数字第一次对外可见的日期,通常滞后 1–4 个月。
在 时刻的策略只能使用公告日 的数字——以报告期对齐,等于让 2010 年的策略"提前 4 个月"看到了一季报,是教科书式的前视偏差。
追溯修正:为什么只存最新值是错的
Section titled “追溯修正:为什么只存最新值是错的”历史财务数据会被追溯修正(重述、审计调整、口径变更)。若数据库只保留每个报告期的最新值,会出现两种叠加的偏差:
- 前视:用修正后的数字代替当时市场看到的数字;
- 幸存者偏差:被重述"抹掉"的原始版本消失,历史看起来比当时更干净。
PIT 数据库的结构
Section titled “PIT 数据库的结构”Point-in-time 数据库为每个事实保留完整的版本历史:
fact(conn_id="600519", field="net_profit", period="2010Q1") ├─ v1 公告日 2010-04-25 值 = 12.6 亿 ← t ∈ [2010-04-25, 修订日) 应使用这条 ├─ v2 修订日 2010-08-20 值 = 12.4 亿 └─ v3 修订日 2011-03-30 值 = 12.7 亿 ← 只有"今天"的策略才能用取数一律用 as-of 查询:给定策略时刻 ,取公告日 的最新版本。
import pandas as pd
def as_of_value(versions: pd.DataFrame, t: pd.Timestamp) -> pd.Series: """versions: 需含 announce_date / revised_date / value 列。取 t 时刻可见的最新版本。""" visible = versions[versions["announce_date"] <= t] return visible.sort_values("announce_date").iloc[-1] if len(visible) else None不止财务数据需要 PIT
Section titled “不止财务数据需要 PIT”- 行业分类:公司的行业归属随时间变化,当前分类回溯会扭曲行业中性化;
- 指数成分:用今天的成分名单回测历史是幸存者偏差,见回测中的典型偏差;
- 股票状态:退市、ST、停牌的历史轨迹必须保留,否则低价股与退市股票被系统性剔除。
自建还是购买
Section titled “自建还是购买”商用 PIT 数据库(如 Compusta-at、Wind 点选版)昂贵;自建的最小可行方案是从公告日开始累积、永不覆盖、只追加版本。对个人研究者,A 股的公告日可从交易所公告抓取,见存储格式与查询。
量化中的用法
Section titled “量化中的用法”- 一切基本面因子以公告日对齐,复核脚本抽查 10 只股票的公告日 vs 使用日;
- 永不覆盖:每次修订追加新版本;
- 行业、成分、状态三类维表同样按 as-of 查询。
- 以公告日而非报告期对齐
- 保留每次修正的版本(as-of 时间戳),永不覆盖
- 行业分类、指数成分也需要 PIT 版本