3. Tick数据预处理:缺失值处理、异常值检测、时间戳对齐与重采样

Tick 数据是逐笔成交或逐笔报价的原始记录,具有高频、非等间隔、数据量大的特点。在将 Tick 数据用于模型训练之前,必须进行严格的预处理,否则原始数据中的噪声、缺失和错位会直接污染标签,导致模型学到虚假规律。本章围绕四个核心环节展开:缺失值处理、异常值检测、时间戳对齐与重采样。

3.1 缺失值处理

Tick 数据缺失通常由网络延迟、交易所撮合间隙或记录系统故障引起。缺失值处理不当会破坏时间序列的连续性,影响后续特征计算(如收益率、波动率)。

关键原则: Tick 数据缺失不能简单删除或填充均值,必须根据缺失模式选择策略。
缺失类型 典型场景 推荐处理方式
单点缺失 某一毫秒的成交价/量缺失 前向填充(ffill)或线性插值
连续缺失(短) 连续 3-5 笔缺失 线性插值或样条插值
连续缺失(长) 超过 10 笔缺失 标记为缺失区间,不填充;或使用前一交易日同期数据
盘前/盘后缺失 非交易时段无数据 保留自然缺失,不填充
# 示例:前向填充与线性插值
import pandas as pd

# 假设 tick_df 包含 'timestamp', 'price', 'volume' 列
tick_df.set_index('timestamp', inplace=True)

# 前向填充(适用于单点缺失)
tick_df['price'].fillna(method='ffill', inplace=True)

# 线性插值(适用于短连续缺失)
tick_df['price'].interpolate(method='linear', inplace=True)

# 标记长连续缺失区间
missing_mask = tick_df['price'].isna()
long_gap = missing_mask.rolling(window=10).sum() >= 10
tick_df.loc[long_gap, 'price_missing_flag'] = 1

3.2 异常值检测

Tick 数据中的异常值通常由错误报价、胖手指交易或数据记录错误引起。异常值会严重扭曲统计特征和模型训练结果,必须在预处理阶段识别并处理。

注意: 不要将市场剧烈波动时的真实大单误判为异常值。异常值检测应结合市场微观结构特征。

常用检测方法

  • 固定阈值法: 价格超出合理范围(如涨跌停板)直接剔除。
  • 移动窗口 Z-score: 以当前点前后 N 笔数据计算均值和标准差,若 |Z| > 3 则标记为异常。
  • 中位数绝对偏差(MAD): 对极端值更稳健,适合 Tick 数据。
  • 价格反转检验: 若当前价格相对前一笔变化超过阈值(如 1%),且下一笔立即大幅回调,则当前笔可能为异常。
# 示例:移动窗口 Z-score 异常值检测
window = 20
tick_df['rolling_mean'] = tick_df['price'].rolling(window).mean()
tick_df['rolling_std'] = tick_df['price'].rolling(window).std()
tick_df['z_score'] = (tick_df['price'] - tick_df['rolling_mean']) / tick_df['rolling_std']
tick_df['is_outlier'] = tick_df['z_score'].abs() > 3

# 异常值处理:用窗口内中位数替换
tick_df.loc[tick_df['is_outlier'], 'price'] = tick_df['price'].rolling(window).median()
Tick 数据异常值检测流程 原始 Tick 数据 固定阈值过滤 移动窗口 Z-score MAD 稳健检测 价格反转检验 综合判定 清洗后 Tick 数据

3.3 时间戳对齐

不同数据源(交易所、券商、第三方数据商)的时间戳精度和时区可能不一致。时间戳对齐是确保多源 Tick 数据在时间轴上正确匹配的前提。

对齐要点

  • 统一精度: 将所有时间戳转换为同一精度(如毫秒或微秒),避免精度截断导致错位。
  • 时区归一化: 统一转换为 UTC 或交易所本地时间,消除夏令时影响。
  • 去重与排序: 同一毫秒内出现多条记录时,按接收顺序保留或聚合。
  • 对齐到标准时钟: 将 Tick 时间戳对齐到最近的整毫秒或整微秒边界。
# 示例:时间戳对齐与去重
tick_df['timestamp'] = pd.to_datetime(tick_df['timestamp'], unit='ms')
tick_df.set_index('timestamp', inplace=True)

# 对齐到整毫秒(向下取整)
tick_df.index = tick_df.index.floor('1ms')

# 去重:同一毫秒内取最后一条记录
tick_df = tick_df[~tick_df.index.duplicated(keep='last')]

# 排序
tick_df.sort_index(inplace=True)

3.4 重采样

重采样是将非等间隔的 Tick 数据转换为等间隔时间序列的过程。这是连接 Tick 数据与下游模型(如 LSTM、Transformer)的关键步骤。

实践建议: 重采样频率的选择取决于交易频率和模型需求。高频策略常用 100ms、500ms、1s;中低频策略常用 1min、5min。

常用重采样方法

方法 描述 适用场景
最后价格法 取采样区间内最后一笔成交价 生成 OHLC 数据
成交量加权平均 以成交量为权重计算平均价格 反映真实成交成本
时间加权平均 以时间间隔为权重计算平均价格 消除成交量不均匀的影响
Tick 计数 统计区间内 Tick 笔数 衡量市场活跃度
# 示例:1秒重采样生成 OHLC 数据
resampled = tick_df['price'].resample('1S').ohlc()
resampled['volume'] = tick_df['volume'].resample('1S').sum()
resampled['vwap'] = (tick_df['price'] * tick_df['volume']).resample('1S').sum() / resampled['volume']
Tick 数据重采样流程 非等间隔 Tick 数据 t1: 09:30:00.123 t2: 09:30:00.456 t3: 09:30:00.789 t4: 09:30:01.012 t5: 09:30:01.345 ... 重采样引擎 频率:1秒 / 100ms 方法:OHLC / VWAP 等间隔时间序列 09:30:00: O=100.1 09:30:01: O=100.3 09:30:02: O=100.2 09:30:03: O=100.5 09:30:04: O=100.4 ...

3.5 预处理流程总结

完整的 Tick 数据预处理管线应按照以下顺序执行:

  1. 时间戳对齐与去重 — 统一精度、时区,去除重复记录。
  2. 缺失值处理 — 根据缺失长度选择填充或标记。
  3. 异常值检测与处理 — 多方法综合判定,避免误杀。
  4. 重采样 — 转换为等间隔时间序列,供模型使用。
核心要点: 预处理的质量直接决定标签校准的准确性。在 Tick 数据上,一个未被处理的异常值可能导致整个标签窗口的偏移。建议在预处理后增加数据质量报告(缺失率、异常率、时间戳连续性指标),作为模型训练前的最后一道检查。