数据源获取:Tushare/JoinQuant等API接入、CSV文件批量读取、Excel数据导入

做套利数据清洗,第一步就是搞到数据。这活儿看着简单,其实坑不少。我见过太多人花80%时间在数据获取上,最后真正做策略的时间反而没多少。今天咱们就把这块彻底讲透。

2.1 数据源的选择:别盲目跟风

市面上数据源很多,但适合期货套利的其实就那几家。我个人习惯把数据源分成三类:

类型 代表 适合场景 注意点
专业金融API Tushare、JoinQuant 实时数据、高频策略 有调用次数限制
本地文件 CSV、Excel 历史回测、离线分析 格式不统一
数据库直连 MySQL、MongoDB 团队协作、大规模存储 需要运维成本

嗯,这里要注意:别一上来就追求实时数据。我刚开始做套利时,花了两周搭实时数据管道,结果发现历史数据都没清洗干净,策略根本跑不起来。先搞定离线数据,再考虑实时。

2.2 Tushare API接入:从注册到第一行数据

Tushare是我用得最多的数据源之一。它的期货数据比较全,而且文档清晰。咱们直接上代码:

import tushare as ts

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

# 获取期货日线数据
df = pro.fut_daily(
    ts_code='RB2401.SHF',  # 螺纹钢2401合约
    start_date='20230101',
    end_date='20231231',
    fields='ts_code,trade_date,open,high,low,close,vol,amount'
)

print(df.head())
我的经验: 第一次调用API时,先打印返回的数据结构。我遇到过字段名和文档对不上的情况,比如文档写的是"vol",实际返回的是"volume"。先看一眼数据长啥样,能省很多排查时间。

为什么会这样?因为不同数据源对字段命名有自己的习惯。Tushare用"vol"表示成交量,JoinQuant可能用"volume"。你想想看,如果直接拿过来用,后面清洗时才发现字段名不对,那得多折腾。

2.3 JoinQuant API接入:聚宽的数据获取方式

JoinQuant(聚宽)的API风格和Tushare不太一样。它更偏向于策略回测场景,但也可以单独用来获取数据。我个人习惯在聚宽上做因子计算,因为它的数据预处理做得比较好。

from jqdatasdk import *

# 登录(需要注册账号)
auth('你的账号', '你的密码')

# 获取期货行情数据
df = get_price(
    security='RB2401.XSGE',  # 螺纹钢2401
    start_date='2023-01-01',
    end_date='2023-12-31',
    frequency='daily',
    fields=['open', 'close', 'high', 'low', 'volume', 'money']
)

print(df.head())
避坑指南: 我曾经在聚宽上同时拉取50个合约的数据,结果被限流了。后来发现,聚宽对单次请求的合约数量有限制。建议分批拉取,每次不超过10个合约,中间sleep 1秒。

2.4 CSV文件批量读取:处理海量历史数据

做套利策略,经常要处理几年的历史数据。这些数据通常以CSV格式存在本地。批量读取时,有几个关键点要注意:

import pandas as pd
import glob
import os

# 批量读取所有CSV文件
csv_files = glob.glob('data/futures/*.csv')

# 用字典存储,key是文件名,value是DataFrame
data_dict = {}
for file in csv_files:
    # 提取合约名称
    contract_name = os.path.basename(file).replace('.csv', '')
    
    # 读取时指定数据类型,避免自动推断
    df = pd.read_csv(
        file,
        dtype={
            'open': 'float64',
            'high': 'float64',
            'low': 'float64',
            'close': 'float64',
            'volume': 'int64'
        },
        parse_dates=['trade_date']
    )
    
    data_dict[contract_name] = df

print(f"成功读取 {len(data_dict)} 个合约数据")
核心要点: 读取CSV时一定要指定dtype。如果不指定,pandas会自动推断类型,但有时候会把"0"开头的合约代码识别成数字,导致数据丢失。我踩过这个坑,后来就养成了手动指定类型的习惯。

2.5 Excel数据导入:处理非标准格式

Excel数据是最让人头疼的。因为不同来源的Excel,格式五花八门。有的表头在第一行,有的在第三行;有的日期是文本格式,有的是数字格式。咱们得灵活处理:

import pandas as pd

# 读取Excel,跳过前两行(因为有些Excel有标题行)
df = pd.read_excel(
    'data/futures_data.xlsx',
    sheet_name='Sheet1',
    skiprows=2,  # 跳过前两行
    header=0,    # 第三行作为表头
    usecols='A:H',  # 只读取A到H列
    dtype={
        '合约代码': 'str',
        '开盘价': 'float64',
        '收盘价': 'float64'
    }
)

# 处理日期格式
df['交易日期'] = pd.to_datetime(df['交易日期'], format='%Y%m%d')

print(df.head())
小技巧: 如果Excel文件特别大(超过100MB),建议先用Excel自带的筛选功能,把不需要的列删掉再导入。我试过直接导入一个500MB的Excel,结果内存爆了。后来就养成了先精简再导入的习惯。

2.6 数据源统一接口封装

实际项目中,我们往往需要同时使用多个数据源。我建议封装一个统一的数据获取接口,这样切换数据源时不用改业务代码:

class DataSource:
    def __init__(self, source_type='tushare'):
        self.source_type = source_type
        if source_type == 'tushare':
            import tushare as ts
            ts.set_token('your_token')
            self.api = ts.pro_api()
        elif source_type == 'jq':
            from jqdatasdk import auth
            auth('account', 'password')
            self.api = 'jq'
    
    def get_futures_data(self, symbol, start_date, end_date):
        if self.source_type == 'tushare':
            return self._get_from_tushare(symbol, start_date, end_date)
        elif self.source_type == 'jq':
            return self._get_from_jq(symbol, start_date, end_date)
    
    def _get_from_tushare(self, symbol, start_date, end_date):
        # Tushare具体实现
        pass
    
    def _get_from_jq(self, symbol, start_date, end_date):
        # JoinQuant具体实现
        pass

# 使用示例
ds = DataSource('tushare')
data = ds.get_futures_data('RB2401.SHF', '20230101', '20231231')

说白了,这个封装就是让你不用关心底层用的是哪个数据源。哪天Tushare收费了,你换个数据源,只需要改一行代码。

2.7 数据获取的常见坑与解决方案

做数据获取这么多年,我总结了几条血泪教训:

  • 合约代码不一致: Tushare用"RB2401.SHF",JoinQuant用"RB2401.XSGE"。建议统一映射表,把不同数据源的代码对应起来。
  • 数据缺失: 节假日、停牌日会导致数据缺失。我习惯用前向填充(ffill)来处理,但要注意不要填充太久的数据。
  • 网络超时: 批量拉取数据时,网络波动会导致请求失败。建议加个重试机制,最多重试3次。
  • 内存溢出: 一次性拉取太多数据,内存会爆。建议分批次拉取,每批1000条。
重要提醒: 数据获取只是第一步,千万别在这上面花太多时间。我见过有人为了追求"完美数据",花了一个月搭建数据管道,结果策略都没时间写。先跑起来,再优化。

2.8 本章知识体系

下面这张图展示了数据源获取的整体流程和各个模块之间的关系:

数据源获取知识体系 数据源获取 API接入 文件读取 数据库直连 Tushare JoinQuant CSV批量 Excel导入 MySQL MongoDB 注意事项 • 合约代码映射:不同数据源代码格式不同,需统一 • 数据类型指定:读取时手动指定dtype,避免自动推断错误 • 分批拉取:避免单次请求数据量过大导致超时 • 重试机制:网络波动时自动重试,最多3次 • 统一接口封装:切换数据源时只需改一行代码

这张图把数据源获取的三大路径和各自的子模块都列出来了。你可以把它当作一个检查清单,每次做数据获取时对照着看,能避免不少低级错误。


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