3. 数据获取:用Python搞定期货/现货历史行情
做跨品种套利,第一步就是搞数据。没有数据,再牛的模型也是空中楼阁。
我个人习惯把数据获取分成三个层次:免费公开数据、专业金融终端、交易所直连。每个层次都有它的适用场景,咱们一个一个说。
3.1 免费方案:Tushare Pro
Tushare Pro 是我用得最多的免费数据源。说实话,对于个人研究和小团队来说,它基本够用了。
我记得刚开始做套利回测时,就是靠 Tushare 拿的螺纹钢和热卷的日线数据。嗯,这里要注意:Tushare 需要注册获取 token,而且不同接口的积分要求不一样。
核心要点:Tushare 的期货数据接口是 futures_daily,现货数据用 index_daily 或 stock_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 数据清洗与对齐
数据拿到手,别急着用。不同来源的数据格式、时间戳、缺失值处理都不一样。
我个人习惯做三步清洗:
- 时间对齐:期货和现货的交易时间不同,需要统一到同一个时间轴
- 缺失值处理:非交易日、涨跌停、临时停牌都会产生缺失
- 异常值过滤:比如价格突变、成交量异常
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 适合专业研究,交易所直连适合高频执行。无论用哪个,数据清洗和对齐都是绕不开的步骤。
这张图把整个数据获取流程串起来了。从三个数据源出发,经过清洗对齐,最终得到可用于建模的价差序列。每一步都有坑,但每一步也都有解法。
最后说一句:数据获取看似简单,但80%的量化项目失败都源于数据问题。多花点时间在数据质量上,后面建模会省心很多。