3、时间序列基础特征:滞后特征、滚动窗口统计、EWMA与时间差

时间序列的特征工程,说白了就是跟「过去」打交道。你想想看,金融数据里没有无缘无故的涨跌,今天的价格往往带着昨天的影子。我做了这么多年量化,最深的体会就是:时间序列的特征,核心就四个字——以史为鉴

这一章我们聊四个最基础、也最实用的时间序列特征。它们几乎出现在每一个实盘策略里,是因子挖掘的「基本功」。

3.1 滞后特征(Lag Features)

滞后特征,就是把过去某个时刻的值拿过来当特征。比如今天的收盘价,昨天的收盘价,前天的收盘价……

为什么有用? 金融市场存在记忆效应。今天的走势往往跟昨天、前天有关。我见过很多新手一上来就搞复杂的深度学习模型,结果还不如一个简单的滞后特征有效。

核心公式: Lag_k(X_t) = X_{t-k}

举个代码例子,用 pandas 实现滞后特征非常方便:

import pandas as pd
import numpy as np

# 模拟收盘价数据
df = pd.DataFrame({
    'close': [100, 102, 101, 105, 107, 106, 110]
})

# 生成滞后1天、2天、3天的特征
df['lag_1'] = df['close'].shift(1)
df['lag_2'] = df['close'].shift(2)
df['lag_3'] = df['close'].shift(3)

print(df)

输出结果:

   close  lag_1  lag_2  lag_3
0    100    NaN    NaN    NaN
1    102  100.0    NaN    NaN
2    101  102.0  100.0    NaN
3    105  101.0  102.0  100.0
4    107  105.0  101.0  102.0
5    106  107.0  105.0  101.0
6    110  106.0  107.0  105.0
注意: 滞后特征会产生 NaN 值。前 k 行数据会缺失,需要做填充或删除处理。我个人习惯用前向填充(ffill)或者直接丢弃前几行。

我曾经在一个高频策略里,只用了 lag_1 到 lag_5 这5个特征,加上一个简单的线性回归,就跑出了不错的夏普比率。你想想看,有时候简单的东西反而更稳健。

3.2 滚动窗口统计(Rolling Mean / Std)

滚动窗口统计,就是在一个固定大小的窗口内计算统计量。最常见的两个:滚动均值滚动标准差

滚动均值可以平滑噪声,识别趋势。滚动标准差则衡量波动率。这两个在风控和择时里都是标配。

核心公式: RollingMean_t = (1/w) * Σ_{i=t-w+1}^{t} X_i

代码实现:

# 计算5日滚动均值和标准差
df['rolling_mean_5'] = df['close'].rolling(window=5).mean()
df['rolling_std_5'] = df['close'].rolling(window=5).std()

print(df[['close', 'rolling_mean_5', 'rolling_std_5']])

输出:

   close  rolling_mean_5  rolling_std_5
0    100             NaN            NaN
1    102             NaN            NaN
2    101             NaN            NaN
3    105             NaN            NaN
4    107           103.0       2.915476
5    106           104.2       2.588436
6    110           105.8       3.563706
小技巧: 窗口大小的选择很关键。太小的窗口容易受噪声干扰,太大的窗口反应迟钝。我一般会尝试 5、10、20、60 这几个窗口,然后看哪个在回测中表现最好。

除了均值和标准差,滚动窗口还可以计算最大值、最小值、中位数、偏度、峰度等。但说实话,均值和标准差是最稳定、最不容易过拟合的。我在实盘里很少用滚动偏度这类高阶统计量,因为样本量不够时它们很不稳定。

3.3 指数加权移动平均(EWMA)

EWMA 跟滚动均值很像,但有一个关键区别:它给近期的数据更高的权重。越老的数据权重越小,呈指数衰减。

为什么需要 EWMA?因为金融市场里,今天的行情比10天前的行情更重要。滚动均值对所有数据一视同仁,这其实不太合理。

核心公式: EWMA_t = α * X_t + (1-α) * EWMA_{t-1}

其中 α 是平滑系数,取值范围 (0, 1)。α 越大,对近期数据越敏感。

代码实现:

# 计算 EWMA,alpha=0.3
df['ewma_0.3'] = df['close'].ewm(alpha=0.3, adjust=False).mean()

# 也可以指定 span(相当于窗口大小)
df['ewma_span_5'] = df['close'].ewm(span=5, adjust=False).mean()

print(df[['close', 'ewma_0.3', 'ewma_span_5']])

输出:

   close  ewma_0.3  ewma_span_5
0    100  100.0000   100.000000
1    102  100.6000   100.666667
2    101  100.7200   100.777778
3    105  102.0040   102.185185
4    107  103.5028   103.790123
5    106  104.2520   104.526749
6    110  105.9764   106.351166
避坑指南: 我曾经在回测里直接用 ewm().mean() 没加 adjust=False 参数,结果发现前几期的权重计算方式跟预期不一样,导致回测结果有偏差。建议做量化时统一用 adjust=False,这样公式更直观。

EWMA 在实战中非常常用。比如很多技术指标(MACD、布林带)底层用的就是 EWMA。我个人习惯用 EWMA 替代简单滚动均值,因为它更符合「近因效应」的直觉。

3.4 时间差特征(Time Delta Features)

时间差特征,就是计算两个时间点之间的间隔。这在金融数据里太常见了:

  • 距离上一次交易的时间
  • 距离上一次涨停/跌停的时间
  • 距离财报发布的时间
  • 相邻两笔交易的时间间隔

时间差特征能捕捉到「事件密度」和「节奏变化」。比如,如果某只股票突然交易频率变高,往往意味着有大事发生。

代码示例:

# 模拟带时间戳的数据
df_time = pd.DataFrame({
    'timestamp': pd.to_datetime([
        '2024-01-01 09:30:00',
        '2024-01-01 09:30:05',
        '2024-01-01 09:30:12',
        '2024-01-01 09:30:20',
        '2024-01-01 09:30:35'
    ]),
    'price': [100, 101, 102, 101, 103]
})

# 计算相邻时间差(秒)
df_time['time_diff'] = df_time['timestamp'].diff().dt.total_seconds()

print(df_time)

输出:

            timestamp  price  time_diff
0 2024-01-01 09:30:00    100        NaN
1 2024-01-01 09:30:05    101        5.0
2 2024-01-01 09:30:12    102        7.0
3 2024-01-01 09:30:20    101        8.0
4 2024-01-01 09:30:35    103       15.0
实战经验: 时间差特征在「事件驱动策略」里特别好用。比如,距离上一次大单成交的时间越短,说明当前交易越活跃。我曾经用这个特征配合成交量,构建了一个短线择时因子,效果出奇的好。

知识体系总览

下面这张图总结了本章的核心内容,帮你快速建立框架:

时间序列基础特征知识体系 时间序列基础特征 滞后特征 (Lag) 滚动窗口统计 指数加权移动平均 时间差特征 shift(1), shift(2), ... 捕捉序列记忆效应 rolling(5).mean() 平滑噪声 / 衡量波动 ewm(alpha=0.3).mean() 近因效应 / 指数衰减 diff().dt.total_seconds() 事件密度 / 节奏变化 核心思想:以史为鉴,用过去的信息预测未来 实战中常组合使用,如 Lag + Rolling + EWMA 多维度刻画

实战要点总结

嗯,到这里四个基础特征就讲完了。最后我分享几个实战中的要点:

  • 不要贪多:滞后特征不是越多越好。我见过有人一口气生成 lag_1 到 lag_100,结果模型严重过拟合。一般 lag_1 到 lag_5 就够用了。
  • 注意数据泄露:滚动窗口和 EWMA 在计算时,一定要确保只用到了历史数据。pandas 默认是左闭右开的,但如果你不小心用了未来数据,回测结果就是假的。
  • 组合使用效果更好:比如用 EWMA 作为趋势信号,用滚动标准差作为波动率信号,两者结合可以构建一个简单的均值回归策略。
  • 时间差特征别忽略:很多人在做特征工程时只关注价格和成交量,却忘了时间本身就是一个重要维度。尤其是在高频数据里,时间差特征往往能带来意想不到的收益。
一句话总结: 滞后特征看过去,滚动窗口看局部,EWMA 看加权,时间差看节奏。把这四个基本功练扎实了,后面的因子挖掘才能站得稳。

公众号:蓝海资料掘金营,微信deep3321