4. 数据源与数据获取

在Tick事件回放与撮合仿真中,数据源决定了回放的真实性与撮合结果的可信度。很多初学者把精力全部放在撮合算法上,却忽略了数据获取与清洗环节,最终导致回放价格跳变、时间戳乱序、成交量对不上。本节围绕“数据从哪里来、怎么下载、如何清洗、统一成什么格式”四个问题展开,帮助你搭建一条稳定可复用的数据链路。

一、核心原理:Tick数据的三种来源与数据链路

Tick数据本质上是带时间戳的逐笔成交或逐笔委托记录。按获取方式,常见数据源可分为三类:

  • 实时行情接口:交易所或行情商提供的WebSocket/TCP推送,如国内期货CTP、股票Level-2、加密货币交易所的WebSocket。特点是低延迟、字段丰富,但需要处理断线重连与订阅管理。
  • REST/HTTP历史接口:通过HTTP请求按时间区间拉取历史成交,如币安的aggTrades、部分券商的历史成交查询。适合小批量补数,但受限于频率与分页。
  • 离线历史数据文件:交易所或数据商提供的CSV、Parquet、二进制打包文件,按日或按月下载。适合大规模回测,但格式差异大、需要清洗。

无论哪种来源,最终都要经过“采集→落地→清洗→标准化→入库”这条链路。下图展示了从多源数据到统一Tick格式的完整数据流。

Tick数据获取与标准化链路 实时行情接口 WebSocket / TCP REST历史接口 HTTP分页拉取 离线数据文件 CSV / Parquet 采集与落地 断线重连 去重 / 补数 清洗与标准化 时间戳对齐 字段映射 统一 Tick 格式

二、方法流程:历史数据下载与清洗步骤

以加密货币交易所的逐笔成交为例,一个可复用的下载与清洗流程通常包含以下步骤:

  1. 确定时间范围与标的:明确交易对、起止日期,按天或按月切分,避免单次请求过大。
  2. 调用接口或下载文件:REST接口注意分页与限频;离线文件注意校验MD5,防止下载不完整。
  3. 字段映射:把不同来源的字段统一为:timestamp, symbol, price, volume, side, trade_id。
  4. 时间戳标准化:统一为毫秒或微秒UTC,避免本地时区混用。
  5. 去重与排序:按trade_id去重,按时间戳升序排列。
  6. 异常值处理:剔除价格为0、成交量为负、时间戳越界的记录。
  7. 落地存储:输出为Parquet或CSV,按日期分区,便于回放时按需加载。

下面是一段Python清洗示例,展示如何把原始DataFrame标准化为统一Tick格式:

import pandas as pd

def normalize_ticks(df, symbol):
    df = df.rename(columns={
        'T': 'timestamp', 'p': 'price', 'q': 'volume',
        'm': 'is_buyer_maker', 'a': 'trade_id'
    })
    df['symbol'] = symbol
    df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True)
    df['side'] = df['is_buyer_maker'].apply(lambda x: 'sell' if x else 'buy')
    df = df[['timestamp', 'symbol', 'price', 'volume', 'side', 'trade_id']]
    df = df.drop_duplicates(subset=['trade_id'])
    df = df[(df['price'] > 0) & (df['volume'] > 0)]
    df = df.sort_values('timestamp').reset_index(drop=True)
    return df

三、案例场景:跨交易所数据对齐

假设你要回放某标的在两个交易所的Tick,并做跨市场套利仿真。两个交易所的时间戳精度不同:A所是毫秒,B所是微秒;字段名也不同。此时标准化格式的价值就体现出来了。你需要先分别清洗,再统一到同一时间基准,最后按时间戳归并。常见做法是:

  • 统一使用UTC毫秒时间戳,微秒数据向下取整到毫秒。
  • 为每条Tick增加exchange字段,区分来源。
  • 回放时使用最小堆按时间戳合并多路数据流。
建议在清洗阶段就固定Schema,并在入库时做一次Schema校验。这样回放引擎只需面对一种格式,撮合逻辑不会被数据差异污染。

四、误区与复盘:数据清洗中最容易踩的坑

在实际项目中,以下问题反复出现,值得警惕:

误区 后果 正确做法
时间戳混用本地时区 回放顺序错乱,跨日数据错位 统一UTC,入库前校验时区
不去重直接回放 成交量虚增,撮合结果失真 按trade_id去重
忽略接口限频 请求被封,数据缺口 加退避重试与断点续传
字段含义想当然 买卖方向反了,策略反向 对照官方文档确认字段语义
清洗后不校验 脏数据流入回放,难以定位 统计缺失率、重复率、时间跨度
清洗不是一次性工作。交易所接口字段可能变更,历史文件格式也可能升级。建议把清洗脚本纳入版本管理,并对每次下载的数据生成校验报告,记录行数、时间范围、去重数量,便于复盘。

总结来说,数据源与数据获取是Tick回放与撮合仿真的地基。选择合适的数据源,建立稳定的下载与清洗流程,统一为标准Tick格式,才能让后续的回放与撮合建立在可信的数据之上。把这条链路做扎实,后面的策略验证才有意义。