3. 数据清洗与预处理:缺失值处理、异常值检测与时间对齐

高频行情数据在采集、传输与存储过程中,不可避免地会引入噪声、缺失与异常。本章聚焦于将原始Tick/快照数据转化为可用于特征工程的标准时间序列,核心步骤包括:缺失值处理、异常值检测(跳空、涨跌停)以及时间对齐与重采样。

核心原则:高频数据清洗必须兼顾“速度”与“保真度”。过度平滑会抹去微观结构信号,清洗不足则会导致特征标签失真。建议在清洗前后保留数据质量统计日志。

3.1 缺失值处理

高频数据缺失通常表现为:某笔Tick缺失、某秒无成交、或某字段(如卖一量)为空。处理策略需根据缺失模式与业务场景选择。

缺失类型 典型场景 推荐处理方法 注意事项
完全随机缺失 网络丢包导致单笔Tick丢失 前向填充(ffill) 适用于短时间间隔(< 100ms)
连续缺失 交易所断流、系统宕机 标记为缺失区间,不填充 避免引入虚假价格序列
字段级缺失 卖五价为空(流动性不足) 用卖一价 + 最小价差估算 需记录估算标记
盘口快照缺失 某时刻无买卖盘数据 线性插值(仅限价格) 量数据不建议插值
代码示例:高频缺失值处理(Python伪代码)
import pandas as pd
import numpy as np

# 假设df为包含'timestamp', 'price', 'bid1', 'ask1'的DataFrame
# 1. 前向填充:适用于毫秒级缺失
df['price_ffill'] = df['price'].fillna(method='ffill', limit=5)

# 2. 标记连续缺失区间(超过10个Tick视为无效区间)
df['missing_flag'] = df['price'].isna().astype(int)
df['missing_group'] = df['missing_flag'].ne(df['missing_flag'].shift()).cumsum()
df['missing_count'] = df.groupby('missing_group')['missing_flag'].transform('sum')
df.loc[df['missing_count'] > 10, 'price'] = np.nan  # 整段置为NaN

# 3. 盘口价格线性插值(仅限价格字段)
df['bid1_interp'] = df['bid1'].interpolate(method='linear', limit=3)
缺失值处理决策流程 原始高频数据 是否缺失? 保留原始值 判断缺失模式 前向填充 标记缺失区间 线性插值

3.2 异常值检测:跳空与涨跌停

高频数据中的异常值会严重扭曲特征分布,尤其是价格跳空和涨跌停两种场景。跳空通常由隔夜信息、重大事件或数据错误引起;涨跌停则是交易所规则导致的特殊价格状态。

3.2.1 价格跳空检测

跳空定义为相邻两笔Tick价格变化超过阈值。检测方法需区分“正常波动”与“异常跳空”。

  • 绝对阈值法:价格变化超过N个最小变动价位(Tick Size)。例如,沪深300股指期货最小变动0.2点,若相邻Tick价格变化超过10个Tick(2点),标记为跳空。
  • 相对阈值法:价格变化超过前N笔滚动均值的M倍标准差。适用于波动率突变场景。
  • 隔夜跳空:当日第一笔价格与昨日最后一笔价格之差,需单独标记,不参与日内波动统计。
注意:跳空不一定是错误数据。隔夜跳空是有效信息,应保留但单独标记;日内跳空若由撮合异常引起(如价格从10.00直接跳到10.50又跳回),应剔除或修正。

3.2.2 涨跌停状态处理

涨跌停期间,价格被锁定在涨停价或跌停价,成交量急剧萎缩,盘口挂单严重失衡。此时特征计算需特殊处理。

状态 价格特征 成交量特征 特征工程处理
涨停 最新价 = 涨停价,卖一为空 成交量极低或为0 标记涨停状态位;不计算收益率;盘口失衡指标置为极端值
跌停 最新价 = 跌停价,买一为空 成交量极低或为0 标记跌停状态位;不计算收益率;盘口失衡指标置为极端值
盘中临时停牌 价格不变,无成交 成交量为0 剔除该区间或标记为缺失
异常值检测与分类处理流程 价格序列输入 跳空检测 隔夜跳空:保留+标记 日内异常跳空:剔除 涨跌停状态标记

3.3 时间对齐与重采样

高频数据源(交易所、券商、第三方)的时间戳精度和基准可能不一致。时间对齐是将多源数据统一到同一时间轴的过程;重采样则是将不规则Tick数据转换为固定频率的时间序列。

3.3.1 时间戳标准化

  • 精度统一:将所有时间戳统一到纳秒或微秒级。Python中建议使用 pd.Timestamp 或 np.datetime64。
  • 时区处理:交易所数据通常为本地时间(如北京时间),需显式指定时区,避免夏令时或跨市场对齐错误。
  • 时钟漂移校正:对比交易所官方撮合时间与本地接收时间,若偏差超过1ms,需进行线性校正。

3.3.2 重采样策略

高频特征工程中,常用重采样频率包括:1ms、10ms、100ms、1s、5s。选择取决于策略持仓周期和信号衰减速度。

重采样频率 适用策略 OHLCV计算方式 注意事项
1ms 高频做市、逐笔统计 首笔为Open,末笔为Close 数据量极大,需压缩存储
100ms 统计套利、订单流分析 加权平均价(VWAP) 适合盘口快照对齐
1s 日内趋势、动量策略 Last + Volume累计 最常用频率,平衡精度与计算
5s 低频因子计算 标准OHLCV 适合分钟级因子回测
代码示例:1秒重采样(Python)
# 假设df包含'timestamp'(datetime), 'price', 'volume'
df.set_index('timestamp', inplace=True)

# 1秒重采样:计算OHLCV
resampled = df.resample('1S').agg({
    'price': 'ohlc',          # 生成Open, High, Low, Close
    'volume': 'sum'
})

# 展开多级列索引
resampled.columns = ['_'.join(col).strip() for col in resampled.columns.values]

# 处理空区间:无成交的秒用前向填充
resampled.fillna(method='ffill', inplace=True)

3.3.3 多源数据对齐

当同时使用逐笔成交、盘口快照和订单簿数据时,需按时间戳对齐到同一时间轴。

  • 左对齐:以成交数据时间轴为主,盘口快照取最近时刻的快照。
  • 右对齐:以盘口快照时间轴为主,成交数据聚合到快照时间点。
  • 最近邻对齐:寻找时间差最小的匹配点,适用于毫秒级精度要求。
工程建议:在分布式流处理框架(如Flink、Kafka Streams)中,建议使用事件时间(Event Time)而非处理时间(Processing Time)进行对齐,并设置合理的watermark延迟(通常为100ms-500ms)以处理乱序数据。

完成数据清洗与预处理后,高频行情数据将形成干净、连续、对齐的时间序列,为后续特征计算和标签生成奠定坚实基础。下一阶段将进入特征构造环节。