3. 特征工程(上):技术指标(均线、MACD、RSI)的计算与衍生、滞后特征与滚动窗口统计

各位同学,欢迎来到特征工程部分。说实话,在量化交易这个领域,我见过太多人把精力花在模型调参上,却忽略了最基础也最关键的环节——特征工程。你想想看,模型再牛,喂进去的是垃圾数据,出来的只能是更精致的垃圾。今天我们就来聊聊技术指标的计算与衍生,以及滞后特征和滚动窗口统计这些基本功。

3.1 技术指标:从均线说起

均线(Moving Average)是最基础的技术指标。我个人习惯把它看作是「市场的平均成本线」。简单移动平均(SMA)和指数移动平均(EMA)是两种最常见的实现方式。

SMA 的计算公式

SMA = (P1 + P2 + ... + Pn) / n

EMA 的计算公式

EMA_t = α * P_t + (1 - α) * EMA_{t-1}
其中 α = 2 / (n + 1)

我在项目中遇到过一个问题:用 SMA 做短线交易时,信号总是滞后太多。后来我改用 EMA,情况好了不少。为什么呢?因为 EMA 给近期数据赋予了更高的权重,反应更灵敏。

核心要点:均线周期选择没有标准答案。5日、10日均线适合短线,20日、60日均线适合中线,120日、250日均线适合长线。具体选哪个,得看你的交易频率。

3.2 MACD:趋势跟踪的利器

MACD(指数平滑异同移动平均线)本质上是对均线的二次加工。它由三部分组成:DIF线、DEA线和柱状线。

计算步骤

  1. 计算快线(通常12日EMA)和慢线(通常26日EMA)
  2. DIF = 快线 - 慢线
  3. DEA = DIF的9日EMA
  4. 柱状线 = (DIF - DEA) * 2

嗯,这里要注意:MACD 的默认参数(12, 26, 9)是 Gerald Appel 在1979年提出的,当时是为了分析美股。用在A股上,我个人建议把参数调小一些,比如(8, 17, 5),效果可能会更好。

实战技巧:我曾经用 MACD 底背离策略做了一波创业板,收益还不错。底背离就是价格创新低,但 MACD 的 DIF 线没有创新低。这往往预示着下跌动能衰竭。

3.3 RSI:超买超卖的判断

RSI(相对强弱指标)衡量的是价格变动的速度和幅度。它的核心思想是:在上涨行情中,收盘价上涨的幅度应该大于下跌的幅度。

计算公式

RSI = 100 - (100 / (1 + RS))
其中 RS = 平均上涨幅度 / 平均下跌幅度

标准用法是:RSI > 70 视为超买,RSI < 30 视为超卖。但我在实际交易中发现,在强趋势行情中,RSI 会长时间停留在超买或超卖区域。这时候盲目反向操作,很容易被市场打脸。

避坑指南:我曾经在2015年牛市中使用 RSI > 70 就做空,结果被连续打脸三次。后来我学乖了——在强趋势行情中,RSI 的阈值要适当放宽,比如改成 80 和 20。

3.4 滞后特征:让模型看到「过去」

滞后特征(Lag Features)就是把过去某个时间点的数据作为当前的特征。说白了,就是让模型知道「昨天发生了什么」。

常见的滞后特征

  • 滞后1日收益率:ret_1 = (close_t / close_{t-1}) - 1
  • 滞后5日收益率:ret_5 = (close_t / close_{t-5}) - 1
  • 滞后10日成交量变化:vol_10 = volume_t / volume_{t-10}

你想想看,如果只给模型当天的数据,它怎么知道趋势呢?滞后特征就是给模型装上了「后视镜」。

3.5 滚动窗口统计:捕捉局部规律

滚动窗口统计(Rolling Window Statistics)是在一个固定大小的窗口内计算统计量。这是我最喜欢用的特征工程方法之一。

常用统计量

统计量 含义 应用场景
滚动均值 窗口内价格的平均值 判断当前价格是否偏离均值
滚动标准差 窗口内价格的波动程度 衡量市场波动率
滚动最大值 窗口内的最高价 判断是否突破前高
滚动最小值 窗口内的最低价 判断是否跌破前低
滚动偏度 窗口内收益率的偏斜程度 判断市场是否处于极端状态
滚动峰度 窗口内收益率的尖峰程度 判断市场是否出现异常波动

代码示例

import pandas as pd
import numpy as np

# 假设 df 是包含收盘价的数据框
df['rolling_mean_20'] = df['close'].rolling(window=20).mean()
df['rolling_std_20'] = df['close'].rolling(window=20).std()
df['rolling_max_20'] = df['close'].rolling(window=20).max()
df['rolling_min_20'] = df['close'].rolling(window=20).min()
df['rolling_skew_20'] = df['close'].rolling(window=20).skew()
df['rolling_kurt_20'] = df['close'].rolling(window=20).kurt()

重要提醒:滚动窗口统计会产生 NaN 值。前 n-1 行(n 为窗口大小)的数据是无法计算的。处理方式有两种:要么直接丢弃,要么用向前填充。我个人建议直接丢弃,因为填充会引入未来信息。

3.6 特征衍生:组合创造价值

单一的技术指标往往不够用。把多个指标组合起来,往往能产生更好的效果。这就是特征衍生。

常见的衍生方式

  • 比值类:价格/均线、成交量/均量、RSI/RSI均线
  • 差值类:价格-均线、DIF-DEA、当前RSI-过去RSI
  • 交叉类:快线上穿慢线(金叉)、快线下穿慢线(死叉)
  • 归一化类:(价格 - 滚动均值) / 滚动标准差

举个例子,我常用的一个特征叫「价格位置」:

# 价格在20日区间内的位置
df['price_position'] = (df['close'] - df['rolling_min_20']) / (df['rolling_max_20'] - df['rolling_min_20'])

这个特征的值在0到1之间,表示当前价格在最近20天内的相对位置。0表示最低点,1表示最高点。这个特征在震荡市中特别好用。

3.7 知识体系总览

下面这张图展示了本章的核心逻辑:从原始数据出发,经过技术指标计算、滞后特征构建、滚动窗口统计,最终形成可用于模型训练的特征矩阵。

特征工程(上):技术指标与统计特征 原始行情数据 技术指标计算 滞后特征构建 滚动窗口统计 均线 (MA) MACD RSI 滞后1日、5日、10日收益率 滞后成交量、滞后波动率 均值、标准差 最大、最小值 偏度、峰度 特征衍生:比值、差值、交叉、归一化 最终特征矩阵 → 模型训练

我的经验:特征不是越多越好。我曾经在一个项目里搞了200多个特征,结果模型过拟合得一塌糊涂。后来我精简到30个核心特征,效果反而更好。记住:好的特征工程是「少而精」,不是「多而杂」。

好了,这一章的内容就到这里。技术指标的计算、滞后特征的构建、滚动窗口统计,这些都是特征工程的基本功。下一章我们会继续聊特征工程的下半部分——如何做特征筛选和降维。到时候见。

专注资料整理