技术指标计算:移动平均线(SMA/EMA)、布林带、RSI、MACD的Python实现

做量化交易的朋友都知道,技术指标是信号生成的基础。说白了,它们就是把价格、成交量这些原始数据,通过数学公式加工一下,变成我们能看懂的交易信号。

我个人习惯把技术指标分成两类:一类是趋势跟踪型,比如移动平均线、MACD;另一类是震荡型,比如RSI、布林带。今天咱们就手把手实现这四个最经典的指标。

核心要点:所有技术指标的计算,本质上都是对历史数据的滑动窗口运算。理解了这个,你就能自己实现任何指标。

3.1 移动平均线:SMA与EMA

移动平均线是最基础的指标。它用来平滑价格数据,帮我们看清趋势方向。

简单移动平均线(SMA)

SMA的计算很简单:取最近N天的收盘价,求个平均值。嗯,就这么简单。

import numpy as np
import pandas as pd

def calculate_sma(data, window=20):
    """
    计算简单移动平均线
    data: 收盘价序列(Series或list)
    window: 窗口大小,默认20天
    """
    # 我习惯用rolling方法,代码简洁
    sma = data.rolling(window=window).mean()
    return sma

# 示例
prices = pd.Series([100, 102, 101, 103, 105, 104, 106, 108, 107, 109])
sma_5 = calculate_sma(prices, window=5)
print("5日SMA:", sma_5.tolist())

小技巧:我在项目中遇到过一个问题——数据量不够时,前N-1个值会是NaN。记得用dropna()处理掉,不然后续计算会出问题。

指数移动平均线(EMA)

EMA和SMA的区别在于:EMA给近期的数据更高的权重。说白了,它更敏感,反应更快。

def calculate_ema(data, window=20, smoothing=2):
    """
    计算指数移动平均线
    smoothing: 平滑因子,通常取2
    """
    # 计算权重系数
    alpha = smoothing / (window + 1)
    
    # 初始化EMA序列
    ema = data.copy()
    
    # 第一个值用SMA代替
    ema.iloc[0] = data.iloc[0]
    
    # 递推计算
    for i in range(1, len(data)):
        ema.iloc[i] = alpha * data.iloc[i] + (1 - alpha) * ema.iloc[i-1]
    
    return ema

# 或者直接用pandas的ewm方法,更省事
def calculate_ema_fast(data, window=20):
    return data.ewm(span=window, adjust=False).mean()

注意:EMA的初始值处理方式会影响前几个值。我曾经因为用了不同的初始化方法,导致回测结果差了0.5%。建议统一用SMA作为初始值。

3.2 布林带(Bollinger Bands)

布林带由三条线组成:中轨(SMA)、上轨(中轨+2倍标准差)、下轨(中轨-2倍标准差)。它用来衡量价格的波动范围。

def calculate_bollinger_bands(data, window=20, num_std=2):
    """
    计算布林带
    data: 收盘价序列
    window: 窗口大小
    num_std: 标准差倍数,默认2
    """
    # 计算中轨(SMA)
    middle_band = data.rolling(window=window).mean()
    
    # 计算标准差
    std = data.rolling(window=window).std()
    
    # 计算上下轨
    upper_band = middle_band + num_std * std
    lower_band = middle_band - num_std * std
    
    # 返回DataFrame,方便后续使用
    bands = pd.DataFrame({
        'middle': middle_band,
        'upper': upper_band,
        'lower': lower_band
    })
    
    return bands

# 示例
bands = calculate_bollinger_bands(prices, window=5, num_std=2)
print(bands)

实战经验:布林带收窄往往预示着大行情要来了。我在做期货策略时,就专门用布林带宽度小于某个阈值作为入场信号,效果还不错。

3.3 相对强弱指标(RSI)

RSI用来衡量价格变动的速度和幅度。取值范围0-100,一般认为超过70是超买,低于30是超卖。

def calculate_rsi(data, window=14):
    """
    计算RSI指标
    data: 收盘价序列
    window: 周期,默认14
    """
    # 计算价格变化
    delta = data.diff()
    
    # 分离上涨和下跌
    gain = delta.where(delta > 0, 0)
    loss = -delta.where(delta < 0, 0)
    
    # 计算平均涨幅和平均跌幅(使用EMA平滑)
    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))
    
    return rsi

# 示例
rsi_values = calculate_rsi(prices, window=5)
print("RSI:", rsi_values.tolist())

避坑指南:我曾经用简单平均代替EMA来计算RSI,结果信号频繁出错。记住,标准的RSI用的是指数平滑,不是简单平均。

3.4 MACD指标

MACD由三部分组成:快线(DIF)、慢线(DEA)、柱状图(MACD柱)。它结合了趋势和动量两个维度。

def calculate_macd(data, fast=12, slow=26, signal=9):
    """
    计算MACD指标
    data: 收盘价序列
    fast: 快线周期,默认12
    slow: 慢线周期,默认26
    signal: 信号线周期,默认9
    """
    # 计算快线和慢线的EMA
    ema_fast = data.ewm(span=fast, adjust=False).mean()
    ema_slow = data.ewm(span=slow, adjust=False).mean()
    
    # DIF = 快线 - 慢线
    dif = ema_fast - ema_slow
    
    # DEA = DIF的EMA
    dea = dif.ewm(span=signal, adjust=False).mean()
    
    # MACD柱 = 2 * (DIF - DEA)
    macd_bar = 2 * (dif - dea)
    
    # 打包返回
    macd = pd.DataFrame({
        'DIF': dif,
        'DEA': dea,
        'MACD_BAR': macd_bar
    })
    
    return macd

# 示例
macd_values = calculate_macd(prices, fast=5, slow=10, signal=3)
print(macd_values)

核心逻辑:MACD的金叉(DIF上穿DEA)是买入信号,死叉(DIF下穿DEA)是卖出信号。但别只看这一个信号,我一般会结合RSI或成交量来确认。

3.5 知识体系总览

下面这张图展示了四个指标之间的关系和应用场景。你想想看,它们其实可以组合使用,形成更可靠的交易策略。

技术指标知识体系 技术指标 移动平均线 SMA / EMA 布林带 Bollinger Bands 相对强弱指标 RSI MACD DIF / DEA / 柱 组合应用 趋势 + 震荡 + 动量 趋势跟踪型:移动平均线、MACD 震荡型:布林带、RSI 组合使用可提高信号可靠性

3.6 实战建议

写到这里,我想分享几点个人经验:

  • 参数不是死的:默认参数(20、14、12/26/9)只是参考。我在做不同品种时,都会重新优化参数。比如做比特币,我习惯用更短的周期。
  • 指标不是越多越好:我见过有人同时用十几个指标,结果信号互相矛盾。其实2-3个就够了,关键是要理解每个指标在说什么。
  • 先验证再实盘:任何指标组合,都要先在历史数据上跑一遍。我曾经因为一个计算bug,在实盘上亏了3%。从那以后,我每次写完代码都会做单元测试。

最后提醒:技术指标只是工具,不是圣杯。它们能帮你发现机会,但不能保证盈利。风险管理才是交易的核心。


公众号:蓝海资料掘金营,微信deep3321