4. 数据获取与清洗

在Fama-French风格因子复现中,因子构造的准确性高度依赖底层数据的质量。很多初学者把精力集中在回归和分组排序上,却忽略了数据源选择、频率对齐和异常值处理,最终导致因子收益出现难以解释的偏差。本章围绕三类核心数据——股票收益率、财务数据、市值数据——讲清楚从哪里获取、如何对齐频率、以及怎样处理异常值。

一、核心原理:三类数据的角色与匹配逻辑

Fama-French因子本质上是在“市值分组”和“账面市值比分组”的交集上计算组合收益。因此三类数据各有明确职责:

  • 股票收益率:因变量,用于计算组合的持有期收益,通常来自行情数据库,频率为日度或月度。
  • 市值数据:分组变量之一,决定规模因子(SMB)的划分,必须与收益率在同一时点对齐。
  • 财务数据:分组变量之二,决定价值因子(HML)的划分,频率低、披露滞后,需要特别处理“前视偏差”。

关键原则是:财务数据必须使用“当时可获得”的版本。例如2023年12月31日的账面价值,若年报在2024年4月才披露,则2024年1月至3月的分组不能使用该数据,否则会引入未来信息。

核心对齐规则:收益率与市值按同一交易时点对齐;财务数据按“公告日”而非“报告期”对齐,并设置合理的披露滞后缓冲(通常3~6个月)。

二、方法流程:从获取到清洗的完整链路

下面以A股或通用流程为例,给出可复用的操作步骤。

  1. 确定数据源:行情与市值可用Wind、CSMAR、Tushare、Yahoo Finance、CRSP等;财务数据可用Wind、CSMAR、Compustat、巨潮资讯等。
  2. 统一标识与频率:将股票代码统一为同一格式,收益率和市值统一为月度频率,财务数据保留报告期与公告日两个字段。
  3. 处理停牌与缺失:停牌期间收益率设为缺失而非0,避免虚假零收益;缺失值根据研究设计决定剔除或插补。
  4. 异常值处理:对收益率进行缩尾(Winsorize)或截尾(Trim),对财务比率进行上下1%缩尾。
  5. 构造对齐后的面板:以“股票代码-月份”为主键,合并收益率、市值和最近可用的财务数据。

下面是一段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 条
实践建议:在因子复现项目中,把数据清洗脚本独立成模块,每次运行都输出上述日志。这样当因子收益出现异常时,可以快速定位是数据源问题还是分组逻辑问题。

总结来说,数据获取与清洗不是简单的“下载-合并”,而是需要理解每类数据的经济含义和时间属性。收益率与市值强调时点对齐,财务数据强调公告日对齐,异常值处理强调保留真实差异。只有把这三件事做扎实,后续的因子构造和回归才有可靠基础。