MACD — Moving Average Convergence Divergence
Fast EMA minus slow EMA, with a signal-line EMA and a histogram. Multi-value: .line, .signal, .histogram.
Signature
MACD(fast_period, slow_period, signal_period, on=<source>)| Argument | Type | Required | Notes |
|---|---|---|---|
fast_period |
int Param or literal | Yes | Fast EMA length. Default 12, bounds 2–50. |
slow_period |
int Param or literal | Yes | Slow EMA length. Default 26, bounds 10–200. |
signal_period |
int Param or literal | Yes | Signal-line EMA length. Default 9, bounds 2–50. |
on= |
symbol, OHLCV field, or indicator | No | Source. Defaults to the trade symbol’s close. |
Formula
$$ \text{line} = \text{EMA}{\text{fast}}(\text{close}) - \text{EMA}{\text{slow}}(\text{close}) $$
$$ \text{signal} = \text{EMA}_{\text{signal}}(\text{line}), \qquad \text{histogram} = \text{line} - \text{signal} $$
Both price EMAs are seeded from the simple average of the first slow_period closes; the signal line seeds to the first computed MACD line value and follows its own EMA recursion from there.
Warmup
slow_period bars. All three outputs read 0 until the slow window is full.
Reading values
MACD is multi-value — you access fields with attributes, not .value.
m = MACD(12, 26, 9, on=self.trade)
m.line # fast EMA − slow EMAm.signal # EMA of the linem.histogram # line − signalNo crossed_above on multi-value
m.crossed_above(0) is RC2_CROSS_MULTIVALUE. Compare fields explicitly, or track the previous bar’s values in persistent state to detect a line/signal cross.
Example
class MACDHistogramTrend(Strategy): """Long while the MACD histogram is positive.""" fast_period = Param(12, min=2, max=50) slow_period = Param(26, min=10, max=200) signal_period = Param(9, min=2, max=50) trade = Symbol() sizing = FixedCapital()
def execute(self): m = MACD(self.fast_period, self.slow_period, self.signal_period, on=self.trade) self.stop_loss(3.0)
if m.histogram > 0 and self.trade.is_flat: self.buy(self.trade, reason=f"MACD histogram positive ({m.histogram:.2f})")
if m.histogram < 0 and self.trade.is_long: self.sell(self.trade, self.trade.position, reason=f"MACD histogram negative ({m.histogram:.2f})")Notes
- The histogram’s sign is the classic trend read (positive = line above signal); its slope leads the sign — a shrinking positive histogram often precedes the bearish cross.
- MACD is unbounded and scales with price. To compare across instruments, divide by price or use percentage-based indicators (
ROC, or thePercent Price Oscillatorfrom the catalog). - For a true line/signal crossing signal, track last-bar values in persistent state — see the worked example in
RC2_CROSS_MULTIVALUE.