第三节:因子数据获取——数据源与预处理实战
做因子投资,第一步就是搞数据。这步要是没做好,后面再牛的模型也是白搭。我见过太多人花大把时间调参数,结果问题出在数据上——数据没对齐、有缺失、频率不对,全白干。
今天咱们就聊聊,因子数据到底从哪来,拿到手之后怎么处理。说白了,就是让你少踩坑。
3.1 主流数据源:Wind、Tushare、JoinQuant
国内做量化,绕不开这三个数据源。我个人的习惯是:生产环境用Wind,研究阶段用Tushare或JoinQuant。为什么?往下看。
3.1.1 Wind(万得)
Wind是机构标配。数据全、质量高、更新快。但贵,一年几万块。个人用户基本用不起。
- 优点:覆盖A股、港股、期货、债券、基金,还有宏观经济数据。因子数据可以直接拉,比如PE、PB、ROE这些。
- 缺点:贵,接口是COM组件,Python调用有点麻烦。我早期用Wind的时候,经常被COM报错搞到崩溃。
- 适用场景:机构、私募、有预算的个人。
3.1.2 Tushare
Tushare是个人量化玩家的福音。免费版就能拿到不少数据,付费版也不贵。我刚开始做因子研究时,用的就是Tushare。
- 优点:免费、接口简单、文档清晰。支持股票、基金、期货、指数等。
- 缺点:免费版有调用频率限制,数据更新有延迟。因子数据需要自己算,比如你要算动量因子,得自己拿行情数据算。
- 适用场景:个人研究、小团队、学生。
# Tushare获取股票日线数据示例
import tushare as ts
# 设置token(需要注册)
ts.set_token('your_token_here')
pro = ts.pro_api()
# 获取平安银行2023年日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20230101', end_date='20231231')
print(df.head())
3.1.3 JoinQuant(聚宽)
JoinQuant是量化平台,也提供数据API。它的优势在于:数据已经做了清洗和对齐,直接拿来用就行。
- 优点:数据质量高、频率转换方便、有因子库可以直接调用。比如你想要的动量因子、价值因子,平台已经算好了。
- 缺点:本地使用需要付费,免费版只能在平台内跑策略。
- 适用场景:快速验证策略、不想自己处理数据的用户。
3.2 数据清洗与预处理
数据拿到手,第一件事不是跑模型,而是清洗。你想想看,原始数据里什么妖魔鬼怪都有:缺失值、异常值、重复数据、ST股票……不清洗直接跑,结果就是垃圾进垃圾出。
3.2.1 缺失值处理
因子数据经常有缺失。比如某只股票停牌了,那天的行情数据就是空的。处理方法有三种:
- 删除:直接删掉缺失的行。简单粗暴,但会损失信息。
- 填充:用前值、后值、均值填充。我习惯用前值填充,因为因子数据通常是缓慢变化的。
- 插值:用线性插值或时间插值。适合时间序列数据。
# 缺失值处理示例
import pandas as pd
# 假设df是因子数据,index是日期,columns是股票代码
# 前值填充
df.fillna(method='ffill', inplace=True)
# 或者删除缺失超过20%的股票
df.dropna(thresh=len(df) * 0.8, axis=1, inplace=True)
3.2.2 异常值处理
因子数据里经常有极端值。比如某只股票一天涨了100倍(新股),或者PE突然变成负数。这些异常值会严重影响因子效果。
我常用的方法是MAD(中位数绝对偏差)法:
# MAD法处理异常值
import numpy as np
def winsorize_series(s, n=5):
median = s.median()
mad = np.abs(s - median).median()
upper = median + n * mad
lower = median - n * mad
return s.clip(lower, upper)
# 对因子列做缩尾处理
df['factor'] = winsorize_series(df['factor'])
3.2.3 特殊处理:ST股、新股、停牌股
这些股票在因子投资中通常要剔除。为什么?因为它们的交易行为不正常,因子信号不可靠。
- ST股:涨跌幅限制5%,流动性差,直接剔除。
- 新股:上市前60天,波动大,因子不稳定。我一般剔除上市不满60天的股票。
- 停牌股:复牌后容易补涨补跌,因子数据有断层。建议剔除停牌超过5天的股票。
3.3 数据对齐与频率转换
因子数据来自不同数据源,频率可能不一样。比如行情数据是日频,财报数据是季频,宏观数据是月频。怎么对齐?
3.3.1 数据对齐
对齐的核心原则是:用低频率数据填充高频率数据。比如你要做日频因子,那季频的财报数据就要填充到每一天。
具体做法:
- 以日期为索引,把不同频率的数据合并到一个DataFrame里。
- 低频率数据用前值填充(ffill),保证未来数据不会泄露。
- 对齐后检查一下,有没有缺失值。
# 数据对齐示例
# 假设daily_data是日频行情,quarterly_data是季频财报
# 将季频数据填充到日频
quarterly_daily = quarterly_data.reindex(daily_data.index, method='ffill')
# 合并
merged = pd.concat([daily_data, quarterly_daily], axis=1)
3.3.2 频率转换
有时候你需要把日频数据转成周频或月频。比如做月度调仓的策略,因子数据就要用月频。
转换方法:
- 日频转周频:取每周最后一个交易日的值。
- 日频转月频:取每月最后一个交易日的值。
- 日频转季频:取每季最后一个交易日的值。
# 日频转月频示例
# 取每月最后一个交易日的数据
monthly = df.resample('M').last()
# 或者取每月均值
monthly_mean = df.resample('M').mean()
3.4 知识体系总览
下面这张图,把因子数据获取的整个流程串起来了。你可以把它当成一个检查清单,做数据的时候对照着来。
嗯,数据这块就聊到这儿。记住一句话:数据质量决定因子效果。你花80%的时间在数据处理上,一点都不夸张。我见过太多人因子选得不错,结果数据没处理好,回测和实盘差距巨大。
下一节咱们聊聊因子计算的具体方法。不过在那之前,先把数据搞干净——这是基本功,偷懒不得。