第三章:因子数据获取——数据源选择、清洗与对齐
做量化研究,有个残酷的现实:因子再好,数据不行,模型就是废纸。我见过太多人花几周挖了个漂亮因子,结果回测时发现数据源有bug,白忙一场。今天咱们聊聊数据获取这关怎么过。
3.1 数据源选择:Wind、Bloomberg、Tushare怎么选?
数据源的选择,说白了就是成本、质量、覆盖面的三角权衡。我个人习惯把数据源分成三类:
| 数据源 | 适用场景 | 成本 | 数据质量 | 我的评价 |
|---|---|---|---|---|
| Wind | 国内机构、公募私募 | 高(年费几万起) | ★★★★★ | 国内A股首选,财务数据最全 |
| Bloomberg | 全球市场、跨境策略 | 极高(年费十几万) | ★★★★★ | 全球数据标准,但贵得肉疼 |
| Tushare | 个人研究、小团队 | 免费/低 | ★★★★ | 性价比之王,但偶尔有坑 |
我的建议:如果你在机构工作,直接上Wind或Bloomberg。个人研究先用Tushare跑通逻辑,再换正式数据源。千万别在免费数据上做最终回测——我吃过这个亏。
3.2 数据清洗与预处理:脏数据是量化的大敌
数据拿到手,第一件事不是建模,是洗数据。我见过最惨的案例:有人用未清洗的数据跑回测,年化收益30%,结果发现是数据里混了未来数据。嗯,这里要注意三点:
3.2.1 缺失值处理
缺失值分两种:随机缺失和系统性缺失。随机缺失好办,填充或删除都行。系统性缺失就麻烦了——比如小市值股票经常缺失分析师覆盖数据,直接删除会导致幸存者偏差。
我个人习惯的做法:
- 时间序列缺失(比如某天停牌):用前值填充,或者用行业均值
- 截面缺失(比如某只股票没有某因子):先看缺失比例,超过30%直接剔除该因子
- 特殊处理:财务数据有滞后性,记得用最新可用数据,别用未来数据
避坑指南:我曾经在回测时发现某因子突然失效,查了两天才发现是数据源把停牌日的价格填了0,导致收益率计算全错。从那以后,我每次拿到数据都会先跑一遍缺失值检查脚本。
3.2.2 异常值检测
异常值怎么处理?我一般用MAD(中位数绝对偏差)方法,比标准差更稳健。举个例子:
import numpy as np
def detect_outliers_mad(data, threshold=3.5):
median = np.median(data)
mad = np.median(np.abs(data - median))
modified_z_scores = 0.6745 * (data - median) / mad
return np.abs(modified_z_scores) > threshold
为什么用MAD?因为金融数据经常有厚尾分布,用标准差会误杀很多正常值。你想想看,一个因子在极端行情下出现大波动,那可能是信号,不是错误。
3.2.3 数据对齐
这是最容易被忽视的环节。不同数据源、不同频率的数据,时间戳可能对不上。比如:
- 日频数据:有的用收盘价,有的用复权价
- 财务数据:季报发布时间和财报截止时间不同
- 指数数据:有的用价格指数,有的用全收益指数
我习惯的做法是:统一用自然日对齐,然后做前向填充。比如财务数据在4月30日发布,那从5月1日开始使用该数据,直到下一期发布。
警告:千万别用未来数据做对齐!比如用t+1的数据去预测t时刻的因子,这是量化研究中最常见的错误之一。我曾经在代码里发现一个bug:用当天的收盘价去计算前一天的因子值,结果回测曲线漂亮得不像真的——嗯,那当然不是真的。
3.3 数据频率与对齐问题
数据频率的选择,取决于你的策略周期。我个人经验:
| 策略类型 | 推荐频率 | 注意事项 |
|---|---|---|
| 高频策略 | 分钟级/ tick级 | 注意交易成本、滑点 |
| 中频策略 | 日频 | 注意复权方式 |
| 低频策略 | 周频/月频 | 注意财务数据滞后 |
对齐问题有个经典场景:日频因子和月频收益率的对齐。比如你有一个日频的动量因子,但你想做月度调仓。这时候需要把日频因子聚合到月频——我一般用月末最后一天的因子值,或者用月内均值。
为什么会这样?因为不同频率的数据,信息含量不同。日频数据噪声大,月频数据信号更稳定。你想想看,用日频数据做月度调仓,相当于用高频信号去预测低频收益,中间有个信息衰减的过程。
3.4 知识体系总览
下面这张图总结了本章的核心逻辑,我画了张SVG方便你理解:
这张图把数据获取的流程串起来了。从数据源选择开始,到清洗预处理,再到频率对齐,每一步都有坑。我个人习惯在项目开始前先花20%的时间做数据质量检查——这20%的时间能省掉后面80%的debug时间。
最后说一句:数据是量化研究的基石。你因子挖得再漂亮,模型建得再复杂,数据有问题一切都是白搭。我见过太多人在这上面栽跟头,包括我自己。所以,拿到数据先别急着跑模型,花点时间看看数据长什么样——你会发现很多惊喜(和惊吓)。