4、CSV格式设计:列定义、文件命名与分片策略
做量化交易的朋友都知道,订单簿快照是高频数据的核心资产。今天咱们聊聊CSV格式怎么设计才实用。我这些年踩过不少坑,从列定义到文件命名,再到分片策略,每个细节都直接影响后续分析的效率。
4.1 列定义:时间戳、价格、数量、方向
先说说最基本的四列。你可能会想,就四列有什么好设计的?其实不然。我见过太多团队因为列定义不统一,导致数据清洗花掉一半时间。
| 列名 | 类型 | 说明 | 示例 |
|---|---|---|---|
| timestamp | int64 | Unix毫秒时间戳 | 1704067200000 |
| price | float64 | 价格,保留交易所精度 | 42350.50 |
| quantity | float64 | 数量,保留交易所精度 | 1.2345 |
| side | string | 方向:'bid'或'ask' | bid |
时间戳这块我建议用Unix毫秒。为什么不用字符串?因为字符串排序和计算都慢,而且不同交易所的格式五花八门。用整数时间戳,后续做时间窗口聚合、回测对齐都方便。
价格和数量用float64就够了。有人喜欢用decimal,但CSV本身是文本格式,读进来再转decimal反而多一步。我一般保留交易所原始精度,比如币安给到小数点后8位,那就存8位。
方向用'bid'和'ask',简单明了。别用0和1,虽然省空间,但可读性差。你想想看,排查数据时一眼看到'bid'多舒服。
核心原则:列定义要兼顾机器效率和人类可读性。别为了省几个字节牺牲可维护性。
4.2 文件命名规则
文件命名这事,看似简单,但做不好能让你找数据找到崩溃。我有一套命名规范,用了好几年,团队里没人抱怨过。
# 命名模板
{交易所}_{交易对}_{日期}_{时间粒度}.csv
# 示例
binance_btcusdt_20240101_1min.csv
okex_ethusdt_20240101_1hour.csv
为什么这么设计?
- 交易所放前面:方便按交易所筛选。我经常同时跑多个交易所的数据,一眼就能区分。
- 交易对用下划线:避免斜杠在文件名里出问题。Windows和Linux对斜杠的处理不一样,你懂的。
- 日期用YYYYMMDD:按字典序排序就是按时间排序。这个细节很重要,批量处理时能省很多事。
- 时间粒度标注:1min、5min、1hour,明确告诉使用者这个文件的数据密度。
小技巧:文件名里不要用空格。用下划线或连字符代替。空格在命令行里要转义,烦得很。
4.3 分片策略:按日期 vs 按小时
分片策略直接影响数据查询和处理的效率。我根据数据量和查询模式,总结了两套方案。
按日期分片
适合日频数据或数据量不大的场景。比如每天一个文件,每个文件包含当天所有快照。
# 按日期分片
binance_btcusdt_20240101_1min.csv (约1.4MB)
binance_btcusdt_20240102_1min.csv (约1.5MB)
binance_btcusdt_20240103_1min.csv (约1.3MB)
优点:文件数量少,管理方便。适合做日级别的回测和统计。
缺点:如果数据量很大,单文件可能几百MB,加载和解析都慢。
按小时分片
适合高频数据或数据量大的场景。比如每小时一个文件,每个文件包含该小时内的所有快照。
# 按小时分片
binance_btcusdt_20240101_00_1min.csv (约60KB)
binance_btcusdt_20240101_01_1min.csv (约58KB)
binance_btcusdt_20240101_02_1min.csv (约62KB)
优点:文件小,加载快。可以并行处理多个小时的数据。
缺点:文件数量多,管理稍复杂。查询跨小时的数据需要合并多个文件。
避坑指南:我曾经按分钟分片,结果一天产生1440个文件。查询一天的数据要打开1440次文件,IO开销巨大。后来改成按小时分片,性能提升了一个数量级。
4.4 示例文件解析
光说不练假把式。咱们看一个实际的文件内容。
# 文件: binance_btcusdt_20240101_00_1min.csv
timestamp,price,quantity,side
1704067200000,42350.50,1.2345,bid
1704067200000,42351.00,0.8765,ask
1704067260000,42350.75,2.1000,bid
1704067260000,42351.25,1.5000,ask
1704067320000,42350.60,3.0000,bid
1704067320000,42351.10,2.2000,ask
这个文件记录了2024年1月1日0点到1点之间,每分钟的订单簿快照。每两行是一组,分别对应买一和卖一的价格和数量。
解析的时候,我一般用pandas的read_csv,指定timestamp列作为索引,这样后续做时间序列分析很方便。
import pandas as pd
df = pd.read_csv('binance_btcusdt_20240101_00_1min.csv',
parse_dates=['timestamp'],
index_col='timestamp')
# 按方向分组
bids = df[df['side'] == 'bid']
asks = df[df['side'] == 'ask']
你看,解析就这么简单。但要注意,如果文件很大,建议用chunksize参数分块读取,避免内存爆掉。
经验之谈:我刚开始做的时候,直接把所有数据读进内存,结果16GB的机器直接卡死。后来改用分块读取,再配合多进程处理,效率提升明显。
4.5 知识体系总览
下面这张图把CSV格式设计的核心逻辑串起来了。从列定义到文件命名,再到分片策略,每一步都有明确的考量。
这张图把三个核心模块的关系展示得很清楚。列定义是基础,文件命名是规范,分片策略是性能保障。三者缺一不可。
好了,CSV格式设计就聊到这儿。记住,好的格式设计能让后续的数据处理事半功倍。别小看这些细节,它们决定了你的量化系统能跑多快、多稳。