MACD(Moving Average Convergence Divergence、移動平均収束拡散)は、短期 EMA と長期 EMA の差をベースにしたトレンド系指標です。本記事では、計算式・pandas 実装・3 段グラフでの可視化・解釈のポイントを整理します。
目次
- MACD を構成する 3 本
- 計算式
- サンプルデータの準備
- MACD を計算する関数
- 可視化(価格 + MACD)
- 読み方のポイント
- クロスのフラグを立てる
- ヒストグラムの転換を取る
MACD を構成する 3 本
MACD は 3 つの値で表現されます。
- MACD ライン: 短期 EMA から長期 EMA を引いた値
- シグナル線: MACD ラインの EMA(さらに平滑化したもの)
- ヒストグラム: MACD ラインからシグナル線を引いた値
慣例的に (短期, 長期, シグナル) = (12, 26, 9) が使われます。
計算式
短期期間を 、長期期間を 、シグナル期間を とします。
ヒストグラムが正の領域に大きく広がっていれば「買われている勢いが増している」、負の領域に大きく広がっていれば「売られている勢いが増している」と解釈されます。
サンプルデータの準備
import numpy as npimport pandas as pd
rng = np.random.default_rng(seed=37)n = 260returns = rng.normal(loc=0.0006, scale=0.013, size=n)close = pd.Series( 2000 * np.exp(np.cumsum(returns)), index=pd.date_range("2025-09-01", periods=n, freq="B"), name="C",)MACD を計算する関数
def macd( close: pd.Series, short: int = 12, long: int = 26, signal: int = 9,) -> pd.DataFrame: """MACD / Signal / Hist の 3 列を返す。""" ema_short = close.ewm(span=short, adjust=False).mean() ema_long = close.ewm(span=long, adjust=False).mean() macd_line = ema_short - ema_long signal_line = macd_line.ewm(span=signal, adjust=False).mean() hist = macd_line - signal_line return pd.DataFrame( {"macd": macd_line, "signal": signal_line, "hist": hist} )
m = macd(close)print(m.tail())adjust=False は EMA を再帰式の定義どおりに計算するオプションで、TA-Lib などの結果と整合しやすくなります。
可視化(価格 + MACD)
価格を上段、MACD を下段に並べる 2 段構成です。
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots( nrows=2, sharex=True, figsize=(11, 6), gridspec_kw={"height_ratios": [3, 2]},)
ax1.plot(close.index, close.values, color="black", linewidth=0.8)ax1.set_title("C & MACD(12, 26, 9)")ax1.set_ylabel("Price")ax1.grid(alpha=0.3)
ax2.plot(m.index, m["macd"], label="MACD", color="tab:blue")ax2.plot(m.index, m["signal"], label="Signal", color="tab:orange")colors = ["tab:red" if v < 0 else "tab:green" for v in m["hist"].fillna(0)]ax2.bar(m.index, m["hist"], color=colors, width=1.0, alpha=0.5, label="Hist")ax2.axhline(0, color="black", linewidth=0.6)ax2.set_ylabel("MACD")ax2.set_xlabel("Date")ax2.legend(loc="upper left")ax2.grid(alpha=0.3)
plt.tight_layout()plt.savefig("macd_chart.png", dpi=120)plt.close(fig)
ヒストグラムは正で緑、負で赤の棒にすると、勢いの方向が一目で読めます。
読み方のポイント
| 観察ポイント | 一般的な解釈 |
|---|---|
| MACD がシグナルを下から上抜け | 上昇への転換の兆し(MACD ゴールデンクロス) |
| MACD がシグナルを上から下抜け | 下落への転換の兆し(MACD デッドクロス) |
| MACD が 0 ラインを上抜け | 短期 EMA が長期 EMA を超える(中期トレンド転換) |
| ヒストグラムの拡大 | 現在のトレンドが強まっている |
| ヒストグラムの縮小 | 現在のトレンドが弱まっている |
「MACD クロス」と「価格の SMA クロス」は別物である点に注意します。両者が同じ日付に出ることは少なく、組み合わせて使うことで遅行性をいくらか緩和できます。
クロスのフラグを立てる
MACD ラインがシグナル線を抜けた日を取り出します。
m["above"] = (m["macd"] > m["signal"]).astype(int)m["cross"] = m["above"].diff()gc = m.index[m["cross"] == 1].tolist()dc = m.index[m["cross"] == -1].tolist()print("MACD GC:", gc[:5])print("MACD DC:", dc[:5])ここでも、シグナル発生日の終値で約定 すると先読みになるため、実装上は position = above.shift(1) などで翌営業日に回します。
ヒストグラムの転換を取る
「ヒストグラムがマイナスからプラスに転じた日」を取りたい場合は次のとおりです。
m["hist_sign"] = np.sign(m["hist"]).fillna(0).astype(int)m["hist_flip_up"] = (m["hist_sign"].diff() > 0) # -1 / 0 -> +1m["hist_flip_dn"] = (m["hist_sign"].diff() < 0)ヒストグラムの転換は MACD クロスより 1 〜 2 日早く出ることがあります。早出を取るか、確実性を取るかでルールを使い分けます。
注意点
- 遅行指標: EMA を 3 段重ねているため、急騰急落直後はシグナルが間に合わないことがある
- 横ばい相場で頻発する誤シグナル: ヒストグラムが小さい範囲で行ったり来たりする
- 0 ラインの意味: 0 ラインはあくまで「短期 EMA = 長期 EMA」のライン。価格の絶対水準とは無関係
- 絶対値での比較は不可: 銘柄ごとに価格水準が違うため、MACD の値そのものを銘柄横断で比較しても意味がない
生成AI へのプロンプト例
ロング形式の DataFrame に対し、Code ごとに MACD を計算する関数を依頼します。
入力 DataFrame:- columns: Date (datetime64), Code (str), C (float)
Code ごとに MACD(12, 26, 9) を計算し、- macd, macd_signal, macd_hist の 3 列を追加した DataFrameを返す関数 add_macd(df, short=12, long=26, signal=9) を書いてください。
要件:- pandas 2.2 系- Code ごとに日付昇順に整列してから計算- ewm(span=N, adjust=False) を使用- 各 Code の冒頭は NaN を許容- 関数の動作確認用サンプルコードを末尾に付けるまとめ
- MACD は EMA の差から作る トレンド系オシレーター
- 構成要素は MACD ライン・シグナル線・ヒストグラムの 3 本
- 標準パラメータは (12, 26, 9)。
ewm(span=N, adjust=False)で再現できる - ゴールデンクロス・デッドクロスの判定は
(macd > signal).astype(int).diff() - 遅行性・横ばい相場での誤シグナルは構造的な弱点。他指標と併用する前提で使う