第四章:数据获取与清洗——套利策略的“地基工程”

做期货跨品种套利,我最深的体会是什么?

数据决定生死。

你策略再牛,模型再复杂,数据是脏的,结果就是垃圾进垃圾出。我见过太多人花几周写策略,却只花半小时拉数据——嗯,最后亏得不明不白。

这一章,咱们就把数据这块硬骨头啃下来。

4.1 数据源选择:Tushare vs JoinQuant

国内做期货量化,主流数据源就两个:Tushare和JoinQuant(聚宽)。

我个人习惯两个都备着,为什么?因为各有各的脾气。

对比维度 Tushare JoinQuant
数据覆盖 全品种,历史数据深 全品种,实时数据强
获取方式 HTTP API + Token 本地SDK + 在线平台
免费额度 积分制,基础够用 每日调用有限制
适合场景 离线研究、回测 实盘、策略开发
我的建议:研究阶段用Tushare拉历史数据,回测用JoinQuant验证。双保险,数据出问题能交叉核对。

4.2 数据对齐:主力合约与连续合约

跨品种套利最头疼的问题是什么?合约不统一。

螺纹钢和热卷,一个1月、5月、10月主力,另一个可能2月、6月。你直接拿两个不同月份的合约算价差?那叫关公战秦琼。

4.2.1 主力合约的“坑”

主力合约是成交量最大的那个。但问题在于——它会切换。

我曾经在回测螺纹钢和铁矿石的套利时,没处理换月,结果价差图里出现了一个巨大的“断崖”。排查了半天,原来是螺纹钢换月了,铁矿石没换。说白了,数据没对齐。

避坑指南:主力合约切换时,价差会突变。一定要做“换月调整”——要么用复权,要么用连续合约。

4.2.2 连续合约的构建逻辑

连续合约就是把不同月份的主力合约“拼接”起来。怎么拼?我常用的方法有两种:

  1. 价格复权法:在换月日,把新旧合约的价差调整掉。适合做统计套利。
  2. 持仓量加权法:按持仓量比例合成一个虚拟合约。适合做趋势跟踪。

我个人偏好复权法,因为它保留了价格的真实波动。你想想看,套利策略本质是赌价差回归,复权后的价差序列更干净。

4.3 异常值处理:那些“离谱”的数据点

数据里总有些“怪物”——比如螺纹钢突然涨停10%,或者铁矿石价格瞬间跌停。这些是真实行情吗?不一定。

我遇到过最离谱的一次:某天螺纹钢的收盘价被记录成了0.01元。查了半天,是数据源的一个bug。如果我没做异常值检测,策略就会认为“哇,价差巨大,赶紧开仓”——然后爆仓。

4.3.1 常用的检测方法

  • 3σ原则:超过均值±3倍标准差的数据,标记为异常。
  • IQR方法:四分位距法,适合非正态分布的数据。
  • 百分比截断:直接去掉前后0.5%的极端值。
核心原则:宁可漏掉一个异常,也不要误杀一个真实行情。套利策略对价差敏感,误杀会导致信号失真。

4.4 缺失值填充:别让数据“断片”

期货数据经常有缺失——节假日、夜盘中断、数据源故障。怎么办?

我常用的填充策略:

  • 前向填充:用上一个非缺失值填充。适合分钟级数据,因为价格变化连续。
  • 线性插值:用前后两个值做线性拟合。适合日线数据。
  • 不填充:直接删除缺失行。适合数据量大的情况。

嗯,这里要注意:千万别用均值填充!期货价格是非平稳的,均值填充会引入巨大偏差。我刚开始做的时候犯过这个错,回测曲线漂亮得不行,实盘一跑就崩。

4.5 实战代码:数据清洗流水线

下面是我常用的数据清洗函数,直接拿去用:

import pandas as pd
import numpy as np

def clean_futures_data(df, method='forward'):
    """
    期货数据清洗流水线
    df: DataFrame,必须包含'close'列
    method: 填充方法,'forward'或'linear'
    """
    # 1. 去除停牌日(成交量=0)
    df = df[df['volume'] > 0].copy()
    
    # 2. 异常值检测(3σ)
    mean = df['close'].mean()
    std = df['close'].std()
    df = df[(df['close'] > mean - 3*std) & 
            (df['close'] < mean + 3*std)]
    
    # 3. 缺失值填充
    if method == 'forward':
        df['close'] = df['close'].ffill()
    elif method == 'linear':
        df['close'] = df['close'].interpolate()
    
    # 4. 删除剩余NaN
    df = df.dropna()
    
    return df

# 使用示例
# raw_data = tushare.get_futures_daily('RB.SHF')
# clean_data = clean_futures_data(raw_data, method='forward')
我的习惯:清洗完数据后,一定画一张价差图看一眼。肉眼能发现很多统计方法发现不了的问题。

4.6 知识体系总览

这一章的内容,我用一张图帮你串起来:

数据获取与清洗核心流程 数据源 Tushare / JoinQuant 数据对齐 主力合约 / 连续合约 异常值处理 3σ / IQR / 截断 缺失值填充 前向 / 线性 / 删除 清洗后数据 干净、对齐、连续 ✅ 可用于套利策略的价差序列 数据清洗是套利策略的基石,每一步都不可跳过

这张图就是数据清洗的完整流水线。从数据源到最终可用的价差序列,每一步都有讲究。跳过任何一步,你的策略都可能“翻车”。

本章核心要点:
  • 数据源选Tushare+JoinQuant双保险
  • 主力合约必须做换月调整,否则价差失真
  • 异常值用3σ或IQR检测,宁可漏杀不可误杀
  • 缺失值用前向填充或线性插值,别用均值
  • 清洗完一定要可视化检查,肉眼最可靠

数据搞定了,下一步才能谈策略。别急,地基打牢了,楼才能盖得高。

蓝海数据掘金营,专注资料整理