3. 单变量衍生:基于时间序列的滞后变量、移动平均、差分与对数收益率计算
单变量衍生是量化特征工程中最基础、最常用的技术。它仅利用单个时间序列变量自身的历史信息,通过数学变换生成新的预测因子。本章聚焦于四种核心方法:滞后变量、移动平均、差分与对数收益率。这些方法能够有效捕捉时间序列中的动态模式、趋势与波动,为后续的因子分箱与模型训练提供高质量输入。
3.1 滞后变量 (Lag Variables)
滞后变量是时间序列预测的基石。它通过将当前时刻的值与过去某一时刻的值对齐,构建起历史与未来的映射关系。在量化交易中,我们常用滞后变量来捕捉价格动量、反转效应或技术指标的滞后影响。
3.1.1 定义与计算
对于时间序列 X_t,滞后 k 期的变量定义为:
Lag_k(X_t) = X_{t-k}
其中 k 为滞后阶数,通常取 1, 2, 3, 5, 10, 20 等整数。在 Python 中,使用 pandas 的 shift() 函数可以轻松实现:
import pandas as pd
# 假设 df 包含日度收盘价 'close'
df['lag_1'] = df['close'].shift(1) # 前一交易日收盘价
df['lag_5'] = df['close'].shift(5) # 5 个交易日前收盘价
df['lag_20'] = df['close'].shift(20) # 20 个交易日前收盘价
3.1.2 应用场景与注意事项
| 场景 | 典型滞后阶数 | 说明 |
|---|---|---|
| 短期动量 | 1, 2, 3 | 捕捉隔夜或近几日的价格延续效应 |
| 周度反转 | 5, 10 | 识别一周或两周内的价格反转信号 |
| 月度效应 | 20, 22 | 考察月度级别的日历效应或趋势 |
| 技术指标滞后 | 根据指标周期 | 如 MACD 信号线滞后、布林带宽度滞后 |
shift() 时,默认会引入 NaN 值,需在后续处理中妥善填充或删除。
3.2 移动平均 (Moving Average)
移动平均是平滑时间序列、去除噪声、识别趋势的经典工具。它通过计算固定窗口内数据的平均值,生成一条平滑曲线,帮助交易者过滤掉短期随机波动。
3.2.1 简单移动平均 (SMA) 与指数移动平均 (EMA)
简单移动平均 (SMA) 对窗口内所有数据赋予相同权重:
SMA_n(X_t) = (X_t + X_{t-1} + ... + X_{t-n+1}) / n
指数移动平均 (EMA) 则赋予近期数据更高的权重,对价格变化反应更灵敏:
EMA_n(X_t) = α * X_t + (1 - α) * EMA_n(X_{t-1})
其中 α = 2 / (n + 1)
Python 实现:
# 简单移动平均
df['sma_20'] = df['close'].rolling(window=20).mean()
# 指数移动平均
df['ema_20'] = df['close'].ewm(span=20, adjust=False).mean()
3.2.2 移动平均的衍生因子
除了作为平滑值本身,移动平均还常用于构建以下衍生因子:
- 价格与均线偏离度:
(close - sma_20) / sma_20,衡量价格相对于均线的乖离率。 - 均线交叉信号: 短期均线上穿/下穿长期均线,如
ema_12与ema_26的金叉/死叉。 - 均线斜率: 计算均线自身的一阶差分,反映趋势的加速度。
3.3 差分 (Difference)
差分运算是将非平稳时间序列转化为平稳序列的常用手段,同时也能直接度量变量的变化量。一阶差分计算相邻两期值的差值,二阶差分则对一阶差分结果再次差分。
3.3.1 一阶差分与高阶差分
# 一阶差分:今日收盘价 - 昨日收盘价
df['diff_1'] = df['close'].diff(1)
# 二阶差分:一阶差分的差分
df['diff_2'] = df['close'].diff(2)
# 多期差分:今日收盘价 - 5 日前收盘价
df['diff_5'] = df['close'].diff(5)
3.3.2 差分因子的应用
| 差分类型 | 含义 | 典型应用 |
|---|---|---|
| 一阶差分 | 绝对价格变化 | 衡量日度涨跌幅度,构建日内波动率因子 |
| 多期差分 | 累计价格变化 | 捕捉周度、月度累计收益,用于动量/反转策略 |
| 二阶差分 | 变化率的变化 | 识别价格加速度,用于判断趋势拐点 |
3.4 对数收益率 (Log Return)
对数收益率是量化金融中衡量资产收益的标准方法。与简单收益率相比,对数收益率具有时间可加性、近似正态分布等优良统计性质,更适合用于建模与统计分析。
3.4.1 定义与计算
对数收益率定义为:
r_t = ln(P_t) - ln(P_{t-1}) = ln(P_t / P_{t-1})
Python 实现:
import numpy as np
# 计算日度对数收益率
df['log_return'] = np.log(df['close'] / df['close'].shift(1))
# 计算多期对数收益率(5日)
df['log_return_5'] = np.log(df['close'] / df['close'].shift(5))
3.4.2 对数收益率的优势
- 时间可加性: 多期对数收益率等于单期对数收益率之和,便于计算任意区间的累计收益。
- 分布对称性: 对数收益率在统计上更接近正态分布,有利于使用基于正态假设的统计模型。
- 数值稳定性: 对数变换压缩了极端值的影响,减少了异常值对模型的干扰。
3.4.3 对数收益率 vs 简单收益率
| 对比维度 | 对数收益率 | 简单收益率 |
|---|---|---|
| 计算公式 | ln(P_t / P_{t-1}) | (P_t - P_{t-1}) / P_{t-1} |
| 时间可加性 | ✅ 可加 | ❌ 不可加 |
| 取值范围 | (-∞, +∞) | [-1, +∞) |
| 分布特征 | 近似正态 | 左偏、有界 |
| 多期计算 | 直接求和 | 需连乘后减1 |
3.5 单变量衍生流程总览
下图展示了从原始价格序列到四种核心衍生因子的完整计算流程:
3.6 实战案例:基于沪深300指数的因子衍生
以下代码演示了如何对沪深300指数日度收盘价数据,批量生成上述四种单变量衍生因子:
import pandas as pd
import numpy as np
# 模拟沪深300指数日度数据
dates = pd.date_range('2020-01-01', '2023-12-31', freq='B')
np.random.seed(42)
price = 4000 + np.cumsum(np.random.randn(len(dates)) * 10)
df = pd.DataFrame({'date': dates, 'close': price})
df.set_index('date', inplace=True)
# 1. 滞后变量
df['lag_1'] = df['close'].shift(1)
df['lag_5'] = df['close'].shift(5)
df['lag_20'] = df['close'].shift(20)
# 2. 移动平均
df['sma_20'] = df['close'].rolling(20).mean()
df['ema_20'] = df['close'].ewm(span=20, adjust=False).mean()
df['ma_deviation'] = (df['close'] - df['sma_20']) / df['sma_20']
# 3. 差分
df['diff_1'] = df['close'].diff(1)
df['diff_5'] = df['close'].diff(5)
df['diff_accel'] = df['diff_1'].diff(1) # 二阶差分
# 4. 对数收益率
df['log_return'] = np.log(df['close'] / df['close'].shift(1))
df['log_return_5'] = np.log(df['close'] / df['close'].shift(5))
# 查看衍生因子统计摘要
print(df.iloc[:, 1:].describe())
3.7 本章小结
单变量衍生是量化因子工程的起点,其核心在于利用时间序列的自相关结构提取预测信息。本章详细介绍了四种基础方法:
- 滞后变量:构建历史与未来的直接映射,捕捉序列的短期记忆性。
- 移动平均:平滑噪声、识别趋势,并衍生出乖离率、交叉信号等高级因子。
- 差分:度量变化量与变化加速度,是平稳化处理与动量刻画的基础。
- 对数收益率:标准化收益度量,具备优良的统计性质,是量化建模的首选收益形式。