Moving averages & smoothing

14 functions

MA(X, N)

Simple moving average of X over N bars.

N may itself be a series, so the length can vary bar by bar. Bars before the window is full return an invalid value.

X(series)
The series to average — usually CLOSE.
N(integer)
Number of bars in the window.
// a classic three-line moving average set
MA5:  MA(CLOSE, 5);
MA10: MA(CLOSE, 10);
MA20: MA(CLOSE, 20), COLORYELLOW, LINETHICK2;

// N can be a series — a length that widens with volatility
LEN := 10 + INTPART(STD(CLOSE, 20) / CLOSE * 200);
ADAPTIVE: MA(CLOSE, LEN), COLORLIBLUE;
EMA(X, N)

Exponential moving average, weight 2/(N+1).

X(series)
The series to smooth.
N(integer)
Number of bars; the weight of the current bar is 2/(N+1).
// MACD, written out in full
DIF:  EMA(CLOSE, 12) - EMA(CLOSE, 26);
DEA:  EMA(DIF, 9);
// the histogram is the gap between the two lines, doubled
MACD: (DIF - DEA) * 2, COLORSTICK;
EXPMA(X, N)

Exponential moving average, seeded from the first valid value.

X(series)
The series to smooth.
N(integer)
Number of bars.
// same weighting as EMA, different starting value —
// the two only differ over the first few dozen bars
FAST: EXPMA(CLOSE, 12);
SLOW: EXPMA(CLOSE, 50), COLORYELLOW;
EXPMEMA(X, N)

Exponential average seeded with a simple average of the first N bars — the smoother EMA variant used by DMI.

X(series)
The series to smooth.
N(integer)
Number of bars, also the length of the seeding average.
// Wilder's ATR — TR is a built-in, no need to spell it out
ATR: EXPMEMA(TR, 14), COLORYELLOW;

// the same smoothing drives DMI
ATR14 := EXPMEMA(TR, 14);
PDI: EXPMEMA(MAX(HIGH - REF(HIGH, 1), 0), 14) / ATR14 * 100;
SMA(X, N, M)

Chinese-style smoothed average: Y = (M·X + (N−M)·Y') / N.

The backbone of KDJ and RSI. M is the weight of the current bar, so SMA(X, N, 1) is the classic Wilder smoothing.

X(series)
The series to smooth.
N(integer)
Smoothing length — the divisor in the formula.
M(integer)
Weight of the current bar. M = 1 gives Wilder smoothing; M must not exceed N.
// KDJ, built from the raw stochastic
RSV := (CLOSE - LLV(LOW, 9)) / (HHV(HIGH, 9) - LLV(LOW, 9)) * 100;
K: SMA(RSV, 3, 1);
D: SMA(K, 3, 1);
J: 3 * K - 2 * D, COLORMAGENTA;
DMA(X, A)

Dynamic moving average: Y = A·X + (1−A)·Y'. A may be a series.

Values of A outside 0–1 are clamped to the previous output, which makes it safe to drive A from volume ratios.

X(series)
The series to smooth.
A(series)
Weight of the current bar, 0–1. May vary bar by bar; values outside the range reuse the previous output.
// let today's share of the last 20 bars' volume set the weight,
// so heavy bars pull the average harder
W := VOL / SUM(VOL, 20);
VWMA: DMA(CLOSE, W), COLORYELLOW;
WMA(X, N)

Linearly weighted moving average — recent bars weigh more.

X(series)
The series to average.
N(integer)
Number of bars; the oldest bar in the window weighs 1, the newest N.
// WMA turns earlier than MA of the same length
MA10:  MA(CLOSE, 10),  COLORGRAY;
WMA10: WMA(CLOSE, 10), COLORYELLOW;

// the Hull average is built from two WMAs
HULL: WMA(2 * WMA(CLOSE, 5) - WMA(CLOSE, 10), 3), COLORLIBLUE;
MEMA(X, N)

Smoothed average: Y = (X + (N−1)·Y') / N.

X(series)
The series to smooth.
N(integer)
Number of bars. Equivalent to SMA(X, N, 1).
// smoother than EMA at the same length — the tail lags more
MEMA20: MEMA(CLOSE, 20), COLORYELLOW;
EMA20:  EMA(CLOSE, 20),  COLORGRAY;
XMA(X, N)

Moving average that starts producing values before the window is full.

X(series)
The series to average.
N(integer)
Number of bars. Early bars average whatever is available so far.
// MA leaves a gap at the left edge, XMA does not —
// handy when the chart only holds a short history
MA60:  MA(CLOSE, 60),  COLORGRAY;
XMA60: XMA(CLOSE, 60), COLORYELLOW;
AMA(X, A)

Adaptive moving average: Y = Y' + A·(X − Y'), with A below 1.

X(series)
The series to track.
A(series)
How much of the gap to close each bar, below 1. Larger follows price faster.
// speed up when price trends, slow down when it chops:
// efficiency = net move / total travel over 10 bars
EFF := ABS(CLOSE - REF(CLOSE, 10)) / SUM(ABS(CLOSE - REF(CLOSE, 1)), 10);
KAMA: AMA(CLOSE, EFF * 0.6), COLORYELLOW;
TMA(X, A, B)

Two-coefficient moving average: Y = A·Y' + B·X, both below 1.

X(series)
The series to smooth.
A(float)
Weight carried over from the previous bar, below 1.
B(float)
Weight of the current bar, below 1. A + B need not be 1 — that is the point of having both.
// A + B = 1 behaves exactly like EMA with weight 0.2
LIKE_EMA: TMA(CLOSE, 0.8, 0.2), COLORGRAY;
// A + B < 1 lets the line decay toward zero between moves
DECAYING: TMA(CLOSE, 0.8, 0.1), COLORYELLOW;
TRMA(X, N)

Triangular moving average — a simple average applied twice.

X(series)
The series to average.
N(integer)
Number of bars for the outer window; the inner average uses about half of it.
// averaging twice kills most of the noise, at the cost of lag
TRMA20: TRMA(CLOSE, 20), COLORYELLOW;
MA20:   MA(CLOSE, 20),   COLORGRAY;
HARMEAN(X, N)

Harmonic mean over N bars. Any zero in the window invalidates the result.

X(series)
The series to average. Must stay non-zero across the window.
N(integer)
Number of bars in the window.
// the harmonic mean sits below the simple mean and is pulled
// down harder by small values — use it on rates, not prices
HM: HARMEAN(CLOSE, 20), COLORYELLOW;
AM: MA(CLOSE, 20),      COLORGRAY;
TSMA(X, N)

Linear regression value plus its slope — the trend line projected one bar forward.

X(series)
The series to fit.
N(integer)
Number of bars in the regression window.
// the regression line, extended one bar into the future
TSMA20: TSMA(CLOSE, 20), COLORYELLOW;

// price above the projection while the slope is up
LONG := CLOSE > TSMA20 AND SLOPE(CLOSE, 20) > 0;
DRAWICON(LONG AND NOT(REF(LONG, 1)), LOW, 85);