3. 数据获取与预处理:从原始数据到可交易信号

做统计套利,有一句老话我特别认同:「垃圾进,垃圾出」。模型再漂亮,数据不对,结果就是一场空。今天咱们就聊聊数据获取与预处理这第一步。我个人习惯把这步叫做「炼油」——原油不能直接烧,数据也一样。

核心观点:统计套利的成败,80%取决于数据质量。别急着跑模型,先把数据伺候好。

3.1 数据源选择:你的「原油」从哪来?

做跨市场套利,数据源的选择直接决定了你的研究边界。我常用的三个数据源,各有各的脾气。

3.1.1 Yahoo Finance

免费、易用、覆盖全球。适合快速验证想法。但有个坑——数据质量不稳定。我曾经在回测中发现一个套利信号特别漂亮,后来发现是Yahoo的某只ETF价格数据有两天没更新。嗯,从那以后我养成了交叉验证的习惯。

  • 优点:免费、API简单、覆盖美股/港股/ETF
  • 缺点:数据可能延迟、历史数据有时被调整过
  • 适用场景:快速原型、个人研究、非高频策略

3.1.2 Wind(万得)

国内机构的首选。数据全、质量高、更新快。但价格不便宜。我记得第一次用Wind时,被它的数据字典吓到了——光股票字段就有上千个。不过做跨市场套利,Wind的A股+港股+期货数据整合做得确实好。

  • 优点:数据权威、字段丰富、支持多种资产
  • 缺点:收费、API相对复杂、需要本地安装
  • 适用场景:机构研究、实盘策略、需要高频数据

3.1.3 Tushare

国内开源数据平台,这几年发展很快。免费版够用,Pro版更稳定。我比较喜欢它的积分制度——你贡献数据,就能换积分。社区氛围不错。

  • 优点:免费/低价、社区活跃、支持Python直接调用
  • 缺点:数据稳定性不如Wind、部分字段需要积分
  • 适用场景:个人研究、中小团队、快速开发
数据源 费用 数据质量 覆盖范围 推荐指数
Yahoo Finance 免费 ★★★ 全球 ★★★
Wind 收费 ★★★★★ 中国为主 ★★★★★
Tushare 免费/低价 ★★★★ 中国为主 ★★★★

我的建议:如果你刚开始做统计套利研究,先用Tushare或Yahoo Finance跑通流程。等策略稳定了,再考虑上Wind。别一上来就花大钱买数据——你都不知道自己的策略能不能赚钱呢。

3.2 数据清洗:把「脏数据」洗干净

数据拿到手,第一件事不是看价格,而是看有没有「脏东西」。我见过太多人直接拿原始数据跑模型,结果回测曲线漂亮得像假的一样——其实它就是假的。

3.2.1 缺失值处理

缺失值在金融数据里太常见了。停牌、节假日、数据源故障……原因很多。怎么处理?

  • 向前填充(ffill):用上一个非缺失值填充。适合价格数据——停牌后复牌,价格通常延续。
  • 向后填充(bfill):用下一个非缺失值填充。适合某些指标数据。
  • 插值法:线性插值、多项式插值。适合成交量等连续变化的数据。
  • 直接删除:如果缺失比例超过5%,我建议直接删掉那段时间的数据。别心疼。
# 缺失值处理示例
import pandas as pd

# 向前填充(价格数据)
df['close'].fillna(method='ffill', inplace=True)

# 线性插值(成交量)
df['volume'].interpolate(method='linear', inplace=True)

# 删除缺失超过5%的列
threshold = len(df) * 0.05
df.dropna(thresh=threshold, axis=1, inplace=True)

注意:千万别用均值填充金融数据!你想想看,股票价格用均值填充,那还叫股票吗?我见过有人这么干,结果回测出来的夏普比率高达5.0——一看就是假的。

3.2.2 异常值处理

异常值比缺失值更隐蔽。一个极端价格可能让你的协整关系完全变形。怎么发现异常值?

  • 3σ原则:超过均值±3倍标准差的数据,标记为异常。
  • IQR方法:四分位距法。超过Q1-1.5*IQR或Q3+1.5*IQR的数据,视为异常。
  • 百分比截尾:直接去掉前后1%的数据。简单粗暴,但有效。
# 异常值检测示例
import numpy as np

# 3σ原则
mean = df['close'].mean()
std = df['close'].std()
df['is_outlier'] = np.abs(df['close'] - mean) > 3 * std

# IQR方法
Q1 = df['close'].quantile(0.25)
Q3 = df['close'].quantile(0.75)
IQR = Q3 - Q1
df['is_outlier_iqr'] = (df['close'] < Q1 - 1.5*IQR) | (df['close'] > Q3 + 1.5*IQR)

避坑指南:我曾经在分析沪深300与中证500的套利机会时,发现一个异常大的价差。后来查了一下,原来是某一天的数据源把沪深300的收盘价多打了一个零。嗯,从那以后我每次拿到数据都会先画个价格曲线看一眼——肉眼检查永远是最快的。

3.3 数据对齐:让不同市场「同步」

跨市场套利最头疼的问题之一:时间不同步。美股和A股交易时间不一样,期货和股票也不一样。你想想看,如果拿A股下午3点的价格去对比美股下午4点的价格,那还叫套利吗?

3.3.1 时间戳对齐

核心原则:用同一个时间基准。我通常的做法是:

  • 把所有数据统一到UTC时间
  • 按分钟或小时对齐
  • 只保留所有市场都交易的时间段
# 时间戳对齐示例
# 假设df_us是美股数据,df_cn是A股数据

# 统一到UTC时间
df_us.index = df_us.index.tz_convert('UTC')
df_cn.index = df_cn.index.tz_convert('UTC')

# 按小时对齐
df_us_hourly = df_us.resample('1H').last()
df_cn_hourly = df_cn.resample('1H').last()

# 只保留共同交易时间
common_index = df_us_hourly.index.intersection(df_cn_hourly.index)
df_aligned = pd.DataFrame({
    'us_close': df_us_hourly.loc[common_index, 'close'],
    'cn_close': df_cn_hourly.loc[common_index, 'close']
})

3.3.2 频率统一

不同数据源的频率可能不一样。Yahoo Finance默认是日线,Wind可以拿到分钟线。怎么统一?

  • 降采样:高频转低频。比如分钟线转日线,用最后价格或平均价格。
  • 升采样:低频转高频。比如日线转小时线,需要插值。但说实话,我不太推荐升采样——你是在「创造」数据。

我的原则:能降采样就别升采样。宁可损失一些信息,也别引入虚假信息。

3.4 数据存储:把「炼好的油」存好

数据清洗对齐完了,得存起来。别每次都重新下载——浪费时间不说,数据源还可能变。我常用的两种存储方式:

3.4.1 CSV格式

简单、通用、人类可读。适合小规模数据(几万行以内)。但有个问题:没有数据类型信息。每次读取都要重新指定dtype,挺烦的。

# 存储为CSV
df_aligned.to_csv('pair_data.csv', index=True)

# 读取时指定数据类型
dtype_dict = {'us_close': 'float64', 'cn_close': 'float64'}
df = pd.read_csv('pair_data.csv', dtype=dtype_dict, parse_dates=['timestamp'])

3.4.2 HDF5格式

这才是做量化研究的「正经」存储方式。HDF5支持:

  • 压缩存储:同样数据,体积只有CSV的1/5
  • 快速读取:按需读取,不用全部加载到内存
  • 支持多种数据类型:时间戳、分类数据、缺失值都能完美保存
# 存储为HDF5
df_aligned.to_hdf('pair_data.h5', key='pair_data', mode='w', complevel=9)

# 读取HDF5
df = pd.read_hdf('pair_data.h5', key='pair_data')

# 按需读取(只读部分列)
df_partial = pd.read_hdf('pair_data.h5', key='pair_data', columns=['us_close'])

我的习惯:研究阶段用CSV,方便查看和调试。进入实盘或回测阶段,全部转成HDF5。速度快、省空间。而且HDF5支持追加数据——每天收盘后跑个脚本,把新数据追加进去,非常方便。

3.5 本章知识体系

说了这么多,咱们用一张图把整个流程串起来。数据获取与预处理,说白了就是一条流水线:

数据获取与预处理流程 数据源选择 数据清洗 数据对齐 数据存储 回测 / 实盘 反馈优化 Yahoo / Wind / Tushare 缺失值 / 异常值 时间戳 / 频率 CSV / HDF5 策略验证 发现问题 → 回到数据源优化

你看,整个流程是个闭环。数据源选好了,清洗干净了,对齐了,存好了,才能放心地拿去跑模型。而且别忘了——反馈优化。回测中发现异常,别急着改策略,先回去看看数据是不是有问题。

最后说一句:数据预处理没有「完美」这回事。你只能做到「足够好」。什么是足够好?就是你的数据不会成为策略的瓶颈。做到这一点,你就可以放心地进入下一阶段了。

专注资料整理