3、逐笔数据存储方案:内存存储、磁盘存储、数据库存储
做量化交易的朋友都知道,逐笔成交数据有多「吃」存储。我刚开始接触这个领域时,以为几天的数据顶多几百兆。结果呢?一天的高频数据就能撑爆我的笔记本内存。嗯,存储方案选不对,后面全白费。
今天咱们就聊聊,逐笔数据到底该怎么存。我把它分成三大类:内存存储、磁盘存储、数据库存储。每种方案都有它的脾气,咱们一个一个拆解。
3.1 内存存储:Pandas DataFrame
说白了,就是把数据直接塞进内存里。Pandas DataFrame 是咱们最熟悉的工具,没有之一。
适用场景:回测、策略验证、小批量数据分析。
我个人习惯在回测时用 DataFrame。原因很简单——快。读取一次,后面所有操作都在内存里跑,速度没得说。
import pandas as pd
# 读取逐笔成交数据
df = pd.read_csv('tick_data.csv')
print(f'数据量: {len(df)} 行')
print(f'内存占用: {df.memory_usage(deep=True).sum() / 1024**2:.2f} MB')
但这里有个坑。我曾经在项目中一次性加载了 3 天的逐笔数据,结果内存直接飙到 8GB。你想想看,如果做全市场回测,内存根本扛不住。
避坑指南:我曾经因为内存溢出导致回测跑了 6 小时白跑。后来学乖了,用 dtype 参数压缩数据类型,内存能省 40% 以上。
# 压缩数据类型,节省内存
df = pd.read_csv('tick_data.csv',
dtype={
'price': 'float32',
'volume': 'int32',
'timestamp': 'int64'
})
3.2 磁盘存储:HDF5 与 Parquet
内存不够用怎么办?那就存磁盘。但别用 CSV,那玩意儿又慢又占空间。我推荐两个格式:HDF5 和 Parquet。
3.2.1 HDF5 格式
HDF5 是科学计算领域的老牌格式。它的特点是:支持分层存储、支持压缩、读取速度快。
import h5py
# 写入 HDF5
with h5py.File('tick_data.h5', 'w') as f:
f.create_dataset('tick_data', data=df.values)
f.create_dataset('columns', data=df.columns.values.astype('S'))
# 读取 HDF5
with h5py.File('tick_data.h5', 'r') as f:
data = f['tick_data'][:]
cols = [c.decode() for c in f['columns'][:]]
df_h5 = pd.DataFrame(data, columns=cols)
我记得有一次做全市场逐笔数据回放,HDF5 的读取速度比 CSV 快了将近 10 倍。而且压缩后文件大小只有原来的 1/3。
3.2.2 Parquet 格式
Parquet 是大数据生态的宠儿。它的列式存储结构,特别适合逐笔数据这种「按列查询」的场景。
import pyarrow.parquet as pq
# 写入 Parquet
df.to_parquet('tick_data.parquet', compression='snappy')
# 读取 Parquet
df_pq = pd.read_parquet('tick_data.parquet')
我的建议:如果你做的是单机分析,HDF5 够用。如果未来要对接大数据平台,直接上 Parquet。别问我怎么知道的——我踩过换格式的坑。
3.3 数据库存储:InfluxDB 与 ClickHouse
当数据量达到 TB 级别,磁盘文件也扛不住了。这时候需要专业的时序数据库。
3.3.1 InfluxDB
InfluxDB 是专为时序数据设计的。它的查询语法简单,写入速度快,适合实时行情存储。
from influxdb import InfluxDBClient
client = InfluxDBClient(host='localhost', port=8086)
client.switch_database('tick_db')
# 写入数据
json_body = [
{
"measurement": "tick_data",
"tags": {"symbol": "000001"},
"time": "2024-01-01T09:30:00Z",
"fields": {
"price": 10.25,
"volume": 1000
}
}
]
client.write_points(json_body)
但 InfluxDB 有个缺点:不支持复杂的 JOIN 操作。如果你需要关联多张表,它就不太合适了。
3.3.2 ClickHouse
ClickHouse 是我目前的主力存储方案。它的列式存储、向量化执行引擎,让逐笔数据的聚合查询快到飞起。
-- 创建表
CREATE TABLE tick_data (
timestamp DateTime,
symbol String,
price Float64,
volume UInt64
) ENGINE = MergeTree()
ORDER BY (symbol, timestamp);
-- 查询某只股票每分钟的平均价格
SELECT
toStartOfMinute(timestamp) AS minute,
avg(price) AS avg_price
FROM tick_data
WHERE symbol = '000001'
GROUP BY minute
ORDER BY minute;
性能对比:我做过测试,在 10 亿行逐笔数据上,ClickHouse 的聚合查询比 MySQL 快了 100 倍以上。这不是夸张,是实测数据。
3.4 存储性能对比与选型建议
咱们直接上对比表,一目了然:
| 存储方案 | 读取速度 | 写入速度 | 压缩比 | 并发支持 | 适用场景 |
|---|---|---|---|---|---|
| Pandas DataFrame | 极快 | 快 | 无 | 单线程 | 回测、小批量分析 |
| HDF5 | 快 | 中等 | 高 | 单线程 | 单机大数据分析 |
| Parquet | 快 | 中等 | 高 | 多线程 | 大数据生态、Spark |
| InfluxDB | 中等 | 极快 | 中等 | 高并发 | 实时行情、监控 |
| ClickHouse | 极快 | 快 | 高 | 高并发 | 大规模时序分析 |
选型建议其实很简单:
- 个人研究、回测:Pandas DataFrame + HDF5 就够用
- 团队协作、中等规模:Parquet + ClickHouse 是黄金组合
- 实时行情、高频交易:InfluxDB 写入快,适合做缓存层
注意:别一上来就上 ClickHouse。我见过有人为了存 100 万行数据搭了个 ClickHouse 集群,完全是杀鸡用牛刀。先评估数据量,再选方案。
3.5 知识体系总览
下面这张图,是我梳理的逐笔数据存储方案选型逻辑。你跟着这个思路走,基本不会出错。
这张图的核心逻辑就一句话:先看数据量,再选存储方案。别盲目追求高大上的技术栈,适合你的才是最好的。
好了,关于逐笔数据的存储方案,咱们就聊到这儿。下一章我会讲讲数据清洗的那些坑,保证让你少走弯路。
公众号:蓝海数据掘金营,微信deep3321