第三章 特征工程基础:什么是特征?常见技术指标的计算与实现
各位同学,欢迎来到第三章。
上一章我们聊了数据获取和清洗。数据到手了,干干净净的,然后呢?
直接扔进模型?
别急。你想想看,原始的价格序列,比如“收盘价 100.5”,模型能看懂什么?它只能看到一个数字。但咱们做交易的人,看的是趋势、是强弱、是背离。这些“高维”的信息,就是特征。
3.1 到底什么是特征?
特征,说白了就是数据的“代言人”。
原始数据是“原材料”,特征是“提炼出来的精华”。
举个例子:
- 原始数据:过去10天的收盘价 [100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
- 特征1:过去10天的涨幅 = (109 - 100) / 100 = 9%
- 特征2:过去5日均线 > 过去10日均线(金叉?死叉?)
- 特征3:RSI是否超过70(超买?)
模型不关心价格是100还是1000,它关心的是这些“衍生信号”。
核心观点:特征的质量,决定了模型的上限。数据决定了模型能飞多高,特征决定了它能不能起飞。
我个人习惯把特征分为三类:
- 基础统计特征:均值、方差、最大值、最小值、涨跌幅。
- 技术指标特征:移动平均线、RSI、MACD、布林带等。
- 高阶衍生特征:波动率、相关性、量价配合、时间序列分解等。
这一章,我们重点攻克第二类——技术指标特征。这是量化交易里最经典、最实用的特征家族。
3.2 移动平均线(MA)—— 趋势的“平滑器”
移动平均线,可能是你接触的第一个技术指标。
它的思想很简单:把过去N天的价格平均一下,消除噪音,看清趋势。
3.2.1 计算公式
简单移动平均线(SMA):
SMA(N) = (P1 + P2 + ... + PN) / N
其中P1到PN是过去N天的收盘价。
3.2.2 代码实现
用Python实现,其实就一行核心逻辑。但我建议你手写一遍,别直接用pandas的rolling,理解底层原理很重要。
import pandas as pd
import numpy as np
def calculate_sma(data, window=20):
"""
计算简单移动平均线
:param data: 包含'close'列的DataFrame
:param window: 窗口大小,默认20天
:return: 添加了'SMA'列的DataFrame
"""
# 我习惯用rolling,但为了教学,我写个循环版本
sma_values = []
for i in range(len(data)):
if i < window - 1:
sma_values.append(np.nan) # 前window-1天没有值
else:
# 取过去window天的收盘价,求平均
window_data = data['close'].iloc[i - window + 1 : i + 1]
sma_values.append(window_data.mean())
data['SMA_' + str(window)] = sma_values
return data
# 示例用法
# df = pd.read_csv('stock_data.csv')
# df = calculate_sma(df, window=5)
# df = calculate_sma(df, window=20)
# print(df[['close', 'SMA_5', 'SMA_20']].tail())
避坑指南:我曾经在实盘策略里直接用pandas的rolling().mean(),结果发现数据对齐出了问题——未来数据泄露了。记住:计算特征时,永远只用历史数据,不能用未来数据。我建议你每次计算完,都检查一下索引是否对齐。
3.2.3 实战中的用法
- 金叉/死叉:短期均线上穿长期均线 = 买入信号;下穿 = 卖出信号。
- 支撑/压力:价格回踩均线不破,可能是支撑;反弹不过均线,可能是压力。
- 趋势判断:均线向上 = 上升趋势;均线向下 = 下降趋势。
嗯,这里要注意:均线是滞后指标。它反映的是过去,不是未来。别指望它预测拐点,它只是帮你确认趋势。
3.3 相对强弱指数(RSI)—— 动量的“体温计”
RSI,全称Relative Strength Index。它衡量的是价格变动的速度和幅度。
说白了,就是看“涨得猛不猛,跌得狠不狠”。
3.3.1 计算公式
RSI的计算稍微复杂一点,但核心思想很直观:
RSI = 100 - (100 / (1 + RS))
其中 RS = 平均上涨幅度 / 平均下跌幅度
通常取14天作为周期。
3.3.2 代码实现
def calculate_rsi(data, window=14):
"""
计算相对强弱指数
:param data: 包含'close'列的DataFrame
:param window: 周期,默认14
:return: 添加了'RSI'列的DataFrame
"""
# 计算每日涨跌幅
delta = data['close'].diff()
# 分离上涨和下跌
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
# 计算平均上涨和平均下跌(使用指数移动平均,更平滑)
avg_gain = gain.ewm(span=window, adjust=False).mean()
avg_loss = loss.ewm(span=window, adjust=False).mean()
# 计算RS和RSI
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
data['RSI_' + str(window)] = rsi
return data
# 示例
# df = calculate_rsi(df, window=14)
# print(df[['close', 'RSI_14']].tail())
注意:当avg_loss为0时,RS会变成无穷大,RSI会变成100。这在连续上涨的行情中会发生。我建议你在代码里加一个保护:if avg_loss == 0: rsi = 100。否则模型可能会学到奇怪的东西。
3.3.3 实战中的用法
- 超买/超卖:RSI > 70 为超买,可能回调;RSI < 30 为超卖,可能反弹。
- 背离:价格创新高,但RSI没创新高 = 顶背离,看跌;价格创新低,但RSI没创新低 = 底背离,看涨。
- 中心线穿越:RSI上穿50 = 多头占优;下穿50 = 空头占优。
我记得有一次做回测,发现RSI在震荡行情里特别好用,但在单边趋势里经常给出错误信号。为什么会这样?因为RSI本质上是一个均值回归指标,趋势行情里它会被“打脸”。
3.4 指数平滑异同移动平均线(MACD)—— 趋势的“加速器”
MACD,全称Moving Average Convergence Divergence。它由三部分组成:
- DIF线:快线(12日EMA) - 慢线(26日EMA)
- DEA线:DIF线的9日EMA(信号线)
- MACD柱:2 × (DIF - DEA)
MACD的核心思想是:通过两条指数移动平均线的“聚合与分离”,来判断趋势的强度和转折。
3.4.1 计算公式
EMA(12) = 前一日EMA(12) × 11/13 + 今日收盘价 × 2/13
EMA(26) = 前一日EMA(26) × 25/27 + 今日收盘价 × 2/27
DIF = EMA(12) - EMA(26)
DEA = 前一日DEA × 8/10 + 今日DIF × 2/10
MACD柱 = 2 × (DIF - DEA)
3.4.2 代码实现
def calculate_macd(data, fast=12, slow=26, signal=9):
"""
计算MACD指标
:param data: 包含'close'列的DataFrame
:param fast: 快线周期,默认12
:param slow: 慢线周期,默认26
:param signal: 信号线周期,默认9
:return: 添加了'DIF', 'DEA', 'MACD'列的DataFrame
"""
# 计算快线和慢线的EMA
ema_fast = data['close'].ewm(span=fast, adjust=False).mean()
ema_slow = data['close'].ewm(span=slow, adjust=False).mean()
# 计算DIF
dif = ema_fast - ema_slow
# 计算DEA(信号线)
dea = dif.ewm(span=signal, adjust=False).mean()
# 计算MACD柱
macd = 2 * (dif - dea)
data['DIF'] = dif
data['DEA'] = dea
data['MACD'] = macd
return data
# 示例
# df = calculate_macd(df)
# print(df[['close', 'DIF', 'DEA', 'MACD']].tail())
个人经验:我建议你把MACD的三个分量都作为特征输入模型,而不是只用MACD柱。因为DIF和DEA的交叉、背离,包含了更丰富的信息。我曾经只用了MACD柱,结果模型在震荡市里表现很差,加上DIF和DEA后,效果提升明显。
3.4.3 实战中的用法
- 金叉/死叉:DIF上穿DEA = 买入信号;下穿DEA = 卖出信号。
- 零轴穿越:DIF上穿零轴 = 多头市场;下穿零轴 = 空头市场。
- 背离:价格与DIF的背离,比RSI背离更可靠。
3.5 本章知识体系总览
下面这张图,是我为你梳理的本章知识结构。你可以把它当作一个“特征工程地图”。
3.6 本章小结
这一章我们聊了三个最基础、最常用的技术指标:
- 移动平均线:趋势的平滑器,帮你识别方向。
- RSI:动量的体温计,帮你判断强弱。
- MACD:趋势的加速器,帮你捕捉转折。
你可能会问:这些指标这么老,还有用吗?
有用。非常有用。
关键在于你怎么用。不是简单地“金叉买入,死叉卖出”,而是把它们作为特征,让模型自己去学习它们之间的非线性关系。模型会发现:当RSI超买且MACD出现顶背离时,下跌的概率是80%;当均线多头排列且RSI在50以上时,上涨的概率是70%。
这就是特征工程的魅力。
最后送你一句话:特征工程不是堆砌指标,而是理解市场。每一个指标背后,都是一种市场逻辑。理解了逻辑,你才能做出好的特征。
公众号:蓝海资料掘金营,微信deep3321