4. 数据清洗基础:缺失值处理、异常值检测(价格跳变、零成交量)、时间戳对齐与重采样

Tick 数据在采集、传输与存储过程中极易受到市场噪声、系统延迟及交易所规则的影响,产生缺失值、异常记录与时间戳错位。本章将系统讲解三类核心清洗操作,确保后续标签校准建立在干净、连续、可对齐的数据基础之上。

4.1 缺失值处理

Tick 数据中的缺失值通常表现为某一行或连续多行的时间戳、价格、成交量字段为空。缺失原因包括:交易所撮合引擎在无成交时跳过推送、网络丢包、数据库写入失败等。

处理原则: 对于 Tick 级别的金融时间序列,禁止直接删除缺失行,因为删除会破坏时间轴的连续性,导致后续重采样与标签计算出现偏差。应优先采用前向填充(Forward Fill)或线性插值。

4.1.1 缺失值分类与处理策略

缺失类型 典型场景 推荐处理方式
单点价格缺失 某笔成交记录缺少价格字段 前向填充(Last Observation Carried Forward)
连续多笔缺失 网络中断导致 3-5 秒无数据 线性插值(Linear Interpolation)
成交量缺失 价格存在但成交量为 0 或空 填充为 0(表示无成交)
时间戳缺失 整行记录的时间戳为空 删除该行(时间戳是索引基础)

4.1.2 前向填充与线性插值代码示例

import pandas as pd
import numpy as np

# 示例:模拟 Tick 数据
tick_data = pd.DataFrame({
    'timestamp': pd.to_datetime(['2024-01-10 09:30:00.000',
                                 '2024-01-10 09:30:00.100',
                                 '2024-01-10 09:30:00.200',
                                 '2024-01-10 09:30:00.300']),
    'price': [100.50, np.nan, 100.55, np.nan],
    'volume': [100, 50, np.nan, 80]
})

# 前向填充价格
tick_data['price_ffill'] = tick_data['price'].ffill()

# 线性插值价格(适用于连续缺失)
tick_data['price_interp'] = tick_data['price'].interpolate(method='linear')

# 成交量缺失填充为 0
tick_data['volume_filled'] = tick_data['volume'].fillna(0)

print(tick_data)

4.2 异常值检测:价格跳变与零成交量

异常值会严重扭曲标签校准结果。Tick 数据中最常见的两类异常是价格跳变(Price Spike)和零成交量(Zero Volume)。

4.2.1 价格跳变检测

价格跳变指相邻 Tick 之间的价格变化幅度远超正常市场波动范围,通常由数据录入错误或撮合异常引起。检测方法包括固定阈值法和滚动统计法。

滚动 Z-Score 法: 计算过去 N 个 Tick 的价格变化均值和标准差,若当前价格变化超过 3 倍标准差,则标记为跳变。
def detect_price_spike(series, window=20, threshold=3):
    """基于滚动 Z-Score 检测价格跳变"""
    returns = series.pct_change().dropna()
    rolling_mean = returns.rolling(window).mean()
    rolling_std = returns.rolling(window).std()
    z_scores = (returns - rolling_mean) / rolling_std
    return z_scores.abs() > threshold

# 标记异常
tick_data['is_spike'] = detect_price_spike(tick_data['price_ffill'])

4.2.2 零成交量处理

零成交量记录表示该 Tick 时间点没有实际成交。在标签校准中,零成交量记录不应参与价格变化计算,但保留时间戳用于对齐。

场景 处理方式
零成交量且价格与前一笔相同 保留,视为无成交的报价更新
零成交量但价格发生跳变 标记为可疑记录,需人工复核
连续多笔零成交量 保留时间戳,但计算标签时跳过

4.3 时间戳对齐与重采样

不同数据源(交易所、券商、第三方数据商)的时间戳精度和基准可能不一致。时间戳对齐是构建统一标签样本的前提。

4.3.1 时间戳对齐策略

  • 最近邻对齐: 将每个 Tick 的时间戳对齐到最近的整数毫秒或微秒。
  • 向前对齐: 将时间戳向下取整到指定精度(如 100ms 桶)。
  • 向后对齐: 将时间戳向上取整到指定精度。

4.3.2 重采样方法

重采样将不规则 Tick 数据转换为固定频率的时间序列,是标签校准的标准前置步骤。

# 设置时间戳为索引
tick_data.set_index('timestamp', inplace=True)

# 重采样为 100ms 频率,使用前向填充
resampled = tick_data.resample('100ms').ffill()

# 重采样为 1s 频率,使用 OHLC 聚合
ohlc = tick_data['price_ffill'].resample('1s').ohlc()
volume_sum = tick_data['volume_filled'].resample('1s').sum()
注意: 重采样频率的选择需与交易品种的流动性匹配。对于高频合约(如股指期货),推荐 100ms-500ms;对于低频合约(如部分债券),推荐 1s-5s。过高的重采样频率会引入大量空值,过低则会丢失微观结构信息。

4.4 数据清洗流程总览

Tick 数据清洗流程 原始 Tick 数据 缺失值处理 异常值检测 时间戳对齐 重采样 干净 Tick 数据 输出:固定频率、无缺失、无异常

4.5 清洗效果评估指标

完成清洗后,建议使用以下指标评估清洗质量:

指标 计算公式 合格标准
缺失率 缺失行数 / 总行数 × 100% < 0.1%
异常率 标记为异常的行数 / 总行数 × 100% < 0.05%
时间戳连续性 相邻 Tick 时间差的标准差 标准差 < 重采样间隔的 50%
数据保留率 清洗后行数 / 原始行数 × 100% > 99.5%
最佳实践: 建议将清洗逻辑封装为可复用的 Pipeline 函数,每次处理新数据时自动生成清洗报告,包含缺失率、异常率、时间戳连续性等关键指标,便于快速定位数据质量问题。