4. 数据获取与清洗
在Fama-French风格因子复现中,因子构造的准确性高度依赖底层数据的质量。很多初学者把精力集中在回归和分组排序上,却忽略了数据源选择、频率对齐和异常值处理,最终导致因子收益出现难以解释的偏差。本章围绕三类核心数据——股票收益率、财务数据、市值数据——讲清楚从哪里获取、如何对齐频率、以及怎样处理异常值。
一、核心原理:三类数据的角色与匹配逻辑
Fama-French因子本质上是在“市值分组”和“账面市值比分组”的交集上计算组合收益。因此三类数据各有明确职责:
- 股票收益率:因变量,用于计算组合的持有期收益,通常来自行情数据库,频率为日度或月度。
- 市值数据:分组变量之一,决定规模因子(SMB)的划分,必须与收益率在同一时点对齐。
- 财务数据:分组变量之二,决定价值因子(HML)的划分,频率低、披露滞后,需要特别处理“前视偏差”。
关键原则是:财务数据必须使用“当时可获得”的版本。例如2023年12月31日的账面价值,若年报在2024年4月才披露,则2024年1月至3月的分组不能使用该数据,否则会引入未来信息。
二、方法流程:从获取到清洗的完整链路
下面以A股或通用流程为例,给出可复用的操作步骤。
- 确定数据源:行情与市值可用Wind、CSMAR、Tushare、Yahoo Finance、CRSP等;财务数据可用Wind、CSMAR、Compustat、巨潮资讯等。
- 统一标识与频率:将股票代码统一为同一格式,收益率和市值统一为月度频率,财务数据保留报告期与公告日两个字段。
- 处理停牌与缺失:停牌期间收益率设为缺失而非0,避免虚假零收益;缺失值根据研究设计决定剔除或插补。
- 异常值处理:对收益率进行缩尾(Winsorize)或截尾(Trim),对财务比率进行上下1%缩尾。
- 构造对齐后的面板:以“股票代码-月份”为主键,合并收益率、市值和最近可用的财务数据。
下面是一段Python示例,展示如何将日度行情聚合为月度,并与财务数据按公告日合并:
import pandas as pd
import numpy as np
# 1. 日度收益率聚合为月度
daily['month'] = daily['date'].dt.to_period('M')
monthly_ret = daily.groupby(['code', 'month'])['ret'].apply(
lambda x: (1 + x).prod() - 1
).reset_index()
# 2. 月末市值
monthly_mv = daily.sort_values('date').groupby(['code', 'month']).tail(1)[['code', 'month', 'mv']]
# 3. 财务数据按公告日对齐:取每月末最近已公告的财报
fin = fin.sort_values('announce_date')
merged = pd.merge_asof(
monthly_ret.sort_values('month'),
fin.sort_values('announce_date'),
left_on='month', right_on='announce_date',
by='code', direction='backward'
)
# 4. 异常值缩尾
merged['ret'] = merged['ret'].clip(
merged['ret'].quantile(0.01),
merged['ret'].quantile(0.99)
)
三、案例/场景:一次典型的对齐失败复盘
假设某研究者在2024年6月使用2023年年报的账面价值构造HML因子,但没有考虑年报披露时间。实际上,部分公司年报在2024年4月才发布,而该研究者从2024年1月就开始使用这些数据。结果1月至3月的分组包含了未来信息,导致HML因子在回测中表现异常优秀,但实盘无法复现。
修正方法是引入announce_date字段,并使用merge_asof按公告日向后匹配。若数据源没有公告日,可统一采用报告期后第4个月作为可用起点,这是一种保守但稳健的近似。
四、误区与复盘:异常值处理的边界
异常值处理不是越干净越好。过度缩尾会抹掉真实的极端收益,而Fama-French因子恰恰依赖横截面收益差异。建议遵循以下清单:
| 数据类型 | 常见问题 | 推荐处理 | 注意事项 |
|---|---|---|---|
| 股票收益率 | 停牌、涨跌停、缺失 | 停牌设缺失,涨跌停保留,1%缩尾 | 不要将停牌收益填0 |
| 市值数据 | 单位不一致、负值 | 统一为亿元,剔除负市值 | 确认是否含流通市值 |
| 财务数据 | 披露滞后、报告期错配 | 按公告日对齐,设置滞后缓冲 | 避免使用未来信息 |
| 账面市值比 | 极端值、负账面价值 | 负值剔除或单独处理,上下1%缩尾 | 负BE公司不参与HML分组 |
复盘时建议输出一份数据质量日志,记录每个步骤剔除的样本量和缩尾比例。例如:
数据质量日志
原始样本: 12,480 条
剔除停牌: -320 条
剔除负市值: -45 条
剔除缺失BE: -210 条
缩尾比例: 1% / 99%
最终样本: 11,905 条
总结来说,数据获取与清洗不是简单的“下载-合并”,而是需要理解每类数据的经济含义和时间属性。收益率与市值强调时点对齐,财务数据强调公告日对齐,异常值处理强调保留真实差异。只有把这三件事做扎实,后续的因子构造和回归才有可靠基础。