本文你将得到什么:
- 不调用任何指标库,纯手工用 EMA 算出 MACD 三要素
- 理解 DIF、DEA、MACD 柱各自的含义与联动关系
- 区分"零轴上金叉"和"零轴下金叉"的实战差异
- 把 MACD 信号画成三面板图(价格 + DIF/DEA + MACD柱)
- 一段可直接复制的完整代码
痛点:为什么你不能只会看软件上的 MACD
行情软件里的 MACD 都是现成的,但很多人用了几年也没搞清楚:
- DIF 和 DEA 到底谁减谁?
- MACD 柱为什么是"(DIF-DEA)×2"?
- 同样的金叉,为什么有的涨、有的不涨?
答案藏在计算过程里。本文带你手工算一遍,算完你就明白"零轴上金叉"和"零轴下金叉"为什么强度完全不同。
环境准备
bash
pip install mairui pandas numpy matplotlib
第一步:拉取数据
python
from mairui import Client
client = Client("LICENCE-66D8-9F96-0C7F0FBCD073")
bars = client.stock_history(code="600519", period="d", dividend="f")
import pandas as pd
df = pd.DataFrame(bars)
df = df.rename(columns={"t": "date", "o": "o", "h": "h", "l": "l", "c": "c"})
df = df.sort_values("date").reset_index(drop=True)
closes = df["c"].astype(float)
第二步:手工计算 EMA
MACD 的底层是三个 EMA:
- EMA(12):快速平滑
- EMA(26):慢速平滑
- EMA(9):对 DIF 再平滑一次得到 DEA
python
def calc_ema(series, span):
"""指数移动平均。"""
return series.ewm(span=span, adjust=False).mean()
ema12 = calc_ema(closes, 12)
ema26 = calc_ema(closes, 26)
EMA 和 MA 的区别:EMA 给近期价格更高权重,对最新变化更敏感。
第三步:算 DIF、DEA、MACD 柱
python
# DIF = 快EMA - 慢EMA
dif = ema12 - ema26
# DEA = DIF 的 9日EMA
dea = calc_ema(dif, 9)
# MACD柱 = (DIF - DEA) * 2
macd_hist = (dif - dea) * 2
print(f"DIF 最新: {dif.iloc[-1]:.4f}")
print(f"DEA 最新: {dea.iloc[-1]:.4f}")
print(f"MACD柱 最新: {macd_hist.iloc[-1]:.4f}")
输出示例(演示数据):
DIF 最新: -0.0105
DEA 最新: 0.0243
MACD柱 最新: -0.0696
解读:
- DIF < DEA,说明短期动能弱于中期平滑值,当前为空头状态
- MACD 柱为负,且 DIF 在零轴下方,整体偏空
第四步:检测 MACD 交叉信号
python
def find_macd_signals(df):
signals = []
for i in range(1, len(df)):
prev = df.iloc[i - 1]
curr = df.iloc[i]
if prev["dif"] < prev["dea"] and curr["dif"] > curr["dea"]:
zero_info = "零轴上" if curr["dif"] > 0 else "零轴下"
signals.append((curr["date"], "golden", curr["dif"], zero_info))
elif prev["dif"] > prev["dea"] and curr["dif"] < curr["dea"]:
zero_info = "零轴上" if curr["dif"] > 0 else "零轴下"
signals.append((curr["date"], "death", curr["dif"], zero_info))
return signals
signals = find_macd_signals(df)
for date, typ, dval, zinfo in signals:
label = "金叉" if typ == "golden" else "死叉"
print(f"{date} {label} DIF={dval:.4f} ({zinfo})")
输出示例:
2025-09-30 金叉 DIF=-0.1524 (零轴下)
2025-10-31 死叉 DIF=-0.0922 (零轴下)
2025-11-05 金叉 DIF=-0.0565 (零轴下)
2025-11-07 死叉 DIF=-0.0728 (零轴下)
2025-11-10 金叉 DIF=-0.0238 (零轴下)
2025-11-25 死叉 DIF=0.0372 (零轴上)
注意最后一组:死叉发生在零轴上方,属于"多头中的回调信号",和零轴下方的死叉含义不同。
第五步:三面板可视化
python
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False
fig, axes = plt.subplots(3, 1, figsize=(12, 10),
gridspec_kw={"height_ratios": [2, 1, 1]})
x = range(len(df))
# 面板1:收盘价
axes[0].plot(x, closes, color="black", linewidth=0.8)
axes[0].set_title("收盘价")
axes[0].set_ylabel("价格")
axes[0].grid(True, alpha=0.3)
# 面板2:DIF / DEA + 交叉标记
axes[1].plot(x, dif, label="DIF", color="blue", linewidth=1)
axes[1].plot(x, dea, label="DEA", color="orange", linewidth=1)
axes[1].axhline(y=0, color="gray", linestyle="--", alpha=0.5)
for date, typ, dval, zinfo in signals:
idx = df[df["date"] == date].index[0]
color = "red" if typ == "golden" else "green"
marker = "^" if typ == "golden" else "v"
axes[1].scatter([idx], [dval], color=color, marker=marker, s=80)
axes[1].set_title("MACD 金叉/死叉")
axes[1].set_ylabel("DIF / DEA")
axes[1].legend()
axes[1].grid(True, alpha=0.3)
# 面板3:MACD柱
colors = ["red" if v >= 0 else "green" for v in macd_hist]
axes[2].bar(x, macd_hist, color=colors, width=0.8)
axes[2].axhline(y=0, color="gray", linestyle="-", alpha=0.5)
axes[2].set_title("MACD 柱状图(红=正,绿=负)")
axes[2].set_ylabel("MACD")
axes[2].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("macd_chart.png", dpi=150)
三面板的好处:价格、DIF/DEA 走势、MACD 柱变化一屏看完,不用在软件里切来切去。
关键认知:金叉的强弱怎么看
| 场景 | 位置 | 含义 | 强度 |
|---|---|---|---|
| 零轴上金叉 | DIF>0, DEA>0 | 多头趋势中的加速信号 | 强 |
| 零轴下金叉 | DIF<0, DEA<0 | 空头趋势中的反弹信号 | 弱 |
| 零轴附近金叉 | DIF≈0 | 趋势转折临界点 | 不确定 |
| 死叉同理 | --- | --- | --- |
本文演示数据中的金叉全部发生在零轴下方,属于"弱势反弹"型金叉,不能和零轴上的强势金叉等量齐观。实战中建议:零轴上金叉才考虑做多,零轴下金叉只当反弹对待。
常见坑与注意
- MACD 的滞后比 MA 更严重:因为 DIF 本身就是 EMA 的差,DEA 又是 DIF 的 EMA,两次平滑导致信号更慢。
- 零轴是多空分界线:DIF 在零轴上方 = 多头区域,下方 = 空头区域。很多人只看金叉死叉,忽略零轴位置,容易误判。
- 背离才是 MACD 的精髓:价格创新高但 DIF 不创新高(顶背离),或价格创新低但 DIF 不创新低(底背离),比单纯的金叉死叉更可靠。后续篇章会单独讲背离检测。
- 演示数据 vs 真实数据:本文使用演示证书跑通逻辑,换正式证书后即为真实行情,代码无需修改。
小结
本文带你手工算了一遍 MACD 的完整计算链路:
- EMA(12) 和 EMA(26) → DIF
- DIF 的 EMA(9) → DEA
- (DIF-DEA)×2 → MACD 柱
并强调了一个实战要点:金叉不是都一样的,零轴位置决定强度。下一篇,我们把 KDJ 和 RSI 拉进来,做一个"超买超卖双确认"系统。
免责声明
本文仅为技术教学,不构成任何投资建议。投资有风险,入市需谨慎。