3. 因子数据获取:数据源选择、数据清洗与对齐、数据存储方案
因子研究的第一步是获取高质量、可回溯的原始数据。数据源的选择直接影响因子复现的可靠性、研究效率以及后续模型服务化的成本。本节将系统对比主流数据源,并给出数据清洗、对齐与存储的工程化方案。
3.1 数据源选择:Wind、Tushare、聚宽对比
国内量化研究常用的数据源可分为三类:商业终端(Wind)、开源社区平台(Tushare)以及在线量化平台(聚宽/JQData)。三者在数据覆盖、更新频率、获取方式与成本上存在显著差异。
| 对比维度 | Wind (WindPy) | Tushare Pro | 聚宽 (JQData) |
|---|---|---|---|
| 数据覆盖 | A股、港股、期货、期权、债券、基金、宏观、行业等全品类 | A股、指数、基金、期货、港股通、部分宏观 | A股、指数、基金、期货、行业、财务、估值 |
| 历史深度 | 1990年至今,日/分钟/ tick 级别 | 2000年至今,日/分钟级别 | 2005年至今,日/分钟级别 |
| 更新频率 | 实时行情,盘后数据通常在 17:00 前完成 | 盘后更新,通常在 18:00-20:00 | 盘后更新,通常在 17:30-19:00 |
| 获取方式 | 本地客户端 + COM/DLL/Python API (WindPy) | HTTP RESTful API (Token 鉴权) | Python SDK (JQData) / HTTP API |
| 费用 | 年费数万至数十万(机构为主) | 积分制,基础免费,高频/高级数据需付费 | 按量计费或订阅制,有免费额度 |
| 本地化部署 | 需安装 Wind 客户端,依赖 Windows 环境 | 纯云端 API,无需本地数据库 | 纯云端 API,无需本地数据库 |
| 典型场景 | 机构投研、实时风控、全品种覆盖 | 个人研究、因子回测、中小团队 | 在线策略开发、回测、模拟交易 |
选型建议: 机构环境优先使用 Wind 作为权威数据源,确保数据合规与审计要求;个人或小团队研究可选用 Tushare Pro 或聚宽 JQData,成本低且上手快。若需高频 tick 数据或深度财务明细,Wind 仍是首选。
3.2 数据清洗与对齐:因子研究的“地基工程”
原始数据通常存在缺失值、异常值、复权不一致、停牌、退市等问题。数据清洗与对齐的目标是生成一张干净、连续、可计算的“因子宽表”。
3.2.1 核心清洗步骤
- 缺失值处理: 对日频数据,前向填充(ffill)或行业均值填充;对财务数据,使用最新报告期数据。
- 异常值检测: 使用 MAD(中位数绝对偏差)或百分位截尾法(如 1%/99% 截尾)处理极端值。
- 复权处理: 统一使用后复权价格计算收益率,避免分红送股导致的收益率跳跃。
- 停牌与退市标记: 停牌期间收益率置为 NaN,退市股票在退市日之后剔除。
- 行业分类对齐: 统一使用申万一级/二级行业分类,避免不同数据源分类不一致。
3.2.2 数据对齐:时间戳与股票池
多因子模型要求所有因子在同一时间截面、同一股票池内对齐。对齐规则如下:
- 时间对齐: 交易日历统一使用上交所/深交所交易日历,剔除非交易日。
- 股票池对齐: 每日仅保留上市状态正常、非 ST、非停牌的股票。
- 频率对齐: 日频因子与日频收益率对齐;分钟因子需先聚合为日频再对齐。
对齐后的数据格式(示例): 一张宽表,行索引为日期,列索引为股票代码,值为因子值或收益率。这是后续因子检验与模型训练的标准输入。
3.3 数据存储方案:从本地文件到分布式数据库
数据存储方案需兼顾读写性能、存储成本与扩展性。根据数据规模与使用场景,推荐以下分层存储架构。
3.3.1 存储方案对比
| 存储方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Parquet 文件 | 单机研究、小团队(< 1TB) | 列存压缩、与 Pandas/Polars 无缝集成、成本低 | 不支持并发写入、无索引 |
| ClickHouse | 中大规模因子库(1TB-10TB) | 列存、高压缩比、支持 SQL 实时查询 | 运维成本较高、不适合频繁更新 |
| DolphinDB | 高频因子、时序大数据 | 内置时序引擎、窗口函数优化、分布式 | 学习曲线陡、社区较小 |
| PostgreSQL + TimescaleDB | 中小规模、需要事务支持 | 成熟生态、支持 SQL 与时间分区 | 列存性能不如专用方案 |
3.3.2 推荐实践:Parquet + 分区 + 索引
对于大多数因子研究团队,推荐使用 Parquet 格式 + 日期分区 + 股票代码排序 的存储方案。示例代码:
import pandas as pd
import pyarrow.parquet as pq
# 假设 factor_df 为清洗对齐后的宽表
# 列:date, stock_code, factor_value, return_1d
factor_df['date'] = pd.to_datetime(factor_df['date'])
# 按日期分区存储
for date_val, group_df in factor_df.groupby(factor_df['date'].dt.date):
partition_path = f"data/factors/{date_val}/factor_data.parquet"
group_df.to_parquet(
partition_path,
index=False,
compression='snappy',
row_group_size=100000
)
# 读取指定日期范围的数据
start_date = '2024-01-01'
end_date = '2024-06-30'
read_df = pd.read_parquet(
'data/factors/',
filters=[('date', '>=', start_date), ('date', '<=', end_date)]
)
print(f"Loaded {len(read_df)} rows from {start_date} to {end_date}")
避坑提示: 避免将原始数据直接存入关系型数据库(如 MySQL)进行因子计算。行存数据库在截面查询(查询某日所有股票因子值)时性能极差,且存储膨胀严重。始终优先使用列存格式或时序数据库。
3.4 数据流水线工程化
将数据获取、清洗、对齐、存储串联为自动化流水线,是因子研究可复现的基础。推荐使用 Airflow / Prefect 调度 DAG,每日自动执行:
- 数据拉取: 从 Wind/Tushare 拉取日频行情、财务数据。
- 清洗对齐: 执行缺失填充、异常处理、复权、股票池过滤。
- 因子计算: 调用因子计算模块,生成因子宽表。
- 存储写入: 将因子数据写入 Parquet 分区或 ClickHouse 表。
- 数据校验: 检查数据完整性(行数、缺失率、极值),触发告警。
关键指标: 一个典型的日频因子流水线(覆盖全A股,约5000只股票,10年历史)在单机 SSD 上可在 15-30 分钟内完成全流程。若使用 ClickHouse 或 DolphinDB,查询单日截面因子值可在毫秒级返回。