高频数据存储:HDF5、Parquet、InfluxDB时序数据库

做高频量化的人,迟早要面对一个灵魂拷问:数据存哪?

我刚开始做高频回测那会儿,傻乎乎地把所有Tick数据塞进MySQL。结果呢?一张表几亿行,查询一次要等半天。后来我才明白——高频数据的存储,不是存不存得下的问题,而是读不读得出来的问题。

今天咱们就聊聊三种主流方案:HDF5、Parquet、InfluxDB。它们各有各的脾气,选对了事半功倍,选错了……嗯,你会浪费大量时间在I/O等待上。

核心观点:高频数据存储没有银弹。本地分析用HDF5,跨平台协作用Parquet,实时监控用InfluxDB。别指望一个方案打天下。

一、HDF5:老牌劲旅,适合本地重度分析

HDF5(Hierarchical Data Format version 5)是科学计算领域的老将。它本质上是一个自描述的文件容器,可以存多维数组、表格、甚至图像。

我个人习惯把HDF5当作本地分析的“工作台”。每天收盘后,把当天的Tick数据追加到一个HDF5文件里,然后用Python的h5py或pandas的HDFStore直接读取分析。速度非常快。

我的经验:HDF5最适合存“一次性写入、多次读取”的数据。如果你需要频繁修改数据,它并不是好选择。

HDF5的核心优势

  • 读取速度快:特别是按列读取时,比CSV快几十倍
  • 支持压缩:默认的zlib压缩能把数据体积压到原来的1/5
  • 层次结构:可以像文件系统一样组织数据,比如 /data/2024/01/01/tick
  • 与Python生态无缝集成:pandas的HDFStore直接读写DataFrame

代码示例:用HDF5存储Tick数据

import pandas as pd
import numpy as np

# 模拟高频Tick数据
np.random.seed(42)
n = 1000000
df = pd.DataFrame({
    'timestamp': pd.date_range('2024-01-01', periods=n, freq='1ms'),
    'price': 100 + np.random.randn(n) * 0.5,
    'volume': np.random.randint(1, 100, n),
    'side': np.random.choice(['buy', 'sell'], n)
})

# 写入HDF5(使用固定格式,速度更快)
df.to_hdf('tick_data.h5', key='tick', mode='w', format='fixed', complevel=5)

# 读取指定时间范围的数据
query = 'timestamp > "2024-01-01 00:00:00" and timestamp < "2024-01-01 00:01:00"'
result = pd.read_hdf('tick_data.h5', 'tick', where=query)
print(f"查询到 {len(result)} 条记录")

避坑指南:我曾经用HDF5存了3年的Tick数据,结果文件超过100GB。HDF5单文件太大时,读写性能会急剧下降。建议按月份或季度拆分文件。

二、Parquet:列式存储的现代选择

Parquet是Apache Hadoop生态下的列式存储格式。它和HDF5最大的区别在于:Parquet天生为“大数据”而生,支持分布式处理,压缩率更高。

我为什么后来转向Parquet?因为团队需要把数据从本地搬到云端。HDF5在Spark、Flink这些框架里支持不太好,而Parquet是它们的“亲儿子”。

Parquet的核心优势

  • 极高的压缩率:Snappy压缩下,高频数据能压到原始大小的1/10
  • 列式存储:只读取需要的列,I/O开销极小
  • 跨平台兼容:Spark、Presto、ClickHouse都能直接读
  • 支持复杂嵌套结构:可以存JSON格式的订单簿快照

代码示例:用Parquet存储高频数据

import pandas as pd
import pyarrow.parquet as pq
import pyarrow as pa

# 同样模拟高频数据
df = pd.DataFrame({
    'timestamp': pd.date_range('2024-01-01', periods=500000, freq='2ms'),
    'bid': 99.5 + np.random.randn(500000) * 0.3,
    'ask': 100.5 + np.random.randn(500000) * 0.3,
    'bid_vol': np.random.randint(1, 50, 500000),
    'ask_vol': np.random.randint(1, 50, 500000)
})

# 写入Parquet(使用Snappy压缩)
table = pa.Table.from_pandas(df)
pq.write_table(table, 'orderbook.parquet', compression='snappy')

# 只读取两列
df_bid_ask = pd.read_parquet('orderbook.parquet', columns=['timestamp', 'bid', 'ask'])
print(f"读取了 {len(df_bid_ask)} 行,仅包含3列")

我的建议:如果你需要和团队共享数据,或者数据要上云,优先选Parquet。它比HDF5更“通用”。

三、InfluxDB:专为时序数据设计的数据库

HDF5和Parquet都是文件格式,而InfluxDB是一个时序数据库。它专门为“时间戳+数值”这种数据结构做了深度优化。

我记得第一次用InfluxDB是在做实时监控系统的时候。当时需要每秒写入几万条行情数据,同时还要支持毫秒级的查询。MySQL扛不住,HDF5不支持并发写入。InfluxDB完美解决了这个问题。

InfluxDB的核心优势

  • 超高写入性能:单机每秒可写入百万级数据点
  • 自动数据保留策略:可以设置数据过期自动删除
  • 内置降采样:自动将高频数据聚合为分钟级、小时级数据
  • 类SQL查询:使用InfluxQL或Flux语言,上手快

代码示例:用InfluxDB存储实时Tick

from influxdb import InfluxDBClient
import time
import random

# 连接InfluxDB(默认端口8086)
client = InfluxDBClient(host='localhost', port=8086)
client.create_database('tick_db')
client.switch_database('tick_db')

# 模拟实时写入
for i in range(100):
    json_body = [
        {
            "measurement": "tick",
            "tags": {
                "symbol": "BTCUSDT",
                "exchange": "binance"
            },
            "time": int(time.time() * 1e9),  # 纳秒时间戳
            "fields": {
                "price": 50000 + random.random() * 100,
                "volume": random.randint(1, 10)
            }
        }
    ]
    client.write_points(json_body)
    time.sleep(0.01)  # 模拟10ms间隔

# 查询最近1分钟的数据
results = client.query('SELECT * FROM tick WHERE time > now() - 1m')
print(f"查询到 {len(list(results.get_points()))} 条记录")

避坑指南:我曾经在生产环境遇到过InfluxDB的“写放大”问题——当数据量太大时,磁盘I/O会暴涨。解决方案是:合理设置shard duration,让数据按天或按小时分片。

四、三种方案对比:一张表说清楚

特性 HDF5 Parquet InfluxDB
存储方式 文件 文件 数据库
写入性能 中等(单线程) 中等(批量写入快) 极高(并发写入)
读取性能 快(按列读取) 极快(列式+谓词下推) 快(按时间范围查询)
压缩率 中等(zlib) 高(Snappy/Zstd) 低(默认不压缩)
并发支持 差(单文件锁) 差(只读并发好) 好(多客户端写入)
适用场景 本地分析、回测 数据交换、云端分析 实时监控、在线查询
学习成本 低(pandas即可) 低(pyarrow/pandas) 中(需学InfluxQL)

五、我的实战建议

说了这么多,到底怎么选?我给出一个决策流程

  1. 如果你只是个人做回测,数据量在几十GB以内 → 用HDF5。简单、直接、够用。
  2. 如果你需要和团队协作,或者数据要上云 → 用Parquet。它是大数据生态的通用语言。
  3. 如果你需要实时写入和查询,比如做盘中的信号监控 → 用InfluxDB。它天生为这种场景设计。
  4. 如果你全都要 → 混合使用。HDF5做本地分析,Parquet做数据交换,InfluxDB做实时监控。

最后说一句:存储方案只是工具,别在工具选择上内耗。高频数据的核心永远是信号的质量策略的稳定性。存储只要不拖后腿,就是好方案。

高频数据存储方案选择 高频数据存储 HDF5 Parquet InfluxDB 适用场景 • 本地回测分析 • 个人研究使用 • 数据量 < 100GB 优点:简单、速度快 缺点:并发差、单文件 推荐:pandas + h5py 适用场景 • 数据交换共享 • 云端大数据分析 • 跨平台协作 优点:压缩率高、通用 缺点:写入稍慢 推荐:pyarrow + Spark 适用场景 • 实时行情监控 • 在线查询服务 • 多客户端写入 优点:写入极快、并发好 缺点:学习成本高 推荐:InfluxDB 2.x 没有银弹,根据场景选择最合适的方案