3、价差数据获取:使用 Tushare/AkShare 获取期货行情数据、数据清洗与对齐

做跨期套利,最怕什么?

不是策略失效,而是数据打架。

你想想看,主力合约换月了,你还在用旧数据算价差,那结果能对吗?我早年就吃过这个亏,回测曲线漂亮得像艺术品,实盘一跑直接崩了。后来一查,原来是数据对齐出了问题。

所以这一章,咱们就把数据获取和清洗这件事,彻底讲透。

3.1 数据源的选择:Tushare vs AkShare

国内做期货量化,主流的数据源就两个:Tushare 和 AkShare。我个人习惯是两者搭配着用。

  • Tushare:老牌数据平台,数据质量高,但部分接口需要积分。适合做深度回测。
  • AkShare:开源免费,更新快,接口丰富。适合做实时数据监控。

说白了,Tushare 是正规军,AkShare 是游击队。正规军稳,游击队快。

我的建议:回测用 Tushare,实盘监控用 AkShare。两个都装上,不冲突。

3.2 安装与初始化

先装包,再初始化。这一步没什么难度,但容易踩坑。

# 安装 Tushare
pip install tushare

# 安装 AkShare
pip install akshare

# Tushare 需要 token,去官网注册获取
import tushare as ts
ts.set_token('你的token')
pro = ts.pro_api()

# AkShare 直接调用即可
import akshare as ak
注意:Tushare 的 token 不要硬编码在代码里。我习惯用环境变量或者配置文件读取,防止泄露。

3.3 获取期货行情数据

以螺纹钢为例,咱们获取主力连续合约的数据。

3.3.1 使用 Tushare 获取

# 获取螺纹钢主力连续合约日线数据
df_ts = pro.fut_daily(
    ts_code='RB9999.XSGE',  # 9999 表示主力连续
    start_date='20230101',
    end_date='20231231',
    fields='trade_date,open,high,low,close,vol'
)
print(df_ts.head())

这里有个坑:RB9999 是主力连续合约,但它是拼接出来的。换月的时候会有跳空。我一般会同时获取具体合约的数据,自己手动拼接,这样更可控。

3.3.2 使用 AkShare 获取

# 获取螺纹钢期货实时行情
df_ak = ak.futures_zh_minute_sina(
    symbol='RB2401',  # 具体合约代码
    period='1'        # 1分钟线
)
print(df_ak.head())

AkShare 的接口返回的是 DataFrame,字段名是中文。嗯,这里要注意,中文列名在后续处理中可能会带来麻烦,建议统一重命名。

3.4 数据清洗:别让脏数据毁了你的策略

数据拿到手,第一件事不是算价差,而是清洗。

我曾经遇到过某天的数据突然多了一个零,收盘价从 3800 变成了 38000。你想想看,如果我没清洗,直接拿去算价差,那天的信号得有多离谱。

3.4.1 缺失值处理

# 检查缺失值
print(df.isnull().sum())

# 处理方式:向前填充
df.fillna(method='ffill', inplace=True)

期货数据偶尔会有缺失,尤其是节假日前后。我个人习惯用向前填充,因为期货价格是连续的,用前一天的收盘价填充当天的开盘价,逻辑上说得通。

3.4.2 异常值检测

# 用 Z-score 检测异常值
from scipy import stats
z_scores = np.abs(stats.zscore(df['close']))
df_clean = df[(z_scores < 3)]

Z-score 大于 3 的,基本可以判定为异常。但要注意,极端行情下(比如涨停跌停),Z-score 也会很大。这时候需要结合业务逻辑判断。

核心原则:宁可丢掉一些数据,也不要让脏数据混进去。回测可以容忍少量缺失,但容忍不了错误。

3.5 数据对齐:跨期套利的关键

跨期套利,本质上是两个合约的价差交易。所以两个合约的数据必须严格对齐。

什么叫对齐?就是同一天、同一分钟的数据,必须一一对应。

3.5.1 时间对齐

# 假设我们有近月合约和远月合约的数据
df_near = pd.DataFrame({
    'date': ['2023-01-01', '2023-01-02', '2023-01-03'],
    'close_near': [3800, 3810, 3820]
})
df_far = pd.DataFrame({
    'date': ['2023-01-01', '2023-01-02', '2023-01-04'],
    'close_far': [3850, 3860, 3870]
})

# 合并对齐
df_aligned = pd.merge(df_near, df_far, on='date', how='inner')
print(df_aligned)

这里用 inner 连接,只保留两个合约都有数据的日期。为什么不用 outer?因为如果某一天只有一个合约有数据,价差算出来也是错的。

3.5.2 换月处理

主力合约会换月。比如螺纹钢,每个月都会换一次主力。换月的时候,价差会出现跳变。

我的做法是:

  1. 提前一周开始监控持仓量和成交量。
  2. 当新合约的成交量超过旧合约时,切换数据源。
  3. 切换时,用旧合约的最后一天数据作为基准,调整新合约的价格。
# 换月调整示例
# 假设旧合约最后一天收盘价 3800,新合约当天收盘价 3850
# 价差调整量 = 3850 - 3800 = 50
# 新合约所有数据减去 50,实现无缝拼接
adjustment = 50
df_new_contract['close_adjusted'] = df_new_contract['close'] - adjustment
我曾经踩过的坑:换月调整时,只调整了价格,忘了调整成交量。结果回测时发现,换月当天成交量突然暴增,策略信号全乱了。后来才意识到,成交量也需要做归一化处理。

3.6 知识体系图:数据获取与清洗全流程

下面这张图,是我自己总结的数据处理流程。每次做新策略,我都会照着这个流程走一遍。

价差数据获取与清洗流程图 数据源选择 获取行情数据 数据清洗 数据对齐 换月处理 价差计算 输出价差序列 Tushare / AkShare 缺失值、异常值 时间对齐、换月调整

3.7 实战代码:完整的数据获取与清洗流程

最后,给出一段完整的代码。你可以直接拿去用,改一下合约代码和日期就行。

import pandas as pd
import numpy as np
import tushare as ts
from scipy import stats

# 初始化
ts.set_token('你的token')
pro = ts.pro_api()

def get_and_clean_data(ts_code, start_date, end_date):
    """
    获取并清洗期货数据
    """
    # 获取数据
    df = pro.fut_daily(
        ts_code=ts_code,
        start_date=start_date,
        end_date=end_date,
        fields='trade_date,open,high,low,close,vol'
    )
    
    # 排序
    df.sort_values('trade_date', inplace=True)
    
    # 清洗缺失值
    df.fillna(method='ffill', inplace=True)
    
    # 清洗异常值
    z_scores = np.abs(stats.zscore(df['close']))
    df = df[z_scores < 3]
    
    return df

# 获取近月和远月合约数据
df_near = get_and_clean_data('RB2401.SHFE', '20230101', '20231231')
df_far = get_and_clean_data('RB2405.SHFE', '20230101', '20231231')

# 数据对齐
df_aligned = pd.merge(
    df_near[['trade_date', 'close']].rename(columns={'close': 'close_near'}),
    df_far[['trade_date', 'close']].rename(columns={'close': 'close_far'}),
    on='trade_date',
    how='inner'
)

# 计算价差
df_aligned['spread'] = df_aligned['close_far'] - df_aligned['close_near']

print(df_aligned.head())
小技巧:把这段代码封装成函数,以后每次做新策略,直接调用就行。我自己的工具库里,这类函数已经积累了上百个。

数据获取和清洗,是跨期套利的基础。基础不牢,地动山摇。别嫌麻烦,把这一步做扎实了,后面的策略开发才能事半功倍。

专注资料整理