3、特征工程(上):技术指标计算(MA、MACD、RSI、布林带)

各位同学,欢迎来到特征工程部分。说实话,在量化投资这个领域,我见过太多人把精力花在模型调参上,却忽略了最基础的东西——特征。你想想看,模型再牛,喂进去的是垃圾,出来的只能是更精致的垃圾。今天咱们就聊聊技术指标这个老本行,把MA、MACD、RSI、布林带这几个经典指标讲透。

核心观点:技术指标不是万能的,但没有技术指标是万万不能的。它们是我们从价格数据中提取结构化信息的第一把刀。

3.1 移动平均线(MA)——趋势的骨架

移动平均线,说白了就是给价格序列「搓澡」,把短期的毛刺搓掉,露出趋势的骨架。我个人习惯把MA分成两类:

  • 简单移动平均(SMA):等权平均,反应慢但稳定
  • 指数移动平均(EMA):近重远轻,反应快但容易假信号

我在项目中遇到过一个问题:用SMA做趋势跟踪,结果在震荡市里被反复打脸。后来我改用EMA+自适应窗口,效果好了不少。这里给个代码示例:

import pandas as pd
import numpy as np

def calculate_ma(df, window=20, ma_type='sma'):
    """
    计算移动平均线
    df: 包含'close'列的DataFrame
    """
    if ma_type == 'sma':
        df['MA'] = df['close'].rolling(window=window).mean()
    elif ma_type == 'ema':
        df['MA'] = df['close'].ewm(span=window, adjust=False).mean()
    return df

# 实战用法
df = pd.DataFrame({'close': [10, 11, 12, 11, 10, 13, 14, 15]})
df = calculate_ma(df, window=3, ma_type='ema')
print(df)

我的小技巧:做短线用EMA(5, 10),做中线用SMA(20, 60)。别问我为什么,这是血泪教训换来的。

3.2 MACD——趋势的加速器

MACD,全称是Moving Average Convergence Divergence。名字挺唬人,其实就是两条均线的差值。嗯,这里要注意:MACD不是用来判断方向的,而是用来判断趋势的「力度」。

MACD有三个核心要素:

  • DIF线:快线 - 慢线(通常12EMA - 26EMA)
  • DEA线:DIF的9日EMA
  • 柱状图:DIF - DEA

我曾经犯过一个低级错误:直接用MACD金叉死叉做交易信号,结果在震荡行情里亏得底裤都不剩。后来我加了一个条件——必须配合零轴位置。零轴以上金叉才是真金叉,零轴以下的金叉大概率是反弹。

def calculate_macd(df, fast=12, slow=26, signal=9):
    """
    计算MACD指标
    """
    df['EMA_fast'] = df['close'].ewm(span=fast).mean()
    df['EMA_slow'] = df['close'].ewm(span=slow).mean()
    df['DIF'] = df['EMA_fast'] - df['EMA_slow']
    df['DEA'] = df['DIF'].ewm(span=signal).mean()
    df['MACD_bar'] = 2 * (df['DIF'] - df['DEA'])
    return df

避坑指南:我曾经在回测中用了默认参数(12, 26, 9),结果发现对某些股票完全无效。后来我做了参数扫描,发现不同周期、不同品种的最佳参数差异很大。别迷信默认值。

3.3 RSI——情绪的体温计

RSI(相对强弱指标),说白了就是测量「最近涨得有多猛」。它的逻辑很简单:涨多了要跌,跌多了要涨。但这里有个坑——RSI的超买超卖阈值不是固定的。

标准用法是:

  • RSI > 70:超买,考虑卖出
  • RSI < 30:超卖,考虑买入

但我在实战中发现,牛市中RSI可以长期在70以上,熊市中RSI可以长期在30以下。如果你死板地按阈值操作,会被市场反复教育。我的做法是:用RSI的「背离」来做信号,而不是绝对值。

def calculate_rsi(df, window=14):
    """
    计算RSI指标
    """
    delta = df['close'].diff()
    gain = delta.where(delta > 0, 0)
    loss = -delta.where(delta < 0, 0)
    
    avg_gain = gain.rolling(window=window).mean()
    avg_loss = loss.rolling(window=window).mean()
    
    rs = avg_gain / avg_loss
    df['RSI'] = 100 - (100 / (1 + rs))
    return df

个人经验:RSI配合布林带使用效果更好。当RSI超卖且价格触及布林带下轨时,反弹概率大幅提升。我靠这个组合抓过不少波段。

3.4 布林带(Bollinger Bands)——价格的跑道

布林带,由John Bollinger发明。它由三条线组成:中轨(MA)、上轨(中轨+2倍标准差)、下轨(中轨-2倍标准差)。你想想看,这其实就是给价格画了一个「正常波动范围」。

布林带的核心用法:

  • 带宽收缩:预示即将变盘
  • 价格突破上轨:强势,但可能回调
  • 价格跌破下轨:弱势,但可能反弹
  • 轨道开口:趋势加速

我记得有一次做期货策略,发现布林带的带宽指标(带宽 = (上轨-下轨)/中轨)在收缩到极低值后,往往会出现一波大行情。这个发现让我在2018年的螺纹钢行情中赚了一笔。

def calculate_bollinger(df, window=20, num_std=2):
    """
    计算布林带
    """
    df['MA'] = df['close'].rolling(window=window).mean()
    df['STD'] = df['close'].rolling(window=window).std()
    df['Upper'] = df['MA'] + num_std * df['STD']
    df['Lower'] = df['MA'] - num_std * df['STD']
    df['Bandwidth'] = (df['Upper'] - df['Lower']) / df['MA']
    return df

3.5 知识体系总览

下面这张图是我自己画的,把今天讲的四个指标串起来了。你看一眼就能明白它们各自扮演什么角色:

技术指标知识体系 价格序列 MA 移动平均线 趋势方向识别 MACD 趋势力度判断 RSI 相对强弱 超买超卖检测 布林带 波动范围与突破 组合使用建议 MA判断方向 + MACD确认力度 + RSI过滤极端 + 布林带定位入场点 四个指标相互验证,胜率远高于单一指标

3.6 实战中的坑与经验

最后,我把自己这些年踩过的坑总结一下:

指标 常见错误 我的改进方案
MA 固定窗口,不适应市场变化 使用自适应窗口(如ATR调整)
MACD 只看金叉死叉,忽略零轴位置 零轴以上金叉才做多,以下死叉才做空
RSI 死守70/30阈值 结合背离信号,动态调整阈值
布林带 认为突破上下轨就是反转信号 配合带宽收缩和成交量确认

核心总结:技术指标是工具,不是圣杯。我见过太多人把指标当成了预测未来的水晶球,结果亏得一塌糊涂。记住,指标的作用是帮你「描述」市场状态,而不是「预测」未来走势。把四个指标组合起来,互相验证,这才是正确的打开方式。

专注资料整理