4、特征工程基础:技术指标计算(均线、RSI、MACD)、滚动窗口统计量、滞后特征构建

在量化回测中,原始行情数据(开盘价、收盘价、最高价、最低价、成交量)无法直接作为 LightGBM 模型的输入。特征工程的目标是将这些原始数据转化为能够反映市场状态、趋势、动量及波动性的有效特征。本章将系统讲解三类核心特征:技术指标、滚动窗口统计量和滞后特征,并给出可直接用于回测框架的 Python 实现。

4.1 技术指标计算

技术指标是量化特征工程中最经典的组成部分。它们通过数学变换提取价格和成交量的隐含信息。以下重点介绍均线、RSI 和 MACD 三个最常用的指标。

4.1.1 移动平均线(MA)

移动平均线用于平滑价格序列,识别趋势方向。常见类型包括简单移动平均(SMA)和指数移动平均(EMA)。

类型 计算公式 特点
SMA MAt = (Pt + Pt-1 + ... + Pt-n+1) / n 等权平均,计算简单,对价格突变反应较慢
EMA EMAt = α × Pt + (1-α) × EMAt-1,α = 2/(n+1) 指数加权,近期数据权重更大,反应更灵敏
实践建议:在 LightGBM 特征中,通常同时纳入短期(如 5 日、10 日)和长期(如 20 日、60 日)均线,并计算均线之间的差值或比值(如 5日/20日 均线偏离度),以捕捉短期与长期趋势的收敛与发散。
import pandas as pd
import numpy as np

def add_ma_features(df, windows=[5, 10, 20, 60]):
    """添加简单移动平均线特征"""
    for w in windows:
        df[f'ma_{w}'] = df['close'].rolling(window=w).mean()
        # 价格与均线的偏离度
        df[f'ma_{w}_pct'] = (df['close'] - df[f'ma_{w}']) / df[f'ma_{w}']
    return df

4.1.2 相对强弱指标(RSI)

RSI 衡量价格变动的速度和幅度,用于判断超买或超卖状态。通常以 14 天为周期,RSI 值超过 70 视为超买,低于 30 视为超卖。

计算步骤:

  1. 计算每日价格变动 ΔP = Pt - Pt-1
  2. 分别计算周期内平均上涨幅度(AvgGain)和平均下跌幅度(AvgLoss)
  3. RS = AvgGain / AvgLoss
  4. RSI = 100 - (100 / (1 + RS))
def add_rsi_feature(df, period=14):
    """添加 RSI 特征"""
    delta = df['close'].diff()
    gain = delta.clip(lower=0)
    loss = -delta.clip(upper=0)
    avg_gain = gain.rolling(window=period).mean()
    avg_loss = loss.rolling(window=period).mean()
    rs = avg_gain / avg_loss
    df['rsi_14'] = 100 - (100 / (1 + rs))
    return df

4.1.3 指数平滑异同移动平均线(MACD)

MACD 由快线(DIF)、慢线(DEA)和柱状图(MACD Histogram)三部分组成,用于判断趋势的启动、延续和反转。

组件 计算方式 信号含义
DIF(快线) EMA12 - EMA26 反映短期与长期趋势的差值
DEA(慢线) DIF 的 9 日 EMA 对 DIF 的平滑处理
MACD Histogram 2 × (DIF - DEA) 柱状图由负转正为买入信号
def add_macd_features(df):
    """添加 MACD 特征"""
    exp12 = df['close'].ewm(span=12, adjust=False).mean()
    exp26 = df['close'].ewm(span=26, adjust=False).mean()
    df['macd_dif'] = exp12 - exp26
    df['macd_dea'] = df['macd_dif'].ewm(span=9, adjust=False).mean()
    df['macd_hist'] = 2 * (df['macd_dif'] - df['macd_dea'])
    return df
特征工程要点:技术指标本身是衍生特征,但在 LightGBM 中,我们还可以进一步提取指标的“形态特征”,例如:RSI 是否从低位上穿 30、MACD 柱状图是否由负转正、均线是否形成“金叉/死叉”等。这些布尔型或离散型特征对树模型的分裂非常友好。
技术指标计算流程 原始行情数据(OHLCV) 移动平均线(MA) 相对强弱指标(RSI) MACD 指标 MA_5, MA_20, 偏离度 RSI_14, 超买/超卖信号 DIF, DEA, Histogram LightGBM 特征矩阵

4.2 滚动窗口统计量

滚动窗口统计量是量化特征工程中另一类强大的工具。它们通过滑动窗口计算价格或收益率的分布特征,帮助模型捕捉市场的波动状态和极端行为。

4.2.1 常用滚动统计量

统计量 含义 典型窗口 应用场景
滚动标准差 衡量价格波动率 20 日、60 日 波动率聚集效应、风险度量
滚动偏度 衡量收益率分布不对称性 20 日、30 日 识别趋势中的非对称风险
滚动峰度 衡量收益率分布尾部厚度 20 日、30 日 捕捉极端事件概率
滚动最大值/最小值 窗口内价格极值 10 日、20 日 支撑阻力位识别
滚动分位数 当前价格在窗口内的相对位置 20 日、60 日 判断价格处于历史区间的什么位置
def add_rolling_stats(df, windows=[5, 10, 20]):
    """添加滚动窗口统计量特征"""
    for w in windows:
        # 滚动标准差(波动率)
        df[f'volatility_{w}'] = df['close'].pct_change().rolling(window=w).std()
        # 滚动偏度
        df[f'skew_{w}'] = df['close'].rolling(window=w).skew()
        # 滚动峰度
        df[f'kurt_{w}'] = df['close'].rolling(window=w).kurt()
        # 当前价格在窗口内的百分位排名
        df[f'percentile_rank_{w}'] = df['close'].rolling(window=w).apply(
            lambda x: (x[-1] - x.min()) / (x.max() - x.min()) if x.max() != x.min() else 0.5
        )
    return df
注意:滚动窗口统计量在窗口初期会产生大量 NaN 值。在回测中,必须确保模型在训练和预测时不会使用这些无效值。建议在特征工程后使用 .dropna() 或设置最小有效样本数。

4.3 滞后特征构建

滞后特征(Lag Features)是将过去时刻的变量值作为当前时刻的特征。对于时间序列预测,滞后特征是捕捉序列自相关结构的最直接方式。

4.3.1 滞后特征的类型

  • 价格滞后:过去 n 期的收盘价、开盘价等。
  • 收益率滞后:过去 n 期的对数收益率或简单收益率。
  • 成交量滞后:过去 n 期的成交量或成交额。
  • 技术指标滞后:过去 n 期的 RSI、MACD 等指标值。
def add_lag_features(df, columns=['close', 'volume', 'rsi_14'], lags=[1, 2, 3, 5, 10]):
    """添加滞后特征"""
    for col in columns:
        if col not in df.columns:
            continue
        for lag in lags:
            df[f'{col}_lag_{lag}'] = df[col].shift(lag)
    return df

4.3.2 滞后特征与差分特征

对于非平稳时间序列,直接使用价格滞后可能导致模型学习到虚假关系。通常建议将滞后特征与差分特征(一阶差分或收益率)结合使用。

特征类型 示例 平稳性 适用模型
价格滞后 close_lag_1 非平稳 需配合差分或树模型(对尺度不敏感)
收益率滞后 return_lag_1 近似平稳 通用,推荐作为主要滞后特征
差分滞后 diff_close_lag_1 近似平稳 通用,适合捕捉短期动量
滞后特征构建与时间对齐 T-4 T-3 T-2 T-1 T(当前) T+1 T+2 滞后特征映射(以 T 时刻为例) • lag_1 特征 = T-1 时刻的 close / return • lag_2 特征 = T-2 时刻的 close / return • lag_3 特征 = T-3 时刻的 close / return • lag_5 特征 = T-5 时刻的 close / return 注意事项 • 避免未来信息泄露 • 滞后阶数不宜过多 • 结合差分使用更佳 • 注意 NaN 值处理

4.4 特征组合与高阶衍生

在完成基础特征计算后,可以通过特征组合进一步提升模型表现。LightGBM 对特征交互有自动学习能力,但人工构造有意义的组合特征仍能加速收敛。

  • 比值特征:短期均线 / 长期均线、当前价格 / 滚动均值、成交量 / 滚动均值。
  • 差值特征:快线 - 慢线、当前 RSI - 过去 RSI 均值。
  • 交叉信号:均线金叉/死叉(布尔值)、MACD 柱状图由负转正(布尔值)。
  • 时序聚合:过去 n 日收益率累加、过去 n 日上涨天数占比。
def add_advanced_features(df):
    """添加高阶组合特征"""
    # 均线比值
    df['ma_ratio_5_20'] = df['ma_5'] / df['ma_20']
    # 成交量相对强度
    df['volume_ratio'] = df['volume'] / df['volume'].rolling(20).mean()
    # 过去5日上涨天数占比
    df['up_days_5'] = (df['close'].diff() > 0).rolling(5).sum() / 5
    # RSI 变化方向
    df['rsi_direction'] = np.sign(df['rsi_14'].diff())
    return df
特征工程黄金法则:在回测中,所有特征的计算必须严格基于历史数据,不得使用未来信息。建议在回测框架中实现一个统一的 compute_features(df) 函数,该函数接收截至当前时刻的数据切片,返回特征向量,确保时间序列的因果性。