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线和柱状线。
计算步骤:
- 计算快线(通常12日EMA)和慢线(通常26日EMA)
- DIF = 快线 - 慢线
- DEA = DIF的9日EMA
- 柱状线 = (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 知识体系总览
下面这张图展示了本章的核心逻辑:从原始数据出发,经过技术指标计算、滞后特征构建、滚动窗口统计,最终形成可用于模型训练的特征矩阵。
我的经验:特征不是越多越好。我曾经在一个项目里搞了200多个特征,结果模型过拟合得一塌糊涂。后来我精简到30个核心特征,效果反而更好。记住:好的特征工程是「少而精」,不是「多而杂」。
好了,这一章的内容就到这里。技术指标的计算、滞后特征的构建、滚动窗口统计,这些都是特征工程的基本功。下一章我们会继续聊特征工程的下半部分——如何做特征筛选和降维。到时候见。