fintech-algorithms

MACD

Read the Spreads Before You Read the Signals

Install and import

bash
npm install fintech-algorithms
ts
import { macd } from "fintech-algorithms/technical-indicators/trend-systems/macd";

Signature

macd(values, fastSpan, slowSpan, signalSpan)

Moving average convergence/divergence: the gap between a fast and a slow EMA, its own EMA as a signal line, and the difference between them as a histogram.

Parameters

NameTypeNotes
values(number | null)[]Observation series in chronological order, oldest first.
nulls: propagate
fastSpannumberSpan of the fast EMA.
min: 1 · integer: true
slowSpannumberSpan of the slow EMA; must exceed the fast span.
min: 1 · integer: true
signalSpannumberSpan of the EMA taken over the MACD line itself.
min: 1 · integer: true

Returns

{ fast_ema, slow_ema, macd, signal, histogram }[] · length same-as-input

One record per position carrying both EMAs alongside the three published series.

Warm-up

The first slowSpan − 1 for the MACD line, and slowSpan + signalSpan − 2 for the signal and histogram positions are null. The signal line is an average *of* the MACD line, so it is defined strictly later — plotting the two without allowing for that misaligns them.

Errors

  • When any span is < 1, is not an integer, or fastSpan ≥ slowSpan — throws RangeError

Complexity: time O(n), space O(n).

Worked example

executed Captured by running this function on the input its own test provides. Real output of real code — but not asserted against a published figure.

Input

values
[10, 11, 12, 13, 14, 15]

Showing 6 of 14 elements.

fastSpan
3
slowSpan
5
signalSpan
3

Call

macd(values, fastSpan, slowSpan, signalSpan)

Returns

array of 14 objects

[
  {
    "index": 0,
    "value": 10,
    "fastEma": null,
    "slowEma": null,
    "macd": null,
    "signal": null,
    "histogram": null,
    "status": "warming_price_emas"
  },
  {
    "index": 1,
    "value": 11,
    "fastEma": null,
    "slowEma": null,
    "macd": null,
    "signal": null,
    "histogram": null,
    "status": "warming_price_emas"
  },
  {
    "index": 2,
    "value": 12,
    "fastEma": 11,
    "slowEma": null,
    "macd": null,
    "signal": null,
    "histogram": null,
    "status": "warming_price_emas"
  }
]

Showing 3 of 14 elements.

Diagrams

MACD — ema gap
MACD — macd machine
MACD — scale trap
MACD — signal cross
MACD — three panel path
MACD — warmup timeline
MACD — whipsaw range
MACD — zero cross

Calculation flow

Calculation flow
flowchart LR
    X["Ordered finite source values"] --> F["Fast SMA-seeded EMA"]
    X --> S["Slow SMA-seeded EMA"]
    F --> D{"Both EMAs ready?"}
    S --> D
    D -->|No| W["MACD unavailable"]
    D -->|Yes| M["MACD = fast EMA - slow EMA"]
    M --> G["Signal = SMA-seeded EMA of MACD"]
    M --> H["Histogram = MACD - signal"]
    G --> H
    H --> O["Aligned component row"]
State lifecycle
stateDiagram-v2
    [*] --> WarmingPriceEMAs
    WarmingPriceEMAs --> WarmingSignal: "slow_span observations"
    WarmingSignal --> Ready: "signal_span MACD values"
    Ready --> Ready: "append one finalized observation"
    Ready --> RecomputedSuffix: "revise a historical observation"
    RecomputedSuffix --> Ready: "replace affected suffix"

How it works

This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.

Read the article →

References

  • Primary and authoritative sources
  • Claims derived algebraically in this package
  • Historical and interpretive caution
  • Reproducibility
  • Historical example decision