3、Tick级数据清洗:去重与对齐、异常值处理、时间戳标准化
数据清洗这事儿,说实话,是整套套利模型里最枯燥但最要命的一环。我见过太多人花大把精力搞策略、调参数,结果数据源里藏着几个重复的tick,回测曲线漂亮得不行,一上实盘就崩。嗯,咱们先把地基打牢。
3.1 去重与对齐:别让同一笔交易算两次
Tick数据从交易所出来,经过行情网关、网络传输,再到你的数据库,中间可能被重复推送。我遇到过最夸张的一次,某合约在毫秒级内收到了三笔完全相同的tick——价格、成交量、时间戳一模一样。你想想看,如果不处理,套利信号会被放大三倍,这谁受得了?
去重策略
我个人习惯用「交易对 + 时间戳 + 价格 + 成交量」四元组做唯一键。为什么不用交易对+时间戳?因为同一毫秒内确实可能发生多笔不同价格的交易,直接去重会丢数据。
# 伪代码示例:tick去重逻辑
def dedup_ticks(ticks):
seen = set()
clean = []
for t in ticks:
key = (t.symbol, t.timestamp, t.price, t.volume)
if key not in seen:
seen.add(key)
clean.append(t)
return clean
时间对齐:不同合约的tick不在一个频道上
套利模型的核心是「同一时刻」的价差。但现实是,合约A的tick在09:30:00.123到达,合约B的tick在09:30:00.456到达。直接拿这两个价格算价差?那误差大了去了。
我常用的对齐方法有两种:
- 最近邻对齐:以主合约的tick时间为基准,找副合约最近的一个tick。适合流动性好的品种,误差在几毫秒内。
- 线性插值对齐:用副合约前后两个tick,按时间权重插出中间价格。适合流动性差、tick稀疏的品种。
3.2 异常值处理:那些离谱的价格从哪来的?
Tick数据里的异常值,说白了就是「一眼假」的价格。比如某合约正常在100块附近波动,突然蹦出一个1000块的tick。这种数据不处理,套利模型会以为出现了巨大的套利机会,直接冲进去接盘。
常见的异常类型
| 异常类型 | 典型特征 | 处理方式 |
|---|---|---|
| 价格跳变 | 偏离前一个tick超过N个标准差 | 用前一个tick替换,或标记为缺失 |
| 零值/负值 | 价格为0或负数 | 直接剔除,这明显是数据错误 |
| 成交量异常 | 成交量突然放大到正常值的100倍 | 结合盘口数据验证,可能是大单成交 |
| 时间戳乱序 | 后一个tick的时间早于前一个 | 按时间戳重新排序,丢弃无法修复的 |
我个人的经验是:宁可漏掉一个真异常,也别误杀一个正常tick。套利模型对价格敏感,误杀会导致价差序列出现空洞,影响后续计算。
异常检测的实操方法
最简单有效的方法——移动窗口标准差法。以当前tick为中心,取前后各50个tick,计算均值和标准差。如果当前价格偏离均值超过3倍标准差,就标记为异常。
def detect_outlier(tick, window=50, threshold=3):
# 取窗口内的价格序列
prices = [t.price for t in window_ticks]
mean = np.mean(prices)
std = np.std(prices)
if abs(tick.price - mean) > threshold * std:
return True
return False
3.3 时间戳标准化:让不同数据源说同一种语言
做套利的人,手头的数据源往往不止一个。上交所的tick时间戳是毫秒级,深交所的是微秒级,期货交易所的又是另一种格式。更头疼的是,有些数据源用UTC时间,有些用北京时间。不统一?那价差计算就是鸡同鸭讲。
标准化步骤
- 统一时区:全部转为UTC+8(北京时间),或者全部转成UTC。我个人习惯用UTC+8,因为回测时看盘时间更直观。
- 统一精度:全部转成毫秒级时间戳。微秒级精度太高,反而容易引入噪声。我一般把微秒部分四舍五入到毫秒。
- 处理闰秒:虽然概率低,但交易所确实会在某些时刻插入闰秒。遇到这种情况,直接丢弃闰秒对应的tick,或者用前后tick插值补上。
# 时间戳标准化示例
import pandas as pd
def standardize_timestamp(ts, source_tz='UTC', target_tz='Asia/Shanghai'):
# 转为datetime对象
dt = pd.to_datetime(ts, unit='ms')
# 时区转换
dt = dt.tz_localize(source_tz).tz_convert(target_tz)
# 转回毫秒时间戳
return int(dt.timestamp() * 1000)
3.4 知识体系总览
下面这张图,是我自己梳理的tick级数据清洗流程。说白了,就三步:去重对齐、异常处理、时间标准化。每一步都有坑,但踩过去之后,你的数据质量就能上一个大台阶。
数据清洗这件事,说白了就是「脏活累活」。但你想啊,如果连数据都是脏的,那模型再漂亮又有什么用?我做了这么多年量化,最大的感悟就是:花80%的时间在数据上,20%的时间在策略上,这才是正确的比例。别嫌麻烦,这一步省下来的时间,以后都会在实盘里加倍还给你。