第四节:技术指标计算——让数据开口说话

技术指标这东西,说白了就是给价格数据做「体检」。我刚开始做量化的时候,总觉得指标越多越好,恨不得把几十个指标全堆上去。后来被市场狠狠教育了几次才明白——指标不在多,在于你懂它

今天咱们就聊聊四个最常用的技术指标:MA、MACD、RSI、布林带。我会把计算逻辑讲透,再配上Pandas的高效实现。嗯,这些都是我实战中反复打磨过的代码。

4.1 移动平均线(MA)——最朴素的趋势跟踪器

移动平均线,说白了就是「过去N天的平均价格」。它把价格波动平滑了,让你看清趋势方向。

计算逻辑

  • 简单移动平均(SMA):等权平均
  • 指数移动平均(EMA):越近的数据权重越大

我个人习惯用EMA,因为它对价格变化反应更快。举个例子,你想想看,如果今天突然暴跌,SMA要等好几天才能反映出来,但EMA当天就会明显变化。

避坑指南:我曾经犯过一个低级错误——用收盘价计算MA,但回测时用了开盘价。结果策略表现差得离谱,查了两天才发现是数据对齐的问题。
import pandas as pd
import numpy as np

# 计算SMA和EMA
def calculate_ma(df, window=20):
    df = df.copy()
    df['SMA'] = df['close'].rolling(window=window).mean()
    df['EMA'] = df['close'].ewm(span=window, adjust=False).mean()
    return df

# 实战用法
df = pd.DataFrame({'close': [100, 102, 101, 105, 108, 107, 110]})
result = calculate_ma(df, window=3)
print(result)

4.2 MACD——趋势与动量的二合一

MACD是我最喜欢的指标之一。它由三部分组成:快线(DIF)、慢线(DEA)、柱状图(MACD柱)。

计算步骤

  1. 计算12日EMA和26日EMA
  2. DIF = 12日EMA - 26日EMA
  3. DEA = DIF的9日EMA
  4. MACD柱 = (DIF - DEA) × 2

为什么乘以2?这是为了放大柱状图的视觉效果,方便观察。我在项目中遇到过,如果不乘2,柱状图在图表上几乎看不见。

def calculate_macd(df, fast=12, slow=26, signal=9):
    df = df.copy()
    # 计算EMA
    ema_fast = df['close'].ewm(span=fast, adjust=False).mean()
    ema_slow = df['close'].ewm(span=slow, adjust=False).mean()
    
    # DIF线
    df['DIF'] = ema_fast - ema_slow
    # DEA线
    df['DEA'] = df['DIF'].ewm(span=signal, adjust=False).mean()
    # MACD柱
    df['MACD'] = 2 * (df['DIF'] - df['DEA'])
    
    return df
实战技巧:当DIF上穿DEA时,是买入信号;下穿时是卖出信号。但别急着用——我建议结合零轴位置一起看。零轴上方金叉比下方金叉更可靠。

4.3 RSI——判断超买超卖的利器

RSI(相对强弱指标)衡量的是「上涨幅度占总体波动的比例」。取值范围0-100,一般认为超过70是超买,低于30是超卖。

计算逻辑

  • 计算每日价格变化:涨了多少,跌了多少
  • 分别计算N日内的平均涨幅和平均跌幅
  • RS = 平均涨幅 / 平均跌幅
  • RSI = 100 - (100 / (1 + RS))

你想想看,如果连续涨了10天,平均涨幅远大于平均跌幅,RSI就会很高。这时候市场可能已经过热了。

def calculate_rsi(df, period=14):
    df = df.copy()
    # 计算价格变化
    delta = df['close'].diff()
    
    # 分离涨幅和跌幅
    gain = delta.where(delta > 0, 0)
    loss = -delta.where(delta < 0, 0)
    
    # 计算平均涨幅和平均跌幅
    avg_gain = gain.rolling(window=period).mean()
    avg_loss = loss.rolling(window=period).mean()
    
    # 计算RS和RSI
    rs = avg_gain / avg_loss
    df['RSI'] = 100 - (100 / (1 + rs))
    
    return df
注意:RSI在震荡行情中很好用,但在单边趋势中容易失效。我曾经在2015年大牛市里,RSI连续超买了一个月,如果按超买就卖出的逻辑,早就被甩下车了。

4.4 布林带——价格波动的「安全通道」

布林带由三条线组成:中轨(MA)、上轨(中轨+2倍标准差)、下轨(中轨-2倍标准差)。它告诉你价格在什么范围内波动是「正常的」。

计算步骤

  1. 计算N日移动平均线(中轨)
  2. 计算N日价格标准差
  3. 上轨 = 中轨 + K × 标准差
  4. 下轨 = 中轨 - K × 标准差

K值通常取2,这意味着价格有95%的概率落在通道内。如果价格突破通道,往往意味着趋势要加速了。

def calculate_bollinger(df, window=20, num_std=2):
    df = df.copy()
    # 中轨
    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']
    
    return df

4.5 信号生成——把指标变成交易指令

指标算出来只是第一步,关键是怎么用。我一般会生成三种信号:买入、卖出、持有。

常见信号逻辑

指标 买入信号 卖出信号
MA 价格上穿MA 价格下穿MA
MACD DIF上穿DEA DIF下穿DEA
RSI RSI低于30后上穿30 RSI高于70后下穿70
布林带 价格触及下轨后反弹 价格触及上轨后回落
def generate_signals(df):
    df = df.copy()
    # 初始化信号列
    df['Signal'] = 0
    
    # MACD金叉死叉
    df.loc[(df['DIF'] > df['DEA']) & 
           (df['DIF'].shift(1) <= df['DEA'].shift(1)), 'Signal'] = 1
    df.loc[(df['DIF'] < df['DEA']) & 
           (df['DIF'].shift(1) >= df['DEA'].shift(1)), 'Signal'] = -1
    
    # RSI超买超卖
    df.loc[(df['RSI'] < 30) & 
           (df['RSI'].shift(1) >= 30), 'Signal'] = 1
    df.loc[(df['RSI'] > 70) & 
           (df['RSI'].shift(1) <= 70), 'Signal'] = -1
    
    return df
核心原则:单一指标的信号可靠性有限。我建议至少用两个指标互相验证。比如MACD金叉 + RSI从低位回升,这样的信号成功率会高很多。

4.6 知识体系总览

下面这张图把本章的核心内容串起来了。你可以看到,从原始数据到最终信号,每一步都有明确的逻辑。

技术指标计算知识体系 原始价格数据 MA移动平均线 趋势跟踪 MACD 趋势+动量 RSI 超买超卖 布林带 波动率通道 信号生成(买入/卖出/持有) 交易决策 多指标交叉验证 → 提高信号可靠性

这张图展示了从原始数据到最终决策的完整链路。四个指标各有侧重,但最终都要落到信号生成这一步。我个人建议,刚开始做回测时,先选两个指标练手,等熟悉了再逐步增加。

效率提升:用Pandas的向量化操作计算指标,比用for循环快几十倍。我见过有人用循环算MACD,100万条数据跑了半小时——换成向量化操作,3秒搞定。

好了,技术指标的计算就聊到这儿。记住,指标是工具,不是圣杯。真正重要的是你如何理解市场、如何设计策略。下一节我们会把这些指标组合起来,做一个完整的轮动模型回测。


专注资料整理