Recipes
Cookbook of complete DeltaDSL scripts. Trend ribbons, divergence detectors, anchored VWAPs, volume profile heatmaps, multi-pane composites, alert wiring patterns.
Every recipe below is a complete, self-contained script. Drop it into the editor, hit Save, and it should run on any chart. They're written to be readable end-to-end — paste, edit, learn.
The scripts use the project palette (Binance bull / bear, amber chrome). Adjust hues for your taste.
Trend ribbon (two-color MA)
A 50-period SMA painted green when price is above and red when price is below. Filled band between fast and slow MAs gives an at-a-glance "trend strength" cue.
@name "Trend Ribbon"
@pane "overlay"
@input fastLen = input.int(20, "Fast", minval=2, maxval=200, step=1)
@input slowLen = input.int(50, "Slow", minval=5, maxval=500, step=1)
fast = sma(close, fastLen)
slow = sma(close, slowLen)
upRegime = fast > slow
upBand = mask(fast, upRegime)
dnBand = mask(fast, upRegime == false)
plotBand(fast, slow, color="rgba(14,203,129,0.10)")
plotLine(upBand, color="#0ECB81", width=2)
plotLine(dnBand, color="#F6465D", width=2)
plotLine(slow, color="rgba(255,255,255,0.4)", width=1)
flipUp = crossover(fast, slow)
flipDn = crossunder(fast, slow)
plotShape(flipUp, low, shape="arrowUp", color="#0ECB81", size=10)
plotShape(flipDn, high, shape="arrowDown", color="#F6465D", size=10)
alertcondition(flipUp,
title="Trend flipped UP",
message="{{symbol}} {{interval}}: trend flipped UP at {{price}}")
alertcondition(flipDn,
title="Trend flipped DOWN",
message="{{symbol}} {{interval}}: trend flipped DOWN at {{price}}")
Anchored VWAP from session start
Reset VWAP at every UTC session start (hour == 0).
@name "Session VWAP"
@pane "overlay"
@input devs = input.float(2.0, "Bands deviations", minval=0, maxval=5, step=0.25)
src = hlc3
v = volume
isNewSession = hour(time) == 0 and hour(time[1]) == 23
cumPv = iff(isNewSession, src * v, nz(prev(cumPv)) + src * v)
cumVol = iff(isNewSession, v, nz(prev(cumVol)) + v)
vwap = cumPv / cumVol
cumDev2 = iff(isNewSession,
(src - vwap) * (src - vwap) * v,
nz(prev(cumDev2)) + (src - vwap) * (src - vwap) * v)
variance = cumDev2 / cumVol
stdDev = sqrt(variance)
upper = vwap + stdDev * devs
lower = vwap - stdDev * devs
plotLine(vwap, color="#F0B90B", width=2)
plotLine(upper, color="rgba(240,185,11,0.5)", width=1)
plotLine(lower, color="rgba(240,185,11,0.5)", width=1)
plotBand(upper, lower, color="rgba(240,185,11,0.06)")
Note: the
iffrecursion above usesprev(...)to read each accumulator's previous bar — it's the canonical "running sum that resets on a flag" pattern. Each accumulator is a self-referential series.
RSI bullish / bearish divergence
Detects regular divergence between price and RSI using pivots. Plots arrows on hits and wires alerts.
@name "RSI Divergence"
@pane "below"
@input rsiLen = input.int(14, "RSI period", minval=2, maxval=200)
@input pivL = input.int(5, "Pivot left", minval=2, maxval=20)
@input pivR = input.int(5, "Pivot right", minval=2, maxval=20)
paneHeight(0.25)
paneRange(0, 100)
r = rsi(close, rsiLen)
pricePivLow = pivotlow(low, pivL, pivR)
pricePivHigh = pivothigh(high, pivL, pivR)
rsiPivLow = pivotlow(r, pivL, pivR)
rsiPivHigh = pivothigh(r, pivL, pivR)
priceLowPrev = valuewhen(pricePivLow != na, low, 1)
priceLowCurr = valuewhen(pricePivLow != na, low, 0)
rsiLowPrev = valuewhen(rsiPivLow != na, r, 1)
rsiLowCurr = valuewhen(rsiPivLow != na, r, 0)
priceHighPrev = valuewhen(pricePivHigh != na, high, 1)
priceHighCurr = valuewhen(pricePivHigh != na, high, 0)
rsiHighPrev = valuewhen(rsiPivHigh != na, r, 1)
rsiHighCurr = valuewhen(rsiPivHigh != na, r, 0)
bullDiv = (priceLowCurr < priceLowPrev) and (rsiLowCurr > rsiLowPrev)
bearDiv = (priceHighCurr > priceHighPrev) and (rsiHighCurr < rsiHighPrev)
paneLine(r, color="#F0B90B", width=1.5)
paneHline(70, color="rgba(246,70,93,0.5)")
paneHline(30, color="rgba(14,203,129,0.5)")
plotShape(bullDiv, low, shape="arrowUp", color="#0ECB81", size=10)
plotShape(bearDiv, high, shape="arrowDown", color="#F6465D", size=10)
alertcondition(bullDiv, title="Bull RSI divergence",
message="Bull RSI divergence on {{symbol}} {{interval}} at {{price}}")
alertcondition(bearDiv, title="Bear RSI divergence",
message="Bear RSI divergence on {{symbol}} {{interval}} at {{price}}")
MACD with two-tone histogram
Three-pane composite — MACD line, signal, two-tone histogram.
@name "MACD"
@pane "below"
@input fastLen = input.int(12, "Fast EMA", minval=2, maxval=200)
@input slowLen = input.int(26, "Slow EMA", minval=2, maxval=400)
@input signalLen = input.int(9, "Signal", minval=2, maxval=200)
paneHeight(0.25)
macd = macd_line(close, fastLen, slowLen)
signal = macd_signal(close, fastLen, slowLen, signalLen)
hist = macd_hist(close, fastLen, slowLen, signalLen)
posHist = mask(hist, hist >= 0)
negHist = mask(hist, hist < 0)
paneFill(posHist, base=0, color="rgba(14,203,129,0.5)")
paneFill(negHist, base=0, color="rgba(246,70,93,0.5)")
paneLine(macd, color="#0ECB81", width=1.5)
paneLine(signal, color="#F6465D", width=1.5)
paneHline(0, color="rgba(150,150,150,0.4)")
zeroCross = crossover(macd, 0)
alertcondition(crossover(macd, signal),
title="MACD crossed UP",
message="{{symbol}} {{interval}} MACD bullish")
alertcondition(crossunder(macd, signal),
title="MACD crossed DOWN",
message="{{symbol}} {{interval}} MACD bearish")
Donchian channel breakout
Classic 20-period Donchian breakout with persistent break boxes.
@name "Donchian Breakout"
@pane "overlay"
@input length = input.int(20, "Length", minval=2, maxval=200)
@input boxLength = input.int(50, "Box bars left of break", minval=10, maxval=500)
up = highest(high, length)
dn = lowest(low, length)
mid = (up + dn) * 0.5
plotLine(up, color="rgba(240,185,11,0.6)", width=1)
plotLine(dn, color="rgba(240,185,11,0.6)", width=1)
plotLine(mid, color="rgba(240,185,11,0.3)", width=1)
plotBand(up, dn, color="rgba(240,185,11,0.04)")
breakUp = crossover(close, up[1])
breakDn = crossunder(close, dn[1])
plotShape(breakUp, low, shape="arrowUp", color="#0ECB81", size=12)
plotShape(breakDn, high, shape="arrowDown", color="#F6465D", size=12)
alertcondition(breakUp, title="Donchian break UP",
message="Donchian break UP on {{symbol}} {{interval}}")
alertcondition(breakDn, title="Donchian break DOWN",
message="Donchian break DOWN on {{symbol}} {{interval}}")
Volume-weighted bar coloring
Color volume bars by both direction (up/down) AND magnitude (relative to MA).
@name "Volume Heat"
@pane "below"
@input volLen = input.int(20, "Volume MA", minval=2, maxval=200)
@input hotMult = input.float(2.0, "Hot threshold (xMA)", minval=1, maxval=10, step=0.1)
@input coldMult = input.float(0.5, "Cold threshold (xMA)", minval=0.1, maxval=1, step=0.05)
paneHeight(0.20)
vMa = sma(volume, volLen)
ratio = volume / vMa
upBar = close > open
hotUp = mask(volume, upBar and ratio > hotMult)
warmUp = mask(volume, upBar and ratio > 1.0 and ratio <= hotMult)
coolUp = mask(volume, upBar and ratio <= 1.0)
hotDn = mask(volume, upBar == false and ratio > hotMult)
warmDn = mask(volume, upBar == false and ratio > 1.0 and ratio <= hotMult)
coolDn = mask(volume, upBar == false and ratio <= 1.0)
paneFill(hotUp, base=0, color="rgba(14,203,129,0.95)")
paneFill(warmUp, base=0, color="rgba(14,203,129,0.55)")
paneFill(coolUp, base=0, color="rgba(14,203,129,0.20)")
paneFill(hotDn, base=0, color="rgba(246,70,93,0.95)")
paneFill(warmDn, base=0, color="rgba(246,70,93,0.55)")
paneFill(coolDn, base=0, color="rgba(246,70,93,0.20)")
paneLine(vMa, color="#F0B90B", width=1)
Persistent latest swing high/low labels
Drawing-tool integration — the lines behave like user-drawn horizontal lines (selectable, deletable from the chart toolbar).
@name "Latest Swing HUD"
@pane "overlay"
@input pivL = input.int(5, "Left", minval=2, maxval=20)
@input pivR = input.int(5, "Right", minval=2, maxval=20)
ph = pivothigh(high, pivL, pivR)
pl = pivotlow(low, pivL, pivR)
lastHigh = valuewhen(ph != na, ph, 0)
lastLow = valuewhen(pl != na, pl, 0)
drawingHline("swing_high", lastHigh, color="#F6465D", width=1)
drawingHline("swing_low", lastLow, color="#0ECB81", width=1)
labelNew("swing_high_lbl",
time[0], lastHigh,
"Swing High " + tostring(lastHigh, "0.00"),
pane="overlay", anchor="right",
color="#F6465D", textColor="#ffffff", size=11)
labelNew("swing_low_lbl",
time[0], lastLow,
"Swing Low " + tostring(lastLow, "0.00"),
pane="overlay", anchor="right",
color="#0ECB81", textColor="#ffffff", size=11)
The user can select either drawingHline, drag it, or delete it like any chart-drawn line. The script keeps painting the latest swing on top.
Z-score outlier highlighter
Highlights bars where the Z-score of returns exceeds 3 (rare events). Useful for spotting volatility regime changes.
@name "Z-Score Outliers"
@pane "below"
@input lookback = input.int(50, "Lookback", minval=10, maxval=500)
paneHeight(0.20)
ret = (close - close[1]) / close[1]
z = zscore(ret, lookback)
paneLine(z, color="#F0B90B", width=1.5)
paneHline(3, color="rgba(246,70,93,0.6)")
paneHline(-3, color="rgba(246,70,93,0.6)")
paneHline(0, color="rgba(150,150,150,0.4)")
high3 = z > 3
low3 = z < -3
bgcolor(iff(high3, "rgba(246,70,93,0.15)", iff(low3, "rgba(14,203,129,0.15)", "rgba(0,0,0,0)")))
plotShape(high3, high, shape="circle", color="#F6465D", size=8)
plotShape(low3, low, shape="circle", color="#0ECB81", size=8)
alertcondition(high3, title="Z > 3", message="{{symbol}} bullish Z-score outlier")
alertcondition(low3, title="Z < -3", message="{{symbol}} bearish Z-score outlier")
Pivot points (classic)
Daily pivots calculated from yesterday's HLC, drawn as persistent horizontal lines.
@name "Daily Pivots"
@pane "overlay"
@input n = input.int(1, "Days back (1 = yesterday)", minval=1, maxval=10)
isNewDay = dayofmonth(time) != dayofmonth(time[1])
dh = valuewhen(isNewDay, high[1], n - 1)
dl = valuewhen(isNewDay, low[1], n - 1)
dc = valuewhen(isNewDay, close[1], n - 1)
P = (dh + dl + dc) / 3
R1 = 2 * P - dl
S1 = 2 * P - dh
R2 = P + (dh - dl)
S2 = P - (dh - dl)
R3 = dh + 2 * (P - dl)
S3 = dl - 2 * (dh - P)
drawingHline("piv_p", P, color="#F0B90B", width=2)
drawingHline("piv_r1", R1, color="rgba(246,70,93,0.7)", width=1)
drawingHline("piv_s1", S1, color="rgba(14,203,129,0.7)", width=1)
drawingHline("piv_r2", R2, color="rgba(246,70,93,0.5)", width=1)
drawingHline("piv_s2", S2, color="rgba(14,203,129,0.5)", width=1)
drawingHline("piv_r3", R3, color="rgba(246,70,93,0.3)", width=1)
drawingHline("piv_s3", S3, color="rgba(14,203,129,0.3)", width=1)
Higher-timeframe MA overlay
Plot the 200-SMA from the 4h timeframe on a 1h chart by upsampling. (For a true higher-TF source, use requestSecurity once added to the language; today, the workaround is to compute via n*period.)
@name "MA200 (4h equivalent)"
@pane "overlay"
@input multiplier = input.int(4, "TF multiplier (4 = 4h on 1h chart)", minval=1, maxval=24)
ma = sma(close, 200 * multiplier)
plotLine(ma, color="#F0B90B", width=2)
This is an approximation — for exact higher-TF semantics on every chart, the right primitive is requestSecurity, which the language is roadmapped to add.
Linear regression channel
Standard / projected linear regression with stddev channels.
@name "LinReg Channel"
@pane "overlay"
@input length = input.int(100, "Length", minval=10, maxval=500)
@input devs = input.float(2.0, "StdDev", minval=0, maxval=4, step=0.25)
mid = linreg(close, length, 0)
res = close - mid
sd = stdev(res, length)
upper = mid + sd * devs
lower = mid - sd * devs
plotLine(mid, color="#F0B90B", width=2)
plotLine(upper, color="rgba(240,185,11,0.5)", width=1)
plotLine(lower, color="rgba(240,185,11,0.5)", width=1)
plotBand(upper, lower, color="rgba(240,185,11,0.05)")
Multi-condition signal stack
Combine three independent signals into a single "stacked" alert (only fires when all three line up).
@name "Stacked Signal"
@pane "overlay"
@input rsiLen = input.int(14, "RSI", minval=2, maxval=200)
@input maLen = input.int(50, "MA", minval=2, maxval=400)
ma = sma(close, maLen)
r = rsi(close, rsiLen)
hist = macd_hist(close, 12, 26, 9)
aboveMa = close > ma
rsiBull = r > 50
macdBull = hist > 0
stackedBull = aboveMa and rsiBull and macdBull
flipUp = stackedBull and (stackedBull[1] == false)
plotLine(ma, color="#F0B90B", width=2)
plotShape(flipUp, low, shape="arrowUp", color="#0ECB81", size=12)
alertcondition(flipUp,
title="Stacked bullish",
message="3-stack bullish on {{symbol}} {{interval}} at {{price}}")
The stackedBull and (stackedBull[1] == false) pattern fires the alert ONCE on the bar where all three flip green, not every bar where all three are still green.
Next
- Pitfalls — common mistakes the recipes above quietly avoid.
- Versioning — how to ship updates to a script others use.