数据源获取: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())
为什么会这样?因为不同数据源对字段命名有自己的习惯。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())
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)} 个合约数据")
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())
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 本章知识体系
下面这张图展示了数据源获取的整体流程和各个模块之间的关系:
这张图把数据源获取的三大路径和各自的子模块都列出来了。你可以把它当作一个检查清单,每次做数据获取时对照着看,能避免不少低级错误。
公众号:蓝海资料掘金营,微信deep3321