数据篇:期货数据获取与预处理

做量化交易,数据就是你的弹药库。没有数据,再好的策略也是空中楼阁。这一章,我带你搞定期货数据的获取、清洗和存储。这些都是我这些年踩坑踩出来的经验,希望能帮你少走弯路。

一、数据获取:三大主流工具

期货数据从哪里来?市面上工具很多,但我个人最常用的就三个:Tushare、AKShare 和 Wind。它们各有千秋,我分别说说。

1. Tushare:老牌稳定,适合历史研究

Tushare 是我最早接触的金融数据接口。它数据质量高,覆盖全面,但需要注册获取 token。说实话,它的文档写得有点绕,但用熟了就好。

import tushare as ts

# 设置 token(需要去官网注册)
ts.set_token('你的token')
pro = ts.pro_api()

# 获取期货日线数据
df = pro.fut_daily(
    ts_code='RB2401.SHF',  # 螺纹钢主力合约
    start_date='20230101',
    end_date='20231231',
    fields='ts_code,trade_date,open,high,low,close,vol,amount'
)
print(df.head())
个人经验:Tushare 的免费额度有限,一天只能调 200 次。我建议你先把数据批量拉下来存本地,别每次都实时调。

2. AKShare:开源免费,实时数据强

AKShare 是后来崛起的开源库,完全免费。它的实时数据接口特别多,适合做日内策略。不过,它的数据源来自各大财经网站,偶尔会有缺失或延迟。

import akshare as ak

# 获取期货实时行情
futures_zh_min = ak.futures_zh_minute_sina(
    symbol='RB2401', 
    period='1'  # 1分钟线
)
print(futures_zh_min.tail())
注意:AKShare 的接口经常因为网站改版而失效。我曾经在实盘前一天发现接口挂了,差点翻车。建议你准备一个备用数据源。

3. Wind:机构首选,但贵

Wind 是机构标配,数据最全最准。但一年几万块的费用,个人用户基本用不起。如果你在机构工作,直接用 Wind 就好,省心。

from WindPy import w

w.start()

# 获取期货数据
data = w.wsd(
    "RB2401.SHF", 
    "open,high,low,close,volume", 
    "2023-01-01", 
    "2023-12-31"
)
print(data.Data)

二、数据清洗与预处理

数据拿到手,别急着用。我敢说,90% 的原始数据都有问题。缺失值、异常值、复权问题……不处理干净,策略回测就是自欺欺人。

1. 处理缺失值

期货数据经常有缺失,比如节假日、涨停跌停。我的处理原则是:

  • 连续缺失不超过 3 个:用前向填充(ffill)
  • 连续缺失超过 3 个:直接删除该行
  • 开盘价缺失:用前一日收盘价替代
import pandas as pd

# 前向填充缺失值
df.fillna(method='ffill', inplace=True)

# 删除连续缺失超过3天的数据
df = df[df['close'].notna()]
避坑指南:我曾经用简单的均值填充处理缺失值,结果回测曲线漂亮得不行,实盘却一塌糊涂。后来才发现,均值填充会引入未来信息,导致回测过拟合。切记,只能用历史数据填充!

2. 处理异常值

期货市场偶尔会出现极端行情,比如瞬间涨停或跌停。这些数据是真实的,但会干扰策略。我的做法是:

  • 用 3 倍标准差法识别异常值
  • 对于识别出的异常值,用前一日数据替代
  • 保留涨跌停数据,但标记出来
# 3倍标准差法识别异常
mean = df['close'].mean()
std = df['close'].std()
df['is_outlier'] = (abs(df['close'] - mean) > 3 * std)

# 替代异常值
df.loc[df['is_outlier'], 'close'] = df['close'].shift(1)

3. 复权处理

期货有换月问题,不同合约的价格不连续。你需要做复权处理,把历史数据统一到当前合约上。我一般用后复权,简单实用。

# 简单后复权示例
def adjust_price(df):
    # 找到换月点
    roll_date = df[df['contract'] != df['contract'].shift(1)].index
    for date in roll_date:
        ratio = df.loc[date, 'close'] / df.loc[date-1, 'close']
        df.loc[:date-1, 'close'] *= ratio
    return df

三、数据存储:选对格式很重要

数据清洗完了,存哪里?我试过 CSV、HDF5 和数据库,各有适用场景。

1. CSV:简单但慢

CSV 是最简单的格式,适合小数据量。但如果你有几十个品种、几年数据,CSV 的读写速度会让你崩溃。

# 保存为 CSV
df.to_csv('futures_data.csv', index=False)

# 读取 CSV
df = pd.read_csv('futures_data.csv', parse_dates=['trade_date'])

2. HDF5:速度快,适合大数据

HDF5 是我最推荐的格式。它读写速度快,支持压缩,还能按索引查询。我个人的历史数据全部用 HDF5 存储。

# 保存为 HDF5
df.to_hdf('futures_data.h5', key='rb2401', mode='w')

# 读取 HDF5
df = pd.read_hdf('futures_data.h5', key='rb2401')
小技巧:HDF5 支持多 key 存储。你可以把不同品种的数据存在同一个文件里,用 key 区分。这样管理起来特别方便。

3. 数据库:适合团队协作

如果你在团队里做量化,或者数据量特别大(TB 级别),建议用数据库。MySQL 或 PostgreSQL 都行。我个人偏好 PostgreSQL,因为它支持时间序列扩展。

from sqlalchemy import create_engine

# 连接数据库
engine = create_engine('postgresql://user:password@localhost:5432/futures')

# 写入数据库
df.to_sql('futures_daily', engine, if_exists='replace', index=False)

# 从数据库读取
df = pd.read_sql('SELECT * FROM futures_daily WHERE trade_date > "2023-01-01"', engine)

四、知识体系总览

下面这张图,是我梳理的本章知识结构。你可以把它当作一个检查清单,看看自己有没有遗漏。

期货数据获取与预处理知识体系 数据获取 数据清洗 数据存储 Tushare AKShare Wind 缺失值处理 异常值处理 复权处理 CSV HDF5 数据库 关键要点总结 • 数据获取:Tushare 适合历史研究,AKShare 适合实时数据,Wind 是机构首选 • 缺失值:连续缺失≤3用前向填充,>3直接删除 • 异常值:3倍标准差法识别,用前一日数据替代 • 复权:后复权最实用,注意换月点的处理 • 存储:小数据用CSV,大数据用HDF5,团队协作用数据库

五、避坑指南

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

  • 不要相信任何数据源的 100% 准确率。我曾在 Tushare 和 Wind 之间发现 0.5% 的价差,查了半天才发现是复权方式不同。
  • 数据清洗一定要写日志。我习惯记录每次清洗删了多少行、填充了多少值。这样出了问题能追溯。
  • 存储格式不要频繁切换。我见过有人今天用 CSV,明天用 HDF5,后天又换数据库,结果数据对不上。选定一种格式,坚持用下去。

数据是量化交易的基石。这一章的内容,说白了就是帮你打好地基。地基稳了,后面的策略才能盖得高。


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