3、数据获取与清洗:获取历史行情数据、数据清洗、数据对齐

做套利交易,最怕什么?

怕数据不准。数据不准,信号就是废的。我见过太多人,策略逻辑写得天花乱坠,结果一跑回测,发现是数据源本身就有问题。嗯,今天我们就来聊聊数据获取与清洗这档子事。

3.1 数据获取:从哪里拿数据?

我个人习惯用两个库:tushareakshare。前者是老牌金融数据接口,后者是后起之秀,覆盖面更广。

先说说 tushare。它需要 token 认证,注册后就能拿到。我建议你申请一个 pro 版权限,免费额度够用,但别太贪心,一天调个几百次就行。

import tushare as ts

# 设置 token
ts.set_token('你的token')
pro = ts.pro_api()

# 获取某只股票的历史日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20230101', end_date='20231231')
print(df.head())

再说 akshare。它更轻量,不需要 token,直接 pip install akshare 就能用。我最近做期货套利时常用它,数据更新挺及时。

import akshare as ak

# 获取期货主力连续合约数据
df = ak.futures_main_sina(symbol='RB0')
print(df.head())
小提示: 如果你做的是高频套利,建议用 akshare 的实时接口。tushare 的日线数据更适合中低频策略。

3.2 数据清洗:脏数据是魔鬼

数据拿到手,别急着用。先看看有没有坑。我在项目中遇到过好几次,回测跑得漂亮,实盘一塌糊涂,最后发现是数据里有重复行和空值。

3.2.1 去重

同一个时间戳出现两次?这很常见。尤其是从多个数据源合并时,重复数据会干扰你的信号计算。

# 去重:按时间戳去重,保留第一条
df = df.drop_duplicates(subset=['trade_date'], keep='first')

3.2.2 缺失值处理

缺失值怎么处理?我一般分三种情况:

  • 连续缺失不超过3个:用前向填充(ffill)或线性插值。
  • 连续缺失超过3个:直接删除该时间段,别硬补。
  • 开盘价/收盘价缺失:必须处理,否则信号算不出来。
# 前向填充
df['close'] = df['close'].ffill()

# 线性插值
df['close'] = df['close'].interpolate(method='linear')

# 删除缺失过多的行
df = df.dropna(subset=['close', 'open', 'high', 'low'])
注意: 我曾经犯过一个错——用均值填充缺失的收盘价。结果导致信号频繁误触发。后来我改用前向填充,效果好了很多。记住:金融数据有很强的时序依赖性,别乱用均值。

3.3 数据对齐:时间戳必须一致

套利交易的核心是价差。价差怎么算?两个品种的价格相减。但如果它们的时间戳不对齐,你算出来的价差就是错的。

举个例子:

品种A在 09:30:00 有数据,品种B在 09:30:05 才有数据。如果你直接相减,相当于用 09:30:00 的价格减去 09:30:05 的价格,这能对吗?

我建议的做法是:以较慢的那个品种为基准,做重采样对齐

import pandas as pd

# 假设 df_a 和 df_b 都有 datetime 列
# 先设置索引
df_a.set_index('datetime', inplace=True)
df_b.set_index('datetime', inplace=True)

# 重采样到1分钟级别
df_a_resampled = df_a.resample('1T').last()
df_b_resampled = df_b.resample('1T').last()

# 合并对齐
df_merged = pd.merge(df_a_resampled, df_b_resampled, 
                     left_index=True, right_index=True, 
                     suffixes=('_a', '_b'))
核心原则: 对齐后的数据,时间戳必须完全一致。差一秒都不行。你想想看,套利信号往往在毫秒级变化,时间戳错位就是灾难。

3.4 知识体系总览

下面这张图,是我自己总结的数据获取与清洗流程。你可以照着这个框架来搭建你的数据管道。

数据获取与清洗流程 数据获取 tushare / akshare 数据清洗 去重 / 缺失值处理 数据对齐 时间戳对齐 token认证 / 接口调用 drop_duplicates / ffill resample / merge 输出:干净、对齐的行情数据

3.5 实战避坑指南

最后,分享几个我踩过的坑:

  • 时间戳时区问题:tushare 返回的是北京时间,akshare 有些接口返回的是 UTC 时间。一定要统一时区,否则对齐会出错。
  • 停牌日数据:股票停牌时,tushare 会返回空值。我建议直接删除停牌日的数据,别用前一天的收盘价填充。
  • 期货换月数据:期货有主力合约切换,数据会出现跳空。我一般用复权因子处理,或者直接使用连续合约指数。
我的习惯: 每次获取数据后,先打印 df.info() 和 df.describe(),快速检查数据质量。花30秒看一眼,能省下后面几小时的调试时间。

好了,数据获取与清洗就讲到这里。记住一句话:数据质量决定策略上限。你花再多时间优化策略,都不如先把数据搞干净。


专注资料整理