3. 数据源获取与格式:常见Tick数据源、CSV/Parquet格式解析、数据加载与预览
Tick 数据的质量直接决定标签校准的成败,而数据源的选择与格式解析是第一步。本节将系统梳理主流 Tick 数据获取渠道、两种核心存储格式的差异,并给出标准的数据加载与预览流程。
3.1 常见Tick数据源对比
根据数据来源的权威性与覆盖范围,Tick 数据源可分为交易所直连、第三方数据商、开源社区三大类。下表从延迟、成本、数据完整性三个维度进行对比:
| 数据源类型 | 典型代表 | 延迟级别 | 成本 | 数据完整性 | 适用场景 |
|---|---|---|---|---|---|
| 交易所直连 | CME Direct、SSE L1/L2 | 微秒级 | 极高(硬件+席位费) | 完整(含撤销、错误交易) | 高频做市、算法交易 |
| 第三方数据商 | Refinitiv、Bloomberg、Wind | 毫秒级 | 高(年订阅费) | 高(清洗后,偶有缺失) | 量化研究、回测 |
| 开源/社区 | Polygon.io、Quandl、Dukascopy | 秒级 | 低(免费或按量付费) | 中等(可能存在时间戳截断) | 教学、个人策略验证 |
实操建议: 标签校准对时间戳精度要求极高,优先选择带纳秒级时间戳的交易所直连或高端第三方数据。若使用开源数据,务必先做时间戳精度校验。
3.2 CSV与Parquet格式解析
Tick 数据在存储环节最常使用 CSV(文本格式)和 Parquet(列式二进制格式)。两种格式在读写性能、压缩比、Schema 支持上差异显著。
3.2.1 格式核心差异
| 对比维度 | CSV | Parquet |
|---|---|---|
| 存储方式 | 行式文本 | 列式二进制 |
| 压缩率 | 低(通常 1:1~1:2) | 高(Snappy/ZSTD 可达 1:5~1:10) |
| 读取速度(全列) | 慢(需逐行解析) | 快(列裁剪 + 谓词下推) |
| Schema 支持 | 无(需外部定义) | 内嵌(支持嵌套、可选字段) |
| 时间戳精度 | 依赖字符串格式 | 原生支持纳秒级 |
| 典型文件大小(1天A股Tick) | ~8 GB | ~1.2 GB |
3.2.2 格式选择原则
- CSV:适合小规模数据(单日 < 500 MB)、快速预览、跨语言交换;缺点是解析慢、占用空间大。
- Parquet:适合大规模生产环境(多日/多年 Tick)、需要频繁列查询、标签校准流水线;推荐作为主存储格式。
格式转换示例(Python): 将 CSV 批量转为 Parquet,同时统一时间戳列为纳秒级整数。
import pandas as pd
import pyarrow.parquet as pq
import pyarrow as pa
# 读取CSV
df = pd.read_csv('tick_20250101.csv', parse_dates=['timestamp'])
# 转换为纳秒级整数(避免时区歧义)
df['timestamp_ns'] = df['timestamp'].astype('int64')
# 写入Parquet,使用Snappy压缩
table = pa.Table.from_pandas(df)
pq.write_table(table, 'tick_20250101.parquet', compression='snappy')
print("转换完成,压缩比:", df.memory_usage(deep=True).sum() / 1e6, "MB →",
pq.read_metadata('tick_20250101.parquet').serialized_size / 1e6, "MB")
3.3 数据加载与预览
加载 Tick 数据时,必须关注三个关键点:时间戳对齐、缺失值处理、数据类型优化。以下给出标准加载流程。
3.3.1 加载流程步骤
- 指定 Schema:提前定义每列类型(时间戳→int64/nanosecond,价格→float64,成交量→int64)。
- 分区读取:按日期或合约分区,避免一次性加载全部数据。
- 时间戳校验:检查是否有重复时间戳、时间戳倒挂(后一笔早于前一笔)。
- 预览统计:输出行数、时间范围、缺失比例、基本统计量。
3.3.2 预览代码示例
import pandas as pd
import pyarrow.parquet as pq
# 加载Parquet文件,只读取前1000行用于预览
pf = pq.ParquetFile('tick_20250101.parquet')
first_batch = next(pf.iter_batches(batch_size=1000))
df_preview = first_batch.to_pandas()
# 基础信息
print("数据概览:")
print(f" 总行数(预估): {pf.metadata.num_rows}")
print(f" 时间范围: {df_preview['timestamp_ns'].min()} ~ {df_preview['timestamp_ns'].max()}")
print(f" 列名: {df_preview.columns.tolist()}")
print(f" 缺失值统计:\n{df_preview.isnull().sum()}")
# 检查时间戳顺序
time_diff = df_preview['timestamp_ns'].diff()
print(f" 时间戳倒挂数量: {(time_diff < 0).sum()}")
print(f" 重复时间戳数量: {df_preview['timestamp_ns'].duplicated().sum()}")
3.4 数据源与格式选择决策流程
以下 SVG 流程图展示了从数据源选择到格式落地的完整决策路径,帮助你在实际项目中快速定位最优方案。
3.5 常见问题与避坑
⚠️ 时间戳陷阱: 部分第三方数据商提供的 CSV 中,时间戳为字符串格式(如 "2025-01-01 09:30:00.123456"),但实际精度只到毫秒,后三位始终为 000。加载后务必检查最小时间间隔,避免将假精度用于标签校准。
- 缺失值处理:Tick 数据中的 NaN 通常代表无交易或数据缺失,不要直接填充为 0,应标记为缺失并在校准阶段单独处理。
- 分区策略:Parquet 推荐按
date+symbol分区,避免单文件过大导致加载缓慢。 - 内存管理:加载全量 Tick 数据时,使用
pd.read_csv(..., chunksize=50000)或pq.ParquetFile().iter_batches()进行流式处理。