4、时间序列基础特征:滚动均值、滚动标准差、滚动最大值/最小值、滚动分位数

在高频行情中,原始逐笔数据或快照数据包含大量噪声和微观结构效应。直接使用原始价格或成交量进行建模,往往会导致过拟合或信号不稳定。滚动统计量(Rolling Statistics)通过对固定窗口内的数据进行局部聚合,能够有效平滑噪声、捕捉短期趋势与波动特征,是特征工程中最基础且最有效的工具之一。

4.1 滚动统计量的核心概念

滚动统计量以固定长度的滑动窗口在时间序列上逐点移动,对窗口内的子序列计算指定统计函数。窗口长度(Window Size)是唯一的关键超参数,决定了特征的时间尺度。常见窗口类型包括:

  • 滚动均值(Rolling Mean):窗口内数据的算术平均,反映局部趋势与价格中枢。
  • 滚动标准差(Rolling Std):窗口内数据的标准差,度量局部波动率与价格离散程度。
  • 滚动最大值/最小值(Rolling Max/Min):窗口内的极值,用于识别局部支撑/阻力位或价格突破。
  • 滚动分位数(Rolling Quantile):窗口内指定分位点的值(如 25%、75%),刻画局部分布形态与尾部风险。
关键原则:滚动窗口长度必须与策略交易频率匹配。对于高频 tick 级数据,常用窗口为 5、10、20、50 笔;对于 1 秒或 1 分钟快照,常用窗口为 5、10、30、60 个周期。窗口过小则噪声残留,窗口过大则信号滞后严重。

4.2 滚动统计量的计算流程

以下为滚动特征的标准计算步骤,以 Python 的 pandas 库为例:

import pandas as pd
import numpy as np

# 假设 df 包含高频行情数据,index 为时间戳,'price' 列为最新成交价
df = pd.DataFrame({
    'price': [100.1, 100.3, 100.2, 100.5, 100.4, 100.7, 100.6, 100.9, 101.0, 100.8]
})

window = 5  # 滚动窗口大小

# 滚动均值
df['rolling_mean'] = df['price'].rolling(window=window).mean()

# 滚动标准差
df['rolling_std'] = df['price'].rolling(window=window).std()

# 滚动最大值
df['rolling_max'] = df['price'].rolling(window=window).max()

# 滚动最小值
df['rolling_min'] = df['price'].rolling(window=window).min()

# 滚动分位数(25% 和 75%)
df['rolling_q25'] = df['price'].rolling(window=window).quantile(0.25)
df['rolling_q75'] = df['price'].rolling(window=window).quantile(0.75)

print(df)
工程注意:高频数据量极大,建议使用 numba 或 cython 加速滚动计算,或采用增量更新算法(如指数移动平均替代简单移动平均)以降低计算复杂度。

4.3 滚动统计量的对比与选择

特征名称 数学定义 高频行情应用场景 对噪声敏感度 信号滞后
滚动均值 \(\bar{x}_t = \frac{1}{n}\sum_{i=t-n+1}^{t} x_i\) 趋势方向、价格中枢、移动平均线 低 中
滚动标准差 \(\sigma_t = \sqrt{\frac{1}{n-1}\sum_{i=t-n+1}^{t} (x_i - \bar{x}_t)^2}\) 波动率估计、价差宽度、风险度量 中 中
滚动最大值 \(max_t = \max\{x_{t-n+1}, ..., x_t\}\) 局部阻力位、突破信号、止盈参考 高 低
滚动最小值 \(min_t = \min\{x_{t-n+1}, ..., x_t\}\) 局部支撑位、止损参考、价格回撤 高 低
滚动分位数 \(Q_p(t) = \text{第 } p \text{ 百分位}\) 分布形态、异常值检测、价差分布 中 中

4.4 滚动特征在标签优化中的作用

滚动统计量不仅作为原始特征输入模型,更常用于对标签(Label)进行预处理和优化:

  • 标签平滑:对收益率或价格变化标签应用滚动均值,减少微观噪声导致的虚假信号。
  • 波动率调整:使用滚动标准差对收益率进行标准化(Z-score),使标签在不同波动时段具有可比性。
  • 极值截断:利用滚动分位数(如 1% 和 99%)对标签进行 winsorize 处理,抑制极端值对模型训练的干扰。
  • 动态阈值:基于滚动最大值/最小值设定自适应止盈止损阈值,避免固定阈值在趋势行情中过早离场。
常见陷阱:滚动特征在窗口初期会产生 NaN 值,必须妥善处理(如填充前向值或丢弃)。此外,滚动统计量存在天然的自相关性,直接作为特征输入线性模型可能导致多重共线性,建议结合差分或正交化处理。

4.5 滚动特征计算流程示意图

下图展示了滚动统计量在时间序列上的滑动计算过程,以窗口大小为 5 的滚动均值为例:

滚动均值计算流程(窗口=5) t₁=100.1 t₂=100.3 t₃=100.2 t₄=100.5 t₅=100.4 t₆=100.7 t₇=100.6 t₈=100.9 窗口 [t₁, t₅] 滚动均值 (100.1+100.3+100.2+100.5+100.4)/5 = 100.30 窗口滑动规则 每次向前移动 1 个时间步 丢弃最旧值,加入最新值 重新计算窗口内统计量

4.6 多窗口滚动特征融合策略

单一窗口的滚动特征只能捕捉一个时间尺度的信息。高频行情特征工程中,通常采用多窗口融合策略,将不同尺度的滚动统计量拼接为高维特征向量:

# 多窗口滚动特征生成示例
windows = [5, 10, 20, 50]
for w in windows:
    df[f'mean_{w}'] = df['price'].rolling(w).mean()
    df[f'std_{w}'] = df['price'].rolling(w).std()
    df[f'max_{w}'] = df['price'].rolling(w).max()
    df[f'min_{w}'] = df['price'].rolling(w).min()
    df[f'q25_{w}'] = df['price'].rolling(w).quantile(0.25)
    df[f'q75_{w}'] = df['price'].rolling(w).quantile(0.75)
实践建议:高频行情中,建议使用指数加权移动平均(EWMA)替代简单移动平均,因其对近期数据赋予更高权重,信号响应更快。同时,滚动标准差可与滚动均值结合构造布林带(Bollinger Bands)类特征,用于识别价格突破与回归。

4.7 滚动特征与标签的联动优化

下图展示了滚动特征如何直接参与标签优化流程,形成从原始行情到优化标签的完整链路:

滚动特征驱动标签优化链路 原始行情 价格 / 成交量 / 价差 滚动特征计算 均值/标准差/极值/分位数 直接特征 输入模型 标签优化 平滑/标准化/截断 优化后标签 标签优化示例 原始收益率 → 滚动均值平滑 → 滚动标准差标准化 → 滚动分位数截断 → 优化标签

4.8 实践避坑指南

  • 数据泄露:滚动统计量必须使用历史窗口数据,严禁引入未来信息。在回测中务必使用 shift(1) 将滚动特征向后平移一个时间步,确保当前时刻的特征仅基于历史数据。
  • 窗口边界效应:窗口初期的 NaN 值建议使用 min_periods 参数控制最小有效观测数,避免过早输出不稳定统计量。
  • 计算性能:高频数据每秒可达数千笔,建议使用增量算法(如 Welford 在线算法)计算滚动均值和标准差,避免重复全量计算。
  • 特征冗余:高度相关的滚动特征(如窗口 5 和窗口 6 的均值)会导致模型过拟合,建议通过特征选择或 PCA 降维。
进阶方向:滚动统计量可与时间衰减权重结合,构造自适应窗口(如基于波动率变化动态调整窗口长度),进一步提升特征对市场状态变化的响应能力。