3. 数据源选择:常见金融数据源、数据质量评估与清洗基础
在量化回测中,数据是策略的“原材料”。数据源的选择直接决定了样本构建的可行性与回测结果的可靠性。本节将系统梳理主流金融数据源的特点、数据质量评估的核心维度以及数据清洗的基础流程,帮助你在实践中建立稳健的数据管线。
3.1 常见金融数据源对比
不同数据源在覆盖范围、更新频率、历史深度、获取成本及接口易用性上存在显著差异。下表对比了三种最常用的数据源,供你在项目选型时参考。
| 数据源 | 覆盖范围 | 更新频率 | 历史深度 | 成本 | 接口类型 | 适用场景 |
|---|---|---|---|---|---|---|
| Wind(万得) | A股、港股、美股、期货、债券、基金、宏观 | 实时/日频/分钟频 | 20年+ | 高(机构年费) | Wind API(Python/C++/Excel) | 机构级回测、高频研究、专业组合管理 |
| Tushare | A股、港股、美股、期货、基金、指数 | 日频/分钟频(积分制) | 10年+ | 低(基础免费,高级积分付费) | RESTful API(Python SDK) | 个人量化研究、策略原型验证、教学 |
| Yahoo Finance | 全球股票、ETF、指数、外汇、加密货币 | 日频/实时(延迟) | 15年+ | 免费 | yfinance(非官方Python库) | 快速原型、全球资产对比、个人学习 |
选型建议: 机构环境优先选择 Wind,数据质量与合规性有保障;个人研究推荐 Tushare,兼顾数据广度与成本;快速验证或全球资产覆盖可使用 Yahoo Finance,但需注意数据稳定性与延迟问题。
3.2 数据质量评估核心维度
数据质量是回测可信度的基石。即使数据源本身可靠,传输、存储、对齐过程中仍可能引入误差。评估数据质量时,建议从以下四个维度进行系统性检查。
- 完整性(Completeness): 检查是否存在缺失值、交易日缺失、停牌期间数据空白。例如,A股因涨跌停或停牌导致的连续缺失,需区分“正常缺失”与“异常缺失”。
- 准确性(Accuracy): 验证价格、成交量、复权因子等字段是否与官方披露一致。常见问题包括:复权计算错误、除权除息日未对齐、价格跳空异常。
- 一致性(Consistency): 跨数据源或跨时间段的同一字段是否逻辑自洽。例如,收盘价不应低于当日最低价,成交量不应为负数。
- 时效性(Timeliness): 数据更新是否及时,延迟是否在可接受范围内。对于日内回测,分钟级延迟可能导致信号执行偏差。
实践检查清单: 在构建样本前,至少执行以下三项检查:
1. 随机抽取10只股票,对比Wind与Tushare近3个月的日线数据,计算价格差异率。
2. 检查复权因子序列是否单调递增,是否存在负值或跳变。
3. 统计每个交易日的股票数量,确认是否与交易所披露的上市股票总数一致。
1. 随机抽取10只股票,对比Wind与Tushare近3个月的日线数据,计算价格差异率。
2. 检查复权因子序列是否单调递增,是否存在负值或跳变。
3. 统计每个交易日的股票数量,确认是否与交易所披露的上市股票总数一致。
3.3 数据清洗基础流程
数据清洗是将原始数据转化为可用样本的关键步骤。以下流程基于实际回测场景总结,适用于日频及以下频率的数据处理。
- 缺失值处理:
- 交易日缺失:使用
pd.date_range生成完整交易日历,进行左连接填充。 - 价格缺失:优先使用前向填充(
ffill),若连续缺失超过3个交易日,标记为异常并剔除。 - 成交量缺失:若为停牌,保留缺失;若为数据错误,使用0填充并记录日志。
- 交易日缺失:使用
- 异常值检测与修正:
- 价格异常:使用Z-score或IQR方法检测单日涨跌幅超过阈值(如A股±10%)的样本,核实是否为真实交易。
- 成交量异常:对比过去20日移动均值,若单日成交量超过均值5倍且无公告事件,标记为可疑。
- 复权处理:
- 后复权:适用于计算历史收益率,需确保复权因子序列与除权除息日严格对齐。
- 前复权:适用于回测中实时价格计算,注意复权基准日的选择(通常为最新交易日)。
- 标签对齐预处理:
- 将清洗后的价格序列与标签(如未来N日收益率)进行时间戳对齐,确保无未来信息泄露。
- 剔除标签生成时数据不足的样本(如回测最后N日无法计算未来收益率)。
# 示例:缺失值前向填充与异常标记(Python伪代码)
import pandas as pd
import numpy as np
def clean_price_series(df, price_col='close', max_ffill=3):
"""
清洗价格序列:前向填充缺失值,超过阈值则标记为NaN
"""
df = df.copy()
# 前向填充
df[price_col] = df[price_col].ffill(limit=max_ffill)
# 标记连续缺失超过阈值的行
missing_streak = df[price_col].isna().astype(int).groupby(
(df[price_col].notna()).cumsum()
).cumsum()
df['price_anomaly'] = missing_streak > max_ffill
# 异常值标记为NaN,后续剔除
df.loc[df['price_anomaly'], price_col] = np.nan
return df
常见陷阱: 清洗过程中容易引入“未来信息”。例如,使用未来数据填充缺失值(如用后一天的收盘价填充前一天的缺失),会导致回测结果虚高。务必确保所有清洗操作仅依赖历史数据。
3.4 数据源选择与清洗流程总览
下图展示了从数据源选择到清洗完成的完整决策流程,帮助你快速定位当前环节在整体管线中的位置。
3.5 数据源选择决策树
当面对多个数据源时,可依据以下决策树快速确定最优选择。该决策树综合考虑了成本、数据精度、开发效率与合规要求。
实践要点: 数据源选择不是一次性决策。随着回测策略复杂度提升(如从日频到分钟频、从单市场到跨市场),数据源可能需要动态调整。建议在数据管线中预留数据源切换接口,降低后续迁移成本。