5. 数据获取与处理:用Python搞定期货与现货行情

做基差交易,第一步就是拿数据。没有数据,什么策略都是空中楼阁。

我个人习惯用 tushareakshare 这两个库。它们免费、稳定,而且覆盖了国内期货和现货的主要品种。今天我就带你走一遍完整的流程:从获取数据,到清洗对齐,最后算出基差序列。

5.1 数据源的选择与配置

先说说这两个库的区别。tushare 是老牌选手,数据质量高,但部分接口需要积分。akshare 是后起之秀,接口更丰富,完全免费。我一般这样搭配:

  • 期货主力连续合约:用 tushare 的 fut_daily 接口
  • 现货指数:用 akshare 的 index_daily 接口
  • 跨期价差:两个库都能拿,看哪个顺手
小提示: 我在项目中遇到过一个问题——tushare 的积分限制。如果你只是个人研究,用基础积分就够了。但如果是团队开发,建议申请 pro 版,不然每天只能调 200 次,根本不够用。

5.2 获取期货行情数据

拿螺纹钢期货举例。我们需要的不是单个合约,而是 主力连续合约。为什么?因为单个合约会到期,基差序列会断掉。

import tushare as ts
import pandas as pd

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

# 获取螺纹钢主力连续合约日线数据
df_fut = pro.fut_daily(
    ts_code='RB9999.XSGE',  # 9999 代表主力连续
    start_date='20230101',
    end_date='20231231',
    fields='trade_date, close, settle, volume, open_interest'
)

# 重命名列
df_fut.rename(columns={
    'trade_date': 'date',
    'close': 'fut_close',
    'settle': 'fut_settle'
}, inplace=True)

# 日期排序
df_fut['date'] = pd.to_datetime(df_fut['date'])
df_fut.sort_values('date', inplace=True)
df_fut.reset_index(drop=True, inplace=True)

print(df_fut.head())

嗯,这里要注意:settle 是结算价,close 是收盘价。计算基差时,我建议用 结算价。因为期货的结算价是交易所官方价格,比收盘价更稳定,不容易被尾盘操纵。

5.3 获取现货行情数据

螺纹钢的现货价格,我一般用 上海螺纹钢价格指数。akshare 可以直接拿。

import akshare as ak

# 获取螺纹钢现货价格指数
df_spot = ak.index_daily(
    symbol='sh000000',  # 上证指数示例,实际用螺纹钢现货指数代码
    start_date='20230101',
    end_date='20231231'
)

# 重命名列
df_spot.rename(columns={
    'date': 'date',
    'close': 'spot_price'
}, inplace=True)

df_spot['date'] = pd.to_datetime(df_spot['date'])
print(df_spot.head())
注意: 现货数据有时候会缺失。比如节假日,期货还在夜盘交易,但现货市场已经休息了。我曾经因为这个原因,基差序列里突然出现一个巨大的跳空,差点以为是套利机会。后来才发现是数据对齐的问题。

5.4 数据清洗与对齐

数据拿到手,第一件事就是清洗。你想想看,两个数据源的时间戳可能不一样,有的日期期货有数据但现货没有,反过来也一样。

我的标准流程是:

  1. 去重:检查是否有重复日期
  2. 填充缺失值:用前向填充法(ffill)处理短期缺失
  3. 对齐日期:只保留两者都有的交易日
# 合并期货和现货数据
df = pd.merge(df_fut, df_spot, on='date', how='inner')

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

# 前向填充(最多填充1天)
df.fillna(method='ffill', limit=1, inplace=True)

# 删除仍然缺失的行
df.dropna(inplace=True)

# 重置索引
df.reset_index(drop=True, inplace=True)

print(f"对齐后的数据量:{len(df)} 条")

这里有个坑:前向填充不能滥用。如果连续缺失超过3天,我建议直接删除。因为现货价格在长时间缺失后,用前值填充会严重失真。

5.5 计算基差序列

基差的计算公式很简单:

基差 = 现货价格 - 期货价格

但实际应用中,我习惯同时计算 基差率,方便不同品种之间比较。

# 计算基差
df['basis'] = df['spot_price'] - df['fut_settle']

# 计算基差率(百分比)
df['basis_pct'] = (df['basis'] / df['fut_settle']) * 100

# 查看结果
print(df[['date', 'spot_price', 'fut_settle', 'basis', 'basis_pct']].head())

你看,这样我们就得到了一个完整的基差序列。接下来就可以做统计分析、画图、找套利机会了。

核心要点:
  • 基差为正 → 现货溢价(backwardation)
  • 基差为负 → 期货溢价(contango)
  • 基差绝对值越大 → 套利空间越大

5.6 可视化基差序列

光看数字不够直观。我习惯把基差序列画成图,一眼就能看出趋势和异常点。

import matplotlib.pyplot as plt

plt.figure(figsize=(12, 6))
plt.plot(df['date'], df['basis'], label='基差', color='#2E86AB')
plt.axhline(y=0, color='red', linestyle='--', alpha=0.5)
plt.title('螺纹钢基差序列(2023)')
plt.xlabel('日期')
plt.ylabel('基差(元/吨)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

说实话,画图这一步很重要。我见过很多新手,算完基差就直接上策略,结果忽略了数据中的异常跳变。画个图,一眼就能发现问题。

5.7 本章知识体系

下面这张图,是我自己总结的数据处理流程。你照着做,基本不会出错。

基差数据获取与处理流程 数据源 tushare + akshare 数据获取 期货主力 + 现货指数 数据清洗 去重 + 填充缺失 数据对齐 inner join 取交集 计算基差 basis = spot - future 可视化分析 画图 + 异常检测 基差序列(可用) 数据质量决定策略质量,清洗对齐是重中之重

5.8 避坑指南

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

  • 合约换月:主力连续合约在换月时会有跳空。我一般用 复权处理,或者直接使用指数合约(如 RB8888)。
  • 夜盘数据:期货有夜盘,但现货没有。如果你用日线数据,这个问题不大。但如果是日内高频,一定要对齐时间窗口。
  • 数据源切换:不要混用不同数据源的同一品种。我试过 tushare 和 akshare 的螺纹钢数据,收盘价差了 5 块钱,基差直接偏了。
我的习惯: 每次拿到新数据,先画一张基差图,看看有没有明显的异常点。如果有,回头检查数据源。这一步花不了 5 分钟,但能省下后面调试策略的半天时间。

好了,数据获取与处理就讲到这里。你按照这个流程走一遍,基差序列就能稳稳地算出来。下一节我们聊聊如何用这个序列去识别套利机会。


公众号:蓝海资料掘金营,微信deep3321