Docs·Delta DSL Script·Library

Built-in indicators

Moving averages (SMA/EMA/WMA/RMA/HMA/DEMA/TEMA/VWMA), oscillators (RSI/Stoch/CCI/MFI/MACD/Williams%R/Mom/ROC), volatility (ATR/BB/KC/DC), volume (OBV/AD/CMF/PVT), structure (pivots/Supertrend/DMI/ADX). Every canonical indicator in one page.

The indicators below are the same primitives our built-in catalog (RSI, MACD, Bollinger, etc.) uses internally. Every function is vectorised — input one or more series, get a series back. Combine them however you like.

This is a reference page; for usage patterns see Recipes.

Moving averages

sma(src, period)

Simple moving average. Sum of the last period bars divided by period. NaN during warmup.

Delta DSL
ma50  = sma(close, 50)
ma200 = sma(close, 200)

ema(src, period)

Exponential moving average with smoothing factor k = 2 / (period + 1). Reacts faster than sma to recent moves; never fully forgets old data.

Delta DSL
fast = ema(close, 12)
slow = ema(close, 26)
plotLine(fast - slow, color="#F0B90B")    // MACD-style spread

wma(src, period)

Linearly-weighted MA — older bars contribute progressively less. Smoother than sma, less laggy than ema.

rma(src, period)

Wilder's smoothed MA (k = 1 / period). Used by RSI, ADX, and ATR. Smoother than ema for the same period; sometimes called "running moving average".

hma(src, period)

Hull MA — designed for low lag with high smoothness. Approximately:

Delta DSL
hma = wma(2 * wma(src, period/2) - wma(src, period), sqrt(period))

dema(src, period), tema(src, period)

Double / Triple EMA — dema = 2*ema − ema(ema), tema = 3*ema − 3*ema(ema) + ema(ema(ema)). Less lag than EMA at the cost of more volatility on noisy inputs.

vwma(src, volume, period)

Volume-weighted moving average — Σ(src · vol) / Σ(vol) over period bars. Tracks where most of the volume actually traded, useful for institutional support/resistance.

Delta DSL
vwma20 = vwma(close, volume, 20)
plotLine(vwma20, color="#F0B90B", width=2)

Oscillators

rsi(src, period)

Wilder's Relative Strength Index. Returns values in [0, 100].

Delta DSL
@pane "below"

r = rsi(close, 14)
paneRange(0, 100)
paneLine(r, color="#F0B90B", width=1.5)
paneHline(70, color="rgba(246,70,93,0.6)")
paneHline(30, color="rgba(14,203,129,0.6)")

stoch_k(close, high, low, period)

Stochastic %K — 100 * (close − lowest(low, p)) / (highest(high, p) − lowest(low, p)).

stoch_d(close, high, low, kPeriod, dPeriod=3)

Stochastic %D — SMA of %K over dPeriod bars. The classic 14-3 stoch is stoch_d(close, high, low, 14, 3).

cci(high, low, close, period)

Commodity Channel Index — (typical − sma(typical)) / (0.015 · mean_abs_dev). Typical price is hlc3. CCI is unbounded; > +100 and < −100 are the canonical OB / OS levels.

mfi(high, low, close, volume, period)

Money Flow Index — volume-weighted RSI on typical price. Range [0, 100]. Better than RSI for confirming moves with volume.

willr(high, low, close, period)

Williams %R, range [−100, 0]. > −20 is overbought, < −80 is oversold. Inverted version of stoch %K.

mom(src, period)

Momentum — src[i] − src[i − period]. Raw difference; not normalized.

roc(src, period)

Rate of Change — 100 · (src − src[period]) / src[period]. Percentage version of mom.

macd_line(src, fast, slow), macd_signal(src, fast, slow, signal), macd_hist(src, fast, slow, signal)

MACD components. line = ema(src, fast) − ema(src, slow). signal = ema(line, signal). hist = line − signal. Default config is (close, 12, 26, 9).

Delta DSL
@pane "below"

line = macd_line(close, 12, 26)
sig  = macd_signal(close, 12, 26, 9)
hist = macd_hist(close, 12, 26, 9)

paneFill(hist, base=0, color="rgba(240,185,11,0.4)")
paneLine(line, color="#0ECB81", width=1.5)
paneLine(sig,  color="#F6465D", width=1.5)

Volatility / channels

tr(high, low, close)

True Range — max(high − low, |high − close[1]|, |low − close[1]|). Captures the full bar including overnight gaps.

atr(high, low, close, period)

Average True Range — Wilder smoothing of tr. Standard volatility metric used by Supertrend, Keltner channels, and most stop-loss formulas.

Delta DSL
@input atrMult = input.float(1.5, "ATR multiplier", minval=0.5, maxval=5.0, step=0.1)

stop = close - atr(high, low, close, 14) * atrMult
plotLine(stop, color="rgba(246,70,93,0.7)", width=1)

bb_basis(src, period), bb_upper(src, period, mult), bb_lower(src, period, mult)

Bollinger Bands. basis = sma(src, p), upper = basis + mult · stdev(src, p), lower = basis − mult · stdev(src, p). Default (close, 20, 2).

Delta DSL
mid   = bb_basis(close, 20)
upper = bb_upper(close, 20, 2)
lower = bb_lower(close, 20, 2)

plotLine(mid,   color="#F0B90B")
plotLine(upper, color="rgba(240,185,11,0.5)")
plotLine(lower, color="rgba(240,185,11,0.5)")
plotBand(upper, lower, color="rgba(240,185,11,0.04)")

kc_basis(src, period), kc_upper(src, high, low, close, period, mult), kc_lower(src, high, low, close, period, mult)

Keltner Channels — EMA basis with ATR-scaled bands.

Delta DSL
basis = kc_basis(close, 20)
upper = kc_upper(close, high, low, close, 20, 1.5)
lower = kc_lower(close, high, low, close, 20, 1.5)

dc_upper(high, period), dc_lower(low, period), dc_basis(high, low, period)

Donchian Channels — straight rolling-extreme bands. upper = highest(high, p), lower = lowest(low, p), basis = (upper + lower) / 2. Used by trend-following systems (Turtle Trading uses 20-day Donchian breakouts).

Volume / accumulation

obv(close, volume)

On-Balance Volume — cumulative volume signed by close direction. Adds today's volume on up bars, subtracts on down bars, ignores flat bars.

Delta DSL
@pane "below"
o = obv(close, volume)
paneLine(o, color="#F0B90B")

ad(high, low, close, volume)

Accumulation/Distribution Line — cumulative MFM · volume where MFM = ((close − low) − (high − close)) / (high − low). Reads buying / selling pressure within each bar.

cmf(high, low, close, volume, period)

Chaikin Money Flow — Σ(MFM · volume) / Σ(volume) over period bars. Range [−1, +1]. > 0.1 and < −0.1 are the canonical thresholds.

pvt(close, volume)

Price-Volume Trend — cumulative (change(close) / close[1]) · volume. Similar to OBV but weighted by the percentage move, so big moves contribute more than small ones.

Market structure

pivothigh(src, left, right)

Returns src[i − right] if it is the strict maximum of the left + right + 1 window centred right bars in the past. NaN on every non-pivot bar.

Delta DSL
ph = pivothigh(high, 5, 5)         // 5-bar swing pivot

// Continuous step line that updates on each new pivot:
phLine = fixnan(ph)
plotLine(phLine, color="rgba(14,203,129,0.6)", width=1)

The output is lagging by right bars — that's structural, not a bug. A pivot is only confirmable once right bars after it have closed.

pivotlow(src, left, right)

Symmetric to pivothigh.

pivotAvg(pivotSeries, count)

Stair-step rolling average of the last count non-NaN pivots in pivotSeries. Updates on every new pivot, carries forward between events.

Delta DSL
ph    = pivothigh(high, 5, 5)
pl    = pivotlow(low,  5, 5)

phAvg = pivotAvg(ph, 3)            // average of the last 3 swing highs
plAvg = pivotAvg(pl, 3)

plotLine(phAvg, color="rgba(14,203,129,0.7)", width=1.5)
plotLine(plAvg, color="rgba(246,70,93,0.7)",  width=1.5)

supertrend(high, low, close, atrPeriod, mult)

Supertrend BAND value — the visible trail line. Below price during uptrends, above price during downtrends.

supertrend_dir(high, low, close, atrPeriod, mult)

Supertrend direction series — +1 during bull trends, −1 during bear trends. Pair with supertrend for two-tone plotting:

Delta DSL
band = supertrend(high, low, close, 10, 3.0)
dir  = supertrend_dir(high, low, close, 10, 3.0)

bull = mask(band, dir == 1)
bear = mask(band, dir == -1)

plotLine(bull, color="#0ECB81", width=2)
plotLine(bear, color="#F6465D", width=2)

trail(close, upBand, dnBand, initDir=1)

Generic ratcheting trail with caller-supplied bands. Supertrend is one fixed parameterisation of "follow the trend at a distance" — HL2 ± mult × ATR with a ratchet so the band only tightens. Lots of Pine indicators (Chandelier Exit, JMA Trail, Volatility Stop, Range Anchor, every "Supertrend ON INDICATOR" reskin) want the same recurrence but with a DIFFERENT basis (EMA × volatility, Donchian mid ± stdev, pivot ± fixed offset, …). trail() lets the script compute the two bands itself and outsources the ratcheting state machine to the stdlib — without it, the Pine var float trail := … recurrence has no bulk-vector closed form.

Recurrence (see lib/structure.js for the full implementation):

  • Bull regime (dir > 0): trail := max(upBand[i], trail[i-1]) — ratchet UP only. When close < trail, flip to bear and jump to dnBand[i].
  • Bear regime (dir < 0): trail := min(dnBand[i], trail[i-1]) — ratchet DOWN only. When close > trail, flip to bull and jump to upBand[i].

Drop-in for any EMA-based Supertrend variant:

Delta DSL
@input basisLen   = input.int(28,   "Basis length", minval=1, maxval=200)
@input volLen     = input.int(15,   "Volatility length", minval=1, maxval=100)
@input volMult    = input.float(1.25, "Trail × volatility", minval=0.5, maxval=8.0, step=0.25)

ma     = ema(close, basisLen)
volr   = atr(high, low, close, volLen)
upBand = ma - volr * volMult         // bull-side target (tighter when price > ma)
dnBand = ma + volr * volMult         // bear-side target (wider when price < ma)

drift = trail(close, upBand, dnBand, 1)
dir   = trail_dir(close, upBand, dnBand, 1)

plotLine(mask(drift, dir ==  1), color="#0ECB81", width=2)
plotLine(mask(drift, dir == -1), color="#F6465D", width=2)

Other parametrisations the same primitive covers:

  • Chandelier Exit: upBand = highest(high, n) - mult * atr(...), dnBand = lowest(low, n) + mult * atr(...).
  • Pivot Trail: upBand = lastSwingLow + cushion, dnBand = lastSwingHigh - cushion (using valuewhen + pivot*).
  • Donchian Trail: upBand = dc_basis(...) - margin, dnBand = dc_basis(...) + margin.
  • JMA Trail: replace ema with the user's preferred smoother.

initDir seeds the regime on the first valid bar (+1 starts bull, -1 starts bear). The first close-vs-trail check immediately on bar 1 corrects the seed if the market already disagrees.

trail_dir(close, upBand, dnBand, initDir=1)

Companion +1 / -1 direction series for the same trail. Cheap to call alongside trail() (each is an independent O(N) pass — no shared cache to avoid stale state when inputs change between renders). Use the direction series to drive mask(...) for two-tone plotting and crossover(dir, 0) / crossunder(dir, 0) for flip events.

plus_di(high, low, close, period), minus_di(high, low, close, period)

Wilder's Directional Movement Indicator — +DI and −DI lines. Compare the two to gauge trend direction; combine with ADX for trend strength.

adx(high, low, close, period)

Average Directional Index — 100 · ema(|+DI − -DI| / (+DI + -DI), period) (Wilder smoothing). Range [0, 100]. > 25 is the canonical "trending" threshold; < 20 indicates ranging.

Delta DSL
@pane "below"

di_plus  = plus_di(high, low, close, 14)
di_minus = minus_di(high, low, close, 14)
ax       = adx(high, low, close, 14)

paneRange(0, 100)
paneLine(di_plus,  color="#0ECB81", width=1.2)
paneLine(di_minus, color="#F6465D", width=1.2)
paneLine(ax,       color="#F0B90B", width=2)
paneHline(25, color="rgba(255,255,255,0.25)")

Composite recipes

A few common multi-indicator setups:

Squeeze breakout

Delta DSL
@input length = input.int(20, "Length", minval=5, maxval=200)
@input bbMult = input.float(2.0, "BB mult")
@input kcMult = input.float(1.5, "KC mult")

bbU = bb_upper(close, length, bbMult)
bbL = bb_lower(close, length, bbMult)
kcU = kc_upper(close, high, low, close, length, kcMult)
kcL = kc_lower(close, high, low, close, length, kcMult)

inSqueeze = (bbU < kcU) and (bbL > kcL)
plotBgColor(inSqueeze, color="rgba(240,185,11,0.06)")

breakUp   = crossunder(bbU, kcU) == false and not inSqueeze and shift(inSqueeze, 1)
breakDown = breakUp                          // simplified; real implementation tracks direction

Momentum + trend gate

Delta DSL
@input rsiThresh = input.int(55, "RSI bull threshold", minval=50, maxval=70)
@input adxThresh = input.int(25, "ADX trend threshold", minval=15, maxval=40)

trendOk = adx(high, low, close, 14) > adxThresh
momoOk  = rsi(close, 14) > rsiThresh

bullishGate = trendOk and momoOk
plotShape(crossover(close, sma(close, 50)) and bullishGate,
          low, shape="arrowUp", color="#0ECB81", size=8)

Choosing the right indicator

GoalReach for
Smooth average of pricesma, ema, wma, rma
Volume-aware averagevwma
Low-lag MAhma, dema, tema
Overbought / oversoldrsi, stoch_k + stoch_d, cci, willr, mfi
Trend strengthadx, plus_di vs minus_di
Volatility-scaled stop / bandatr, bb_*, kc_*
Breakout channeldc_*, bb_*
Volume pressureobv, ad, cmf, pvt, mfi
Swing structurepivothigh, pivotlow, pivotAvg
Continuous trend signal (HL2 ± ATR)supertrend + supertrend_dir
Continuous trend signal (custom basis)trail + trail_dir
Anchored cumulative (session VWAP, etc.)cumReset + maxSinceReset + minSinceReset (see Series)

Next

  • Statisticsstdev, correlation, linreg, polyreg2, zscore.
  • Drawing — turning these series into chart objects.
  • Recipes — full scripts that combine multiple indicators.