2. Tick数据获取:常见Tick数据源介绍与Python获取方法
Tick数据是量化回测的“原油”,其质量与获取方式直接影响策略的精度与可靠性。本章将系统梳理主流Tick数据源,并演示通过Python API与CSV文件两种方式获取Tick数据的具体方法。
2.1 常见Tick数据源对比
根据数据来源与合规性,Tick数据源可分为交易所直连、数据商代理、社区共享三类。下表从数据精度、成本、获取难度三个维度进行对比:
| 数据源类型 | 典型代表 | 数据精度 | 成本 | 获取难度 | 适用场景 |
|---|---|---|---|---|---|
| 交易所直连 | 上交所L1/L2、深交所L1/L2、CME | 最高(逐笔委托/成交) | 极高(会员费+行情费) | 高(需机构资质) | 机构高频、做市商 |
| 专业数据商 | Wind、聚宽、RiceQuant、Tushare | 高(快照Tick) | 中高(年费/积分) | 中(API申请) | 中低频回测、因子研究 |
| 社区/开源 | AKShare、Yahoo Finance(延迟) | 低(分钟级或延迟Tick) | 免费 | 低(pip安装) | 学习、原型验证 |
选型建议: 个人量化研究者优先选择专业数据商(如Tushare Pro或AKShare),兼顾数据质量与成本;机构用户应直接对接交易所或购买L2行情。
2.2 交易所Tick数据体系
交易所是Tick数据的最终源头。以国内A股为例,Level-1与Level-2行情在数据维度上存在显著差异:
- Level-1(基础行情):每3秒快照一次,包含最新价、成交量、五档买卖盘口。适合日频或分钟级回测。
- Level-2(极速行情):逐笔成交与逐笔委托,时间戳精确到毫秒甚至微秒。支持订单流分析与高频策略。
下图展示了从交易所原始逐笔数据到用户可用的Tick数据帧的流转链路:
2.3 Python获取Tick数据:API方式
通过数据商提供的Python SDK,可以高效获取历史Tick数据。以下以Tushare Pro为例,展示获取某只股票某日Tick数据的标准流程:
import tushare as ts
# 设置token(需在tushare官网注册获取)
pro = ts.pro_api('your_token_here')
# 获取2024年1月2日贵州茅台(600519.SH)的Tick数据
df = pro.tick_data(
ts_code='600519.SH',
trade_date='20240102',
start_time='093000',
end_time='150000'
)
# 查看前5行
print(df.head())
# 输出示例:
# ts_code trade_date trade_time price vol amount buy sell
# 0 600519.SH 20240102 093000 1685.0 10 16850 1 2
# 1 600519.SH 20240102 093001 1685.2 5 8426 1 1
# 2 600519.SH 20240102 093002 1685.1 20 33702 2 3
API调用要点:
- 大部分数据商对Tick数据有调用频率限制(如每分钟最多200次),需合理控制请求间隔。
- 历史Tick数据通常只保留近1-3年,更早的数据需通过数据商VIP接口或购买离线数据集。
- 返回的DataFrame中,
trade_time字段通常为字符串格式,需转换为datetime以便后续时间序列处理。
2.4 Python获取Tick数据:CSV读取方式
对于已下载到本地的Tick CSV文件,使用Pandas读取并做初步清洗是回测前的标准步骤。典型的Tick CSV文件包含以下字段:
| 字段名 | 类型 | 说明 |
|---|---|---|
datetime |
str | 日期时间,格式如 2024-01-02 09:30:00.123 |
price |
float | 成交价格 |
volume |
int | 成交量(股) |
amount |
float | 成交金额(元) |
direction |
str | 买卖方向:B(买)/S(卖)/N(中性) |
import pandas as pd
# 读取Tick CSV文件
df = pd.read_csv(
'tick_data_600519_20240102.csv',
parse_dates=['datetime'],
dtype={
'price': 'float64',
'volume': 'int32',
'amount': 'float64',
'direction': 'category'
}
)
# 按时间排序(确保时间顺序)
df.sort_values('datetime', inplace=True)
# 重置索引
df.reset_index(drop=True, inplace=True)
# 检查缺失值
print(f"缺失值统计:\n{df.isnull().sum()}")
# 查看数据范围
print(f"时间范围: {df['datetime'].min()} ~ {df['datetime'].max()}")
print(f"总Tick数: {len(df)}")
CSV读取常见陷阱:
- 时间戳精度丢失:CSV中毫秒/微秒可能被截断,读取时需指定
parse_dates的格式,如format='%Y-%m-%d %H:%M:%S.%f'。 - 大文件内存溢出:单日Tick数据约10-50万行,多日合并可能达数千万行。建议使用
chunksize分块读取或转为Parquet格式。 - 字段类型错误:
volume可能被读为float,需显式指定dtype为int。
2.5 数据质量校验与预处理
无论通过API还是CSV获取,Tick数据都需要经过以下质量检查才能用于回测:
- 时间连续性检查:检查是否存在时间跳跃或重复时间戳。
- 价格合理性检查:价格是否在当日涨跌停范围内,是否存在负价格或异常跳变。
- 成交量检查:单笔成交量是否超过市场合理阈值(如A股单笔最大100万手)。
- 买卖方向一致性:检查
direction字段是否与价格变动逻辑一致。
# 简单质量检查示例
# 1. 检查重复时间戳
duplicates = df[df.duplicated(subset=['datetime'], keep=False)]
if len(duplicates) > 0:
print(f"发现 {len(duplicates)} 条重复时间戳")
# 2. 检查价格是否在合理范围(假设前收盘价1680,涨跌停±10%)
prev_close = 1680.0
lower_limit = prev_close * 0.9
upper_limit = prev_close * 1.1
out_of_range = df[(df['price'] < lower_limit) | (df['price'] > upper_limit)]
if len(out_of_range) > 0:
print(f"发现 {len(out_of_range)} 条价格异常数据")
# 3. 检查单笔成交量是否异常
max_volume = 1000000 # 100万手
abnormal_vol = df[df['volume'] > max_volume]
if len(abnormal_vol) > 0:
print(f"发现 {len(abnormal_vol)} 条成交量异常数据")
数据清洗原则: 对于异常数据,优先标记而非直接删除。在回测中可设置“数据质量过滤器”,将异常Tick标记为无效,避免影响策略信号计算。
通过以上方法,你可以从不同数据源获取Tick数据,并完成基本的清洗与校验,为后续的收益回测打下坚实的数据基础。