3. 数据获取:用Python搞定期货/现货历史行情

做跨品种套利,第一步就是搞数据。没有数据,再牛的模型也是空中楼阁。

我个人习惯把数据获取分成三个层次:免费公开数据专业金融终端交易所直连。每个层次都有它的适用场景,咱们一个一个说。

3.1 免费方案:Tushare Pro

Tushare Pro 是我用得最多的免费数据源。说实话,对于个人研究和小团队来说,它基本够用了。

我记得刚开始做套利回测时,就是靠 Tushare 拿的螺纹钢和热卷的日线数据。嗯,这里要注意:Tushare 需要注册获取 token,而且不同接口的积分要求不一样。

核心要点:Tushare 的期货数据接口是 futures_daily,现货数据用 index_dailystock_daily

import tushare as ts

# 初始化(替换成你自己的token)
pro = ts.pro_api('your_token_here')

# 获取螺纹钢主力连续合约日线
df_rb = pro.futures_daily(
    ts_code='RB9999.XSGE',  # 9999代表主力连续
    start_date='20200101',
    end_date='20231231',
    fields='trade_date,open,high,low,close,vol,oi'
)

# 获取热卷主力连续合约日线
df_hc = pro.futures_daily(
    ts_code='HC9999.XSGE',
    start_date='20200101',
    end_date='20231231',
    fields='trade_date,open,high,low,close,vol,oi'
)

print(df_rb.head())

小技巧:主力连续合约(9999)会有换月跳空。我建议同时获取具体合约的数据,自己拼接,这样能控制换月逻辑。

3.2 专业方案:Wind Python API

如果你在机构做量化,Wind 基本是标配。Wind 的数据质量高,字段全,但需要付费。

我曾经在项目中同时用 Tushare 和 Wind 做数据校验,发现 Wind 的复权处理更规范,尤其是分红、拆细这些细节。

from WindPy import w

# 启动Wind
w.start()

# 获取螺纹钢指数(连续)日线
data_rb = w.wsd(
    "RB9999.SHF", 
    "close,volume,oi", 
    "2020-01-01", 
    "2023-12-31", 
    "Fill=Previous"
)

# 获取现货螺纹钢价格(上海地区)
data_spot = w.wsd(
    "S0030013",  # Wind商品现货代码
    "close",
    "2020-01-01",
    "2023-12-31"
)

print(data_rb.Data)

注意:Wind 的 Fill=Previous 参数很重要。非交易日的数据会被填充为前值,做价差计算时一定要处理这些填充数据,否则会引入偏差。

3.3 交易所直连:CFFEX / SHFE 官方API

做高频套利或者需要 tick 级数据时,就得走交易所直连了。国内期货交易所(上期所、大商所、郑商所、中金所)都提供官方 API。

说实话,这条路比较折腾。我建议除非你有低延迟需求,否则别轻易碰交易所直连。我曾经为了拿中金所的股指期货 tick 数据,折腾了整整一周的接口调试。

# 伪代码示例:上期所SHFE的API调用
# 实际使用时需要安装对应的SDK

from shfe_api import ShfeMarketData

# 初始化连接
client = ShfeMarketData(
    broker_id='your_broker',
    account='your_account',
    password='your_password'
)

# 订阅螺纹钢主力合约行情
client.subscribe('rb2401')
client.subscribe('rb2405')

# 获取历史tick数据
ticks = client.get_history_ticks(
    instrument='rb2401',
    start_date='20231201',
    end_date='20231231'
)

for tick in ticks[:5]:
    print(tick.time, tick.last_price, tick.volume)

3.4 数据清洗与对齐

数据拿到手,别急着用。不同来源的数据格式、时间戳、缺失值处理都不一样。

我个人习惯做三步清洗:

  1. 时间对齐:期货和现货的交易时间不同,需要统一到同一个时间轴
  2. 缺失值处理:非交易日、涨跌停、临时停牌都会产生缺失
  3. 异常值过滤:比如价格突变、成交量异常
import pandas as pd
import numpy as np

def clean_and_align(futures_df, spot_df):
    """
    清洗并对齐期货和现货数据
    """
    # 1. 统一日期格式
    futures_df['trade_date'] = pd.to_datetime(futures_df['trade_date'])
    spot_df['trade_date'] = pd.to_datetime(spot_df['trade_date'])
    
    # 2. 合并到同一个DataFrame
    merged = pd.merge(
        futures_df, 
        spot_df, 
        on='trade_date', 
        how='inner',  # 只保留两者都有数据的日期
        suffixes=('_fut', '_spot')
    )
    
    # 3. 处理缺失值(前向填充)
    merged = merged.fillna(method='ffill')
    
    # 4. 计算价差
    merged['spread'] = merged['close_fut'] - merged['close_spot']
    
    # 5. 过滤异常价差(3倍标准差)
    mean_spread = merged['spread'].mean()
    std_spread = merged['spread'].std()
    merged = merged[
        np.abs(merged['spread'] - mean_spread) < 3 * std_spread
    ]
    
    return merged

# 使用示例
clean_data = clean_and_align(df_rb, df_spot_rb)
print(f"清洗后数据量: {len(clean_data)} 条")

避坑指南:我曾经用 how='outer' 做合并,结果价差序列里混入了大量非交易日数据,回测结果看起来很美,实盘一跑就亏。记住:套利价差计算一定要用 inner 合并。

3.5 数据源对比与选择

数据源 成本 数据质量 实时性 适用场景
Tushare Pro 免费/低积分 中等 日线级 个人研究、回测
Wind 付费(年费) 分钟级 机构研究、策略开发
交易所API 付费(按流量) 最高 tick级 高频交易、实盘执行

说白了,选哪个数据源取决于你的预算和需求。我个人建议:先用 Tushare 做原型验证,验证通过后再上 Wind 或交易所直连。这样成本最低,效率最高。

核心总结:数据获取是套利策略的基石。Tushare 适合快速验证,Wind 适合专业研究,交易所直连适合高频执行。无论用哪个,数据清洗和对齐都是绕不开的步骤。

数据获取流程框架图 Tushare Pro Wind API 交易所直连 数据清洗与对齐 时间对齐 → 缺失值处理 → 异常值过滤 价差计算 spread = price_futures - price_spot 价差序列(用于建模)

这张图把整个数据获取流程串起来了。从三个数据源出发,经过清洗对齐,最终得到可用于建模的价差序列。每一步都有坑,但每一步也都有解法。

最后说一句:数据获取看似简单,但80%的量化项目失败都源于数据问题。多花点时间在数据质量上,后面建模会省心很多。

专注资料整理