📊 量化回测框架 · 数据篇

避坑指南 · 第3讲
⚡ 数据获取 · 清洗 · 复权 · 缺失值处理

📡 1. 数据源选择 Yahoo · 东方财富 · Tushare

📈 Yahoo Finance

国际股票/ETF

yfinance 库,免费但可能被限流,需注意时区与复权。

🇨🇳 东方财富

A股/基金/指数

akshare / efinance,接口丰富,但字段命名需标准化。

🧬 Tushare

Pro版 · 积分制

结构化数据,需token,适合本地量化库,复权数据完善。

对比维度Yahoo Finance东方财富 (akshare)Tushare Pro
覆盖市场全球主要交易所A股 / 港股 / 期货A股 + 指数 + 基金
频率限制⏳ 中等 (IP限制)⏳ 较低 (频率友好)⏳ 积分制 (高级权限)
复权支持仅提供调整收盘价需自行计算/前复权参数✅ 前复权/后复权
Python库yfinanceakshare / efinancetushare
💡 建议:国内A股优先Tushare或东方财富;全球组合用Yahoo+缓存 ⚠️ 避坑:Yahoo 历史分笔可能缺失,需校验日期连续性

🧹 2. 数据清洗 & 缺失值处理

  • 去重:检查时间索引是否重复,尤其是日内数据。
  • 异常值:价格≤0、涨跌幅>50% 等,标记或剔除。
  • 缺失值:非交易日(NaT) 前向填充或插值;关键数据不可填充则丢弃。
  • 对齐索引:多标的合并时使用 outer join,注意时区统一。
🔍 常用方法
• df.ffill() / bfill()
• df.interpolate()
• df.dropna(thresh=…)
• 市场自定义:非交易日填充前值

🐍 Python 清洗示例

# 缺失值处理 · 前向填充 + 限制连续填充天数
import pandas as pd

df['close'] = df['close'].fillna(method='ffill', limit=5)
# 若开盘价缺失,用前一日收盘价填充
df['open'] = df['open'].fillna(df['close'].shift(1))

# 剔除成交量<=0 的异常行
df = df[df['volume'] > 0]

# 时间索引对齐 (多标的)
prices = pd.concat({ticker: data['close'] for ticker, data in sources.items()}, axis=1)
prices = prices.ffill().dropna(how='any')
⚠️ 避坑:复权数据中缺失值不能简单ffill,可能导致复权因子断层;建议从源重新获取。

🔄 3. 复权处理 前复权 · 后复权 · 避坑

📐 前复权 (常用)

调整历史价格,使价格连续。除权除息日价格跳空被修正,适合回测。

复权因子 = (1 + 分红/前收盘) ...

📐 后复权

保持最新价格不变,调整历史价格。适合长期趋势分析,但回测资金曲线易失真。

原始行情 除权除息数据 复权因子计算 前/后复权价格 合并 因子 调整 ⚠️ 注意复权因子顺序

📦 Tushare 复权因子示例

# 获取复权因子 (Tushare Pro)
import tushare as ts
pro = ts.pro_api('your_token')
df_adj = pro.adj_factor(ts_code='000001.SZ', start_date='20230101', end_date='20231231')
# 前复权价格 = 收盘价 * 复权因子
df['close_adj'] = df['close'] * df_adj['adj_factor']
🧨 避坑指南:① 复权因子需按日期对齐,避免未来数据;② 分红再投资需考虑税收;③ 回测使用前复权,但计算收益率时注意基准。

🧯 避坑速查表

📅 交易日历 不同市场假日不同,用 exchange_calendar 对齐。
🧩 除权除息 获取实际分红、送转股比例,避免复权因子错误。
⏱️ 时区处理 Yahoo 默认UTC,A股需转为北京时间。
📊 幸存者偏差 使用全量股票池,包含已退市标的。