3. 异常Tick类型
在Tick级数据处理中,“异常”并不是一个笼统的概念。不同字段的异常,其成因、识别手段和修复策略差异极大。本节将异常Tick划分为三大类:价格异常(跳空、零价、负价)、成交量异常(突增、突降、零量)以及时间戳异常。理解这三类异常的本质,是后续编写识别规则与修复逻辑的前提。
一、价格异常:跳空、零价与负价
价格是Tick最核心的字段,其异常通常表现为三种形态。跳空指相邻两笔Tick价格出现远超正常波动范围的跃迁,例如上一笔10.00元、下一笔10.80元,中间无过渡。它可能源于真实行情(如集合竞价、涨跌停打开),也可能是数据源拼接错误。零价即价格字段为0或极小值,常见于行情源初始化、字段缺失被默认填充。负价在股票中几乎不可能,但在原油期货等品种中曾真实出现,因此不能简单一律判为错误,需结合品种规则判断。
识别价格异常时,建议同时维护两个维度:绝对边界与相对跳变。绝对边界用于拦截零价、负价及超出涨跌停的价格;相对跳变用于捕捉跳空。下面是一段典型的识别伪代码:
def check_price(tick, prev_tick, limit_up, limit_down):
if tick.price <= 0:
return "ZERO_OR_NEGATIVE"
if tick.price > limit_up or tick.price < limit_down:
return "OUT_OF_LIMIT"
if prev_tick:
jump = abs(tick.price - prev_tick.price) / prev_tick.price
if jump > 0.10: # 单笔跳变超过10%
return "PRICE_JUMP"
return "OK"
二、成交量异常:突增、突降与零量
成交量异常往往比价格异常更隐蔽。突增可能是真实的大单成交,也可能是重复推送或字段错位;突降常出现在数据源切换、撮合延迟场景;零量则需区分“真实无成交”与“字段缺失”。关键思路是:不要用固定阈值,而应基于同标的近N笔Tick的成交量分布建立动态基线,例如使用中位数与MAD(绝对中位差)构造稳健区间。
| 异常类型 | 典型表现 | 常见成因 | 识别要点 |
|---|---|---|---|
| 价格跳空 | 相邻Tick价差超阈值 | 拼接错误、集合竞价 | 相对跳变+时段判断 |
| 零价/负价 | price ≤ 0 | 字段缺失、初始化 | 绝对边界拦截 |
| 成交量突增 | volume远超近期基线 | 大单、重复推送 | MAD稳健区间 |
| 成交量突降 | volume骤降至接近0 | 数据源切换、延迟 | 连续多笔确认 |
| 零量 | volume = 0 | 无成交或字段缺失 | 结合价格是否变化 |
| 时间戳异常 | 乱序、重复、越界 | 时钟漂移、多源合并 | 单调性+时段校验 |
三、时间戳异常:乱序、重复与越界
时间戳异常是三类中最容易被忽视、却对回测影响最大的一类。它主要表现为:乱序(后到的Tick时间戳早于前一笔)、重复(同一时间戳出现多笔相同数据)、越界(时间戳落在非交易时段或未来时间)。乱序会破坏事件驱动回测的因果顺序,重复会导致成交量被重复累计,越界则可能让策略在错误的时间窗口触发。
处理时间戳异常时,应坚持“先校验、后排序、再去重”的流程。校验阶段检查单调性与交易时段;排序阶段对局部乱序窗口重排;去重阶段依据“时间戳+价格+成交量”组合键剔除完全重复记录。需要注意的是,排序窗口不宜过大,否则会引入未来信息,造成回测虚高。
四、案例与复盘:一次典型的复合异常
某期货主力合约在夜盘开盘瞬间出现连续5笔Tick:价格从4200跳至0,再跳回4210,成交量分别为0、500、0、0、800,时间戳出现两笔完全相同。这是一个典型的复合异常:零价、零量、重复时间戳同时出现。若只按单一规则处理,可能只修复价格而保留重复时间戳,导致后续成交量统计翻倍。
正确的复盘流程是:先按时间戳去重,再对零价Tick做前值填充或标记剔除,最后用MAD基线判断500和800是否为真实大单。复盘时要记录每一步的处理动作与影响范围,形成可追溯的修复日志:
[FIX] ts=1698768000.123 dup_removed=1
[FIX] ts=1698768000.125 price=0 -> filled with prev=4200
[FIX] ts=1698768000.130 volume=500 flagged as OUTLIER, kept
[FIX] ts=1698768000.130 volume=800 flagged as OUTLIER, kept
综上,价格、成交量、时间戳三类异常各有其识别逻辑与修复边界。价格异常重在边界与跳变,成交量异常重在分布与基线,时间戳异常重在顺序与时段。只有分别建模、组合校验,才能为后续的Tick修复与回测打下可靠基础。