第三章 技术指标计算:MA/EMA、布林带、RSI、MACD
说实话,技术指标这东西,刚入行的时候我觉得挺玄乎的。不就是几条线来回穿吗?后来真金白银往里砸的时候才发现——指标不是预测未来的水晶球,而是帮你把市场情绪「翻译」成数字的工具。
我个人习惯把技术指标分成两类:一类是趋势跟踪的,比如移动平均线、MACD;另一类是震荡类的,比如布林带、RSI。今天咱们就把这四个最常用的指标,从计算到可视化,再到怎么当特征喂给强化学习模型,一次性讲透。
3.1 移动平均线:MA 与 EMA
移动平均线,说白了就是「过去N天的平均价格」。但这里有个坑——你用的是简单平均还是加权平均?
3.1.1 简单移动平均线(SMA)
公式很简单:
SMA = (P₁ + P₂ + ... + Pₙ) / N
其中 P 是收盘价,N 是周期。比如 20 日 SMA,就是过去 20 个收盘价加起来除以 20。
嗯,这里要注意:SMA 对每个数据点一视同仁。也就是说,10 天前的价格和昨天的价格权重一样。这合理吗?我个人觉得不太合理——昨天的价格显然比 10 天前的更有参考价值。所以就有了 EMA。
3.1.2 指数移动平均线(EMA)
EMA 给近期的价格更高的权重。公式稍微复杂一点:
EMA_today = (Price_today × α) + (EMA_yesterday × (1 - α))
其中 α = 2 / (N + 1)
举个例子,20 日 EMA 的 α = 2 / 21 ≈ 0.095。也就是说,今天的价格只占 9.5% 的权重,剩下的 90.5% 来自昨天的 EMA。这看起来好像近期权重也不高?其实不是——因为昨天的 EMA 本身已经包含了前天的信息,这样层层传递,越近的数据影响越大。
3.2 布林带(Bollinger Bands)
布林带由三条线组成:中轨(通常是 20 日 SMA)、上轨(中轨 + 2 倍标准差)、下轨(中轨 - 2 倍标准差)。
你想想看,它想表达什么?就是价格在「正常波动范围」内运动。如果价格突破上轨,说明当前波动异常大,可能超买;跌破下轨,可能超卖。
公式:
中轨 = SMA(close, 20)
上轨 = 中轨 + 2 × std(close, 20)
下轨 = 中轨 - 2 × std(close, 20)
我曾经犯过一个错误:直接用布林带的上下轨作为买卖信号。结果呢?在趋势行情里,价格沿着上轨一直涨,我不断做空,亏得底裤都不剩。后来才明白——布林带在震荡市里好用,在趋势市里就是个反向指标。
3.3 RSI:相对强弱指标
RSI 衡量的是「上涨幅度占总体波动的比例」。公式:
RSI = 100 - [100 / (1 + RS)]
其中 RS = 平均上涨幅度 / 平均下跌幅度
通常用 14 天周期。RSI 超过 70 算超买,低于 30 算超卖。但这里有个细节——超买不代表马上跌,超卖不代表马上涨。尤其是在大牛市中,RSI 可以在 70 以上待很久。
我个人习惯把 RSI 和价格走势结合起来看。比如价格创新高,但 RSI 没创新高,这叫「顶背离」,往往是反转信号。反过来,价格创新低,RSI 没创新低,叫「底背离」。
3.4 MACD:指数平滑异同移动平均线
MACD 由三部分组成:
- DIF线: 快线(12日EMA) - 慢线(26日EMA)
- DEA线: DIF的9日EMA
- MACD柱: (DIF - DEA) × 2
说白了,MACD 就是在看「短期趋势和长期趋势的差距」。DIF 上穿 DEA 叫金叉,下穿叫死叉。但说实话,金叉死叉的胜率也就 50% 左右,不能单靠这个做决策。
我更喜欢看 MACD 柱的变化。柱子的高度代表动能强弱。柱子从负变正,说明多头动能开始占优;从正变负,说明空头动能增强。
3.5 可视化:把指标画出来
光算不行,得看。我习惯用 Matplotlib 把价格和指标画在同一张图上。下面是一个简单的示例:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 假设 df 包含 'close' 列
df['SMA_20'] = df['close'].rolling(20).mean()
df['EMA_20'] = df['close'].ewm(span=20, adjust=False).mean()
# 布林带
df['BB_mid'] = df['close'].rolling(20).mean()
df['BB_std'] = df['close'].rolling(20).std()
df['BB_upper'] = df['BB_mid'] + 2 * df['BB_std']
df['BB_lower'] = df['BB_mid'] - 2 * df['BB_std']
# RSI
delta = df['close'].diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(14).mean()
avg_loss = loss.rolling(14).mean()
rs = avg_gain / avg_loss
df['RSI'] = 100 - (100 / (1 + rs))
# MACD
df['EMA_12'] = df['close'].ewm(span=12, adjust=False).mean()
df['EMA_26'] = df['close'].ewm(span=26, adjust=False).mean()
df['DIF'] = df['EMA_12'] - df['EMA_26']
df['DEA'] = df['DIF'].ewm(span=9, adjust=False).mean()
df['MACD_bar'] = 2 * (df['DIF'] - df['DEA'])
画图的时候,我一般把价格和布林带放在上面,RSI 放中间,MACD 放下面。这样一眼就能看到价格位置、超买超卖状态、以及动能变化。
3.6 指标作为特征:给强化学习模型喂数据
指标算好了,怎么用?直接扔给模型?不行。有几个坑必须避开:
- 归一化: 不同指标的量纲不同。RSI 是 0-100,MACD 可能是 -5 到 5。不归一化,模型会偏向数值大的特征。
- 滞后性: 移动平均线天然滞后。你想想看,20 日 SMA 反映的是过去 20 天的平均,等它给出信号,行情可能已经走了一半。
- 多重共线性: SMA 和 EMA 高度相关,同时放进去会让模型不稳定。我一般只选一个。
我个人习惯的特征组合是:
- 价格相对于布林带上轨/下轨的位置(归一化到 -1 到 1)
- RSI 的 5 日变化量
- MACD 柱的符号(正为 1,负为 -1)和绝对值
- 成交量变化率
3.7 本章知识体系
下面这张图总结了四个指标的核心逻辑和它们之间的关系:
嗯,到这里,四个核心指标的计算、可视化、特征化就讲完了。记住一句话:指标是工具,不是答案。真正决定策略好坏的是你怎么用这些工具,以及怎么把它们组合成有效的特征。