2. 数据源与格式:常见Tick数据源与存储格式对比
做高频回测,第一步就是搞数据。这一步要是没走对,后面全白搭。我见过太多人花大把时间调策略,最后发现是数据本身有问题——那种感觉,真的挺崩溃的。
今天咱们就聊聊Tick数据的来源,以及怎么存、怎么读效率最高。说白了,就是搞清楚「数据从哪来」和「数据怎么放」这两个问题。
2.1 常见Tick数据源
Tick数据的来源,大致分三类:交易所直连、券商接口、第三方数据商。各有各的优缺点,我一个个说。
2.1.1 交易所直连
这是最原始、最干净的数据源。像上交所、深交所、中金所,都会提供Level-2行情数据。我早年做期货高频时,直接拉过中金所的Tick数据,那叫一个爽——毫秒级精度,没有中间商赚差价。
- 优点:数据最完整,延迟最低,没有第三方加工痕迹
- 缺点:贵。非常贵。而且接口复杂,需要专线,一般人搞不定
- 适用场景:机构级高频策略,或者你钱多任性
2.1.2 券商接口
大部分个人交易者接触到的,其实是券商提供的行情数据。比如你用的通达信、同花顺、QMT这些,背后都是券商在转发交易所的数据。
- 优点:门槛低,开户就能用,很多还免费
- 缺点:数据有延迟,而且券商可能会做「数据清洗」——说白了就是过滤掉一些他们认为「异常」的Tick。你想想看,这多危险?
- 适用场景:策略开发初期,或者做低频回测
我个人习惯,用券商数据做初步验证可以,但真要跑实盘级别的回测,还是得找更靠谱的源。
2.1.3 第三方数据商
这是目前最主流的选择。像Wind、聚宽、米筐、Tushare这些,都提供历史Tick数据。还有一些国外的,比如Quandl、Polygon。
| 数据商 | 覆盖市场 | 数据精度 | 价格 | 我的评价 |
|---|---|---|---|---|
| Wind | A股、期货、期权 | 毫秒级 | 贵(机构价) | 数据最全,但API有点老 |
| 聚宽 | A股、期货 | 毫秒级 | 中等 | 适合量化,文档友好 |
| 米筐 | A股、期货、美股 | 毫秒级 | 中等 | 回测平台不错 |
| Tushare | A股 | 秒级 | 免费/低 | 入门首选,但精度有限 |
2.2 数据存储格式对比
数据拿到手了,怎么存?这问题看着简单,其实门道不少。我见过有人把几百G的Tick数据全塞进CSV里,结果每次回测光读数据就要半小时——这还玩个啥?
目前主流的格式有三种:CSV、Parquet、Arrow。咱们一个一个看。
2.2.1 CSV格式
CSV是最通用的格式,几乎任何工具都能打开。但说实话,它真的不适合高频数据。
# 一个典型的Tick CSV文件
timestamp,symbol,price,volume,side
2024-01-01 09:30:00.123,000001.SZ,10.25,100,B
2024-01-01 09:30:00.125,000001.SZ,10.26,200,S
2024-01-01 09:30:00.127,000001.SZ,10.25,150,B
...
- 优点:人类可读,任何语言都能解析,调试方便
- 缺点:文件巨大(文本存储),读写慢,没有压缩,不支持列式筛选
- 适用场景:数据量小(百万行以内),或者做数据交换
2.2.2 Parquet格式
Parquet是列式存储格式,专门为大数据场景设计的。现在几乎成了量化领域的标配。
# 用pandas读写Parquet
import pandas as pd
# 读取Parquet文件
df = pd.read_parquet('tick_data.parquet')
# 写入Parquet文件
df.to_parquet('tick_data.parquet', compression='snappy')
- 优点:压缩率高(通常能压到CSV的1/5到1/10),读取速度快(列式存储,只读需要的列),支持复杂嵌套结构
- 缺点:写入稍慢,不直观(不能直接文本打开看)
- 适用场景:大规模Tick数据存储,高频回测
2.2.3 Arrow格式
Arrow是这两年火起来的内存列式格式。它和Parquet最大的区别是:Parquet是磁盘格式,Arrow是内存格式。
# 用pyarrow操作Arrow格式
import pyarrow as pa
import pyarrow.parquet as pq
# 从Parquet读到Arrow Table
table = pq.read_table('tick_data.parquet')
# 直接操作Arrow数据
# 零拷贝,速度极快
filtered = table.filter(pa.compute.greater(table.column('price'), 10.0))
- 优点:内存中零拷贝,跨语言共享数据(C++/Python/Java/Rust都能用),向量化计算极快
- 缺点:占用内存大,不适合长期存储
- 适用场景:高频回测时的内存数据交换,实时计算管道
2.3 三种格式对比总结
| 特性 | CSV | Parquet | Arrow |
|---|---|---|---|
| 存储类型 | 行式文本 | 列式二进制 | 列式内存 |
| 压缩率 | 无(或很低) | 高(5-10倍) | 中等 |
| 读取速度 | 慢 | 快 | 极快 |
| 写入速度 | 快 | 中等 | 快 |
| 人类可读 | 是 | 否 | 否 |
| 跨语言支持 | 全支持 | 广泛支持 | 原生支持 |
| 推荐场景 | 小数据量/调试 | 磁盘存储/回测 | 内存计算/实时 |
2.4 我的推荐方案
说了这么多,到底怎么选?我个人的经验是这样的:
- 原始数据落地:用Parquet。压缩率高,读取快,适合长期保存
- 回测时加载:从Parquet读到Arrow。这样在内存里操作极快,而且可以跨语言共享
- 调试和检查:偶尔导出CSV。用Excel或者文本编辑器看一眼,确认数据没问题
你想想看,一套流程下来,数据从磁盘到内存再到计算,每一步都用最合适的格式。这才是做高频回测该有的态度。
这张图把整个流程串起来了。从数据源到存储再到应用,每一层都有对应的最佳实践。记住这个架构,后面咱们写代码的时候,每一步都会对应到这里。