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