第三节:特征工程基础——技术指标计算与数据预处理
各位同学,欢迎来到特征工程这一章。说实话,在量化交易里,模型选得再好,特征不行也是白搭。我见过太多人一上来就堆几百个特征,结果过拟合得一塌糊涂。今天咱们就聊聊,怎么从原始行情数据里,提炼出真正有用的特征。
3.1 技术指标计算:经典指标的实战用法
技术指标这东西,很多人觉得老掉牙。但我个人习惯是,先用经典指标打个底,再考虑上复杂特征。毕竟,这些指标经过了市场几十年的检验,不是没道理的。
3.1.1 移动平均线(MA)
MA 说白了就是过去 N 天的平均价格。它帮我们平滑掉短期的噪音,看清趋势方向。
import pandas as pd
import numpy as np
# 假设 df 包含 'close' 列
df['MA5'] = df['close'].rolling(window=5).mean()
df['MA20'] = df['close'].rolling(window=20).mean()
df['MA60'] = df['close'].rolling(window=60).mean()
3.1.2 MACD 指标
MACD 是均线的升级版。它通过快慢线的交叉和柱状图的变化,帮我们判断动能的强弱。
def compute_macd(df, fast=12, slow=26, signal=9):
df['EMA_fast'] = df['close'].ewm(span=fast, adjust=False).mean()
df['EMA_slow'] = df['close'].ewm(span=slow, adjust=False).mean()
df['DIF'] = df['EMA_fast'] - df['EMA_slow']
df['DEA'] = df['DIF'].ewm(span=signal, adjust=False).mean()
df['MACD'] = 2 * (df['DIF'] - df['DEA'])
return df
3.1.3 RSI 相对强弱指标
RSI 衡量的是过去一段时间内,价格上涨和下跌的力度对比。说白了,就是看市场是「买过头」了还是「卖过头」了。
def compute_rsi(df, period=14):
delta = df['close'].diff()
gain = (delta.where(delta > 0, 0)).rolling(window=period).mean()
loss = (-delta.where(delta < 0, 0)).rolling(window=period).mean()
rs = gain / loss
df['RSI'] = 100 - (100 / (1 + rs))
return df
嗯,这里要注意:RSI 超过 70 算超买,低于 30 算超卖。但别死板,在强趋势行情里,RSI 可以长时间维持在超买或超卖区。我一般会结合趋势指标一起用。
3.1.4 布林带(Bollinger Bands)
布林带由中轨(MA)、上轨(中轨+2倍标准差)和下轨(中轨-2倍标准差)组成。它帮我们判断价格的「相对高低」。
def compute_bollinger(df, period=20, num_std=2):
df['BB_middle'] = df['close'].rolling(window=period).mean()
df['BB_std'] = df['close'].rolling(window=period).std()
df['BB_upper'] = df['BB_middle'] + num_std * df['BB_std']
df['BB_lower'] = df['BB_middle'] - num_std * df['BB_std']
df['BB_width'] = (df['BB_upper'] - df['BB_lower']) / df['BB_middle']
return df
3.2 滚动统计特征:捕捉局部统计规律
技术指标之外,滚动统计特征是我最常用的「万金油」。它们能帮我们捕捉价格序列的局部统计特性。
3.2.1 滚动均值与标准差
滚动均值反映局部趋势,滚动标准差反映波动率。这两个是基础中的基础。
# 滚动统计特征
df['roll_mean_10'] = df['close'].rolling(window=10).mean()
df['roll_std_10'] = df['close'].rolling(window=10).std()
df['roll_max_20'] = df['high'].rolling(window=20).max()
df['roll_min_20'] = df['low'].rolling(window=20).min()
你想想看,为什么用最大值和最小值?因为它们能告诉我们,当前价格在最近 N 天的区间里处于什么位置。这个信息对判断支撑阻力很有帮助。
3.2.2 滚动相关系数
有时候,两个品种之间的相关性变化比价格本身更有预测价值。比如螺纹钢和铁矿石,它们的价格走势通常高度相关,但一旦背离,往往意味着机会。
# 计算滚动相关系数
df['corr_20'] = df['close_steel'].rolling(20).corr(df['close_iron'])
3.3 时间序列滞后特征:让模型「看到」过去
期货价格是有记忆的。今天的价格往往和昨天、前天甚至一周前的价格有关。滞后特征就是把这些历史信息显式地喂给模型。
# 生成滞后特征
for lag in [1, 2, 3, 5, 10, 20]:
df[f'close_lag_{lag}'] = df['close'].shift(lag)
df[f'volume_lag_{lag}'] = df['volume'].shift(lag)
3.4 特征标准化与归一化:让模型「公平」对待每个特征
不同特征的量纲差异很大。比如价格是几千块,成交量是几万手,RSI 是 0-100 的数值。如果不做处理,模型会天然地偏向数值大的特征。
3.4.1 标准化(Z-score)
标准化把数据变成均值为 0、标准差为 1 的分布。适合数据本身近似正态分布的情况。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df['close_scaled'] = scaler.fit_transform(df[['close']])
3.4.2 归一化(Min-Max)
归一化把数据压缩到 [0, 1] 区间。适合数据有明确上下界的情况,比如 RSI 天然就在 0-100 之间。
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler(feature_range=(0, 1))
df['rsi_norm'] = scaler.fit_transform(df[['RSI']])
3.5 本章知识体系总览
下面这张图,是我自己梳理的特征工程知识框架。你可以把它当作一个检查清单,看看自己有没有遗漏什么。
好了,这一节的内容就到这里。特征工程是个细活,需要反复尝试和验证。我建议你从最简单的 MA 和滚动均值开始,慢慢往上加特征。记住:少即是多,好的特征比多的特征更重要。
公众号:蓝海资料掘金营,微信deep3321