MACD

MACD (Moving Average Convergence Divergence) measures the relationship between two EMAs — momentum and trend direction in one indicator, built directly on chapter 101's ema().

def macd(df: pd.DataFrame, fast: int = 12, slow: int = 26, signal: int = 9) -> pd.DataFrame:
    fast_ema = ema(df["close"], fast)
    slow_ema = ema(df["close"], slow)
    macd_line = fast_ema - slow_ema
    signal_line = ema(macd_line, signal)
    histogram = macd_line - signal_line
    return pd.DataFrame({"macd": macd_line, "signal": signal_line, "histogram": histogram}, index=df.index)

The three components and what each means

  • MACD line (fast_ema - slow_ema) — positive means the fast average is above the slow one (bullish momentum), negative means the reverse.
  • Signal line — a smoothed version of the MACD line itself, used to generate crossover signals with less noise than the raw MACD line.
  • Histogram (macd - signal) — the "acceleration" of momentum: growing histogram bars mean momentum is strengthening in whatever direction it's already going; shrinking bars mean momentum is fading, often before an actual crossover occurs.

Standard signals

def macd_crossover_signal(macd_df: pd.DataFrame) -> pd.Series:
    signal = pd.Series(0, index=macd_df.index)
    bullish_cross = (macd_df["macd"] > macd_df["signal"]) & (macd_df["macd"].shift(1) <= macd_df["signal"].shift(1))
    bearish_cross = (macd_df["macd"] < macd_df["signal"]) & (macd_df["macd"].shift(1) >= macd_df["signal"].shift(1))
    signal[bullish_cross] = 1
    signal[bearish_cross] = -1
    return signal

This exact shift-and-compare crossover pattern — current bar's relation flips relative to the previous bar's relation — is the generic building block chapter 113 formalizes for *any* two series, not just MACD.

Zero-line crossover — a separate, slower signal

def macd_zero_cross(macd_df: pd.DataFrame) -> pd.Series:
    return macd_df["macd"].apply(lambda x: 1 if x > 0 else -1)

MACD crossing above/below zero indicates the fast EMA crossing the slow EMA directly (equivalent to a plain EMA crossover, chapter 101) — generally a slower, more trend-confirming signal than the signal-line crossover above, which reacts faster but with more false positives.

Known limitation — lags in choppy, range-bound markets

MACD is built from lagging moving averages, so in a sideways market it generates frequent whipsaw crossovers with no real trend to capture — this is precisely why chapter 106 (ADX) is commonly paired with MACD: use ADX to filter out MACD signals when the market isn't trending at all.

Next: 103 — RSI