4、Tick数据存储:CSV格式存储、Parquet格式存储、HDF5格式存储、数据库存储
数据去重和排序搞定了,接下来就是存的问题。
说实话,Tick数据存储这块,我踩过的坑比写过的代码还多。早期做高频回测时,一个月的Tick数据就能把硬盘撑爆,加载一次要等半小时。后来慢慢摸索出几种主流方案,今天一次性讲清楚。
4.1 CSV格式存储——最直接,但别太依赖
CSV是大家最熟悉的格式。说白了就是逗号分隔的文本文件。我刚开始做量化时,所有Tick数据都存CSV,因为简单、直观、任何工具都能打开。
优点:
- 人类可读,Excel直接打开看
- 跨平台兼容,Linux/Windows/Mac通吃
- 生成和解析代码极简
缺点也很明显:
- 文件体积大——同样的数据,CSV比Parquet大3-5倍
- 读写速度慢——尤其是几千万行级别的Tick数据
- 不支持数据类型——所有字段都是字符串,每次要自己转
- 没有索引——查询某一天的Tick数据,得全文件扫描
⚠️ 我曾经踩过的坑: 有一次存了3个月的股指期货Tick数据,单个CSV文件超过10GB。用Pandas读取时直接内存溢出。后来不得不拆成每天一个文件,但查询跨天数据时又得写一堆拼接逻辑。所以,CSV只适合小规模数据或临时调试。
# 写入CSV示例
import pandas as pd
tick_data = pd.DataFrame({
'timestamp': ['2024-01-01 09:30:00.123', '2024-01-01 09:30:00.456'],
'symbol': ['IF2401', 'IF2401'],
'price': [3500.0, 3501.5],
'volume': [10, 15],
'direction': ['buy', 'sell']
})
tick_data.to_csv('tick_data.csv', index=False)
# 读取CSV
df = pd.read_csv('tick_data.csv', parse_dates=['timestamp'])
print(df.head())
4.2 Parquet格式存储——我目前的主力方案
Parquet是列式存储格式。什么意思呢?传统CSV是一行一行存的,Parquet是一列一列存的。你想想看,做量化分析时,我们经常只需要某几列(比如价格和成交量),列式存储就能只读取需要的列,速度飞快。
核心优势:
- 压缩率高——同样的Tick数据,Parquet体积只有CSV的20%-30%
- 读取速度快——只读需要的列,IO量大幅减少
- 自带Schema——每个字段的类型都明确,不用再转换
- 支持谓词下推——比如只读取某一天的Tick数据,Parquet能在文件层面过滤
💡 我个人习惯: 所有超过100万行的Tick数据,一律用Parquet。配合PyArrow或FastParquet库,读写速度比Pandas原生快5-10倍。
# Parquet读写示例
import pandas as pd
import pyarrow.parquet as pq
# 写入Parquet
tick_data.to_parquet('tick_data.parquet', compression='snappy')
# 读取Parquet——只读需要的列
df = pd.read_parquet('tick_data.parquet', columns=['timestamp', 'price', 'volume'])
# 使用PyArrow直接读取,速度更快
table = pq.read_table('tick_data.parquet', columns=['timestamp', 'price'])
print(table.to_pandas().head())
4.3 HDF5格式存储——适合大规模时间序列
HDF5是层次化数据格式。我在做期权高频策略时,需要同时存储Tick数据、分钟数据、日线数据,还要存一些中间计算结果。HDF5的树状结构正好满足这种需求。
特点:
- 支持多维数组——可以存矩阵、图像等复杂数据
- 内部目录结构——一个文件就是一个数据库
- 支持压缩和分块——大文件也能高效读写
- 跨语言支持——Python、C++、Java、MATLAB都能用
📌 避坑指南: 我曾经用HDF5存了5年的Tick数据,结果文件超过50GB。后来发现HDF5在单文件过大时,写入性能会急剧下降。建议每个HDF5文件控制在10GB以内,或者按年份拆分。
# HDF5读写示例
import pandas as pd
import h5py
# 使用Pandas直接写入HDF5
tick_data.to_hdf('tick_data.h5', key='tick_20240101', mode='a')
# 读取HDF5
df = pd.read_hdf('tick_data.h5', key='tick_20240101')
# 使用h5py更底层操作
with h5py.File('tick_data.h5', 'r') as f:
# 查看文件内部结构
print(list(f.keys()))
# 读取数据集
dataset = f['tick_20240101']
print(dataset.shape)
4.4 数据库存储——生产环境的标配
如果你做的是实盘交易系统,数据库几乎是唯一选择。为什么?因为数据库提供了事务、并发控制、权限管理、备份恢复等企业级功能。
常见选择:
| 数据库 | 适用场景 | 读写性能 | 我的评价 |
|---|---|---|---|
| PostgreSQL + TimescaleDB | 中小规模Tick数据(<1亿条/天) | 写入2万条/秒,读取快 | 我最常用的方案,稳定可靠 |
| ClickHouse | 大规模Tick数据(>1亿条/天) | 写入10万条/秒,分析极快 | 适合做数据分析,不适合频繁更新 |
| InfluxDB | 时序数据专用 | 写入5万条/秒,查询灵活 | 适合监控类场景,Tick数据也能用 |
| MongoDB | 灵活Schema的Tick数据 | 写入3万条/秒,读取一般 | 适合字段不固定的场景 |
💡 我建议: 如果你刚开始做Tick数据存储,先用Parquet文件存历史数据,用PostgreSQL+TimescaleDB存实时数据。等数据量上来了,再考虑ClickHouse。别一上来就上分布式数据库,维护成本太高。
# PostgreSQL + TimescaleDB 示例
import psycopg2
from psycopg2.extras import execute_values
conn = psycopg2.connect(
host='localhost',
database='tick_db',
user='quant',
password='your_password'
)
cur = conn.cursor()
# 创建超表(TimescaleDB特性)
cur.execute("""
CREATE TABLE tick_data (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
price DOUBLE PRECISION,
volume INTEGER,
direction TEXT
);
""")
cur.execute("SELECT create_hypertable('tick_data', 'time');")
# 批量插入Tick数据
tick_records = [
('2024-01-01 09:30:00.123+08', 'IF2401', 3500.0, 10, 'buy'),
('2024-01-01 09:30:00.456+08', 'IF2401', 3501.5, 15, 'sell')
]
execute_values(cur,
"INSERT INTO tick_data (time, symbol, price, volume, direction) VALUES %s",
tick_records
)
conn.commit()
# 查询某一天的Tick数据
cur.execute("""
SELECT * FROM tick_data
WHERE time >= '2024-01-01' AND time < '2024-01-02'
AND symbol = 'IF2401'
ORDER BY time
""")
rows = cur.fetchall()
print(f"查询到 {len(rows)} 条Tick数据")
4.5 四种方案对比总结
嗯,这里我直接给结论吧。四种方案各有千秋,没有银弹。
| 维度 | CSV | Parquet | HDF5 | 数据库 |
|---|---|---|---|---|
| 存储效率 | ⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 读取速度 | ⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 写入速度 | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 查询灵活性 | ⭐ | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ |
| 并发支持 | ❌ | ❌ | ❌ | ✅ |
| 适合场景 | 临时调试 | 历史数据存储 | 复杂数据结构 | 生产环境 |
📌 我的最终建议: 历史Tick数据用Parquet存,实时Tick数据用TimescaleDB存。两者之间通过ETL流程同步。这样既保证了历史数据的压缩率和读取速度,又保证了实时数据的写入和查询性能。我在实盘系统中就是这么干的,跑了两年多没出过问题。
好了,四种存储方案都讲完了。CSV适合临时用,Parquet是我最推荐的离线存储方案,HDF5适合复杂数据结构,数据库是生产环境标配。你根据自己实际场景选就行。