Docs·Delta DSL Script·Drawing

Panes

How @pane controls where your indicator lives — overlay on candles, sub-pane below, or a custom aux pane shared across multiple scripts. Plus paneRange / paneHeight tuning.

The @pane directive at the top of a script picks where the indicator renders. Three shapes are accepted:

@pane valueWhere it rendersY axis
"overlay" (default, or omit)On the candle panePrice
"below"A reserved band at the bottom of the candle areaPane value space (auto or paneRange)
Any other id (e.g. "rsi", "macd")A dedicated aux pane keyed by idPane value space

Every drawing primitive belongs to one of three categories — overlay-only, pane-only, either-or. Calling a pane primitive from an @pane "overlay" script renders the value at its raw price-space coordinate (which usually looks wrong — RSI 0-100 collapses into a 50-tick band on a chart trading at $50k). The mismatch is intentional: it's a visible cue that the @pane directive is missing.

Overlay (@pane "overlay", default)

The script paints on the candle pane. Use this for moving averages, support / resistance, anchored VWAPs, range boxes — anything in price space.

Available primitives: every plot* function plus the world-coord primitives (plotLineXY, plotBox, plotLabel, …) and persistent slots (labelNew / boxNew / lineNew / polylineNew) with pane="overlay".

Delta DSL
@name "Anchored VWAP"
@pane "overlay"

@input length = input.int(50, "Length", minval=10, maxval=500)

vw = sum(close * volume, length) / sum(volume, length)
plotLine(vw, color="#F0B90B", width=2)

bb_u = bb_upper(close, length, 2)
bb_l = bb_lower(close, length, 2)

plotLine(bb_u, color="rgba(240,185,11,0.5)")
plotLine(bb_l, color="rgba(240,185,11,0.5)")
plotBand(bb_u, bb_l, color="rgba(240,185,11,0.04)")

Drawing oscillators on the overlay

Native overlay mode draws values in their own numeric range. An RSI line plotted on a Bitcoin chart appears at y = 70 (not 70 in the price scale, but 70 dollars), invisible against price candles in the thousands. To display an oscillator on the candle pane, use normalize to map it into the visible price range:

Delta DSL
@pane "overlay"

r = rsi(close, 14)
priceLow  = lowest(low,  200)
priceHigh = highest(high, 200)

rsiOverlay = normalize(r, 0, 100, priceLow, priceHigh)
plotLine(rsiOverlay, color="#F0B90B", width=1.5)

normalize accepts series for both toMin and toMax, so the overlay tracks the visible price window as the user pans / zooms.

For most oscillators this trick is unnecessary — just use @pane "below" instead.

Sub-pane (@pane "below")

@pane "below" reserves a band at the bottom of the candle area, masks the candles behind it opaque, and remaps every pane* call into the band. The pane has its own Y axis with three labels (min / mid / max) and the script's @name displayed in the top-left.

Delta DSL
@pane "below"
@name "RSI"

@input period = input.int(14, "Period", minval=2, maxval=200)

paneHeight(0.25)        // 25 % of the candle area (0.10..0.50)
paneRange(0, 100)       // lock the Y axis (omit to auto-fit)

r = rsi(close, period)

paneBand(70, 30, color="rgba(240,185,11,0.06)")
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)")
paneLabel(70, "70", align="left")
paneLabel(30, "30", align="left")

Pane primitives

FunctionPurpose
paneLine(series, color, width=1.5)Polyline inside the band
paneDashedLine(series, color, width=1, dash, gap)Dashed polyline
paneHline(value, color, width=1)Horizontal at a fixed pane value
paneBand(upper, lower, color)Filled band between two pane series
paneFill(series, base=0, color)Histogram fill between base and series[i]
paneCandle(open, high, low, close, …)Per-bar OHLC inside the pane
paneLabel(value, text, color, size=10, align)Annotate a level
paneRange(min, max)Lock Y axis (else auto-fit each frame)
paneHeight(ratio)Pane height as fraction of candle area, 0.10..0.50
panePlotLine, panePlotVLine, panePlotBox, panePlotLabelWorld-coord pane primitives

paneRange and paneHeight

Both are one-shot configuration calls. Call each once near the top of the script. Multiple calls override (the last wins).

  • paneRange(min, max) locks the Y axis. Without it, the engine auto-scans every pane draw call for the visible window's [min, max] each frame, which is right for MACD-style indicators but produces a "wobbling" axis on RSI (range expands the moment the line touches a new extreme).
  • paneHeight(ratio) sets the pane's vertical real estate as a fraction of the candle area. The default is 0.25 (a quarter of the chart). Range: 0.10 (a thin strip) to 0.50 (half the chart).

When to use paneFill vs paneBand

You wantReach for
Solid colour between TWO seriespaneBand(upper, lower, color)
Histogram bars from 0 (or a fixed value)paneFill(series, base=0, color)

paneFill is the canonical primitive for MACD histograms, momentum bars, anything zero-anchored.

Delta DSL
@pane "below"

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

// Two-tone histogram (positive / negative bars):
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(line, color="#0ECB81", width=1.5)
paneLine(sig,  color="#F6465D", width=1.5)

Pane size on mobile

The paneHeight(0.25) ratio applies on every device. On phones (where the chart area is short), this means the pane consumes roughly the same fraction of available space — usually the right call. If the user has the chart maximised on desktop and the pane looks too tall, drop to 0.18 or 0.20.

Custom aux panes (any other id)

Any string that is not "overlay" or "below" allocates a dedicated aux pane. Two scripts using the same id share one band — useful for compound indicators (MACD line + signal + histogram all in @pane "macd"). Different ids stack vertically in registration order.

Delta DSL
@pane "rsi"
@name "RSI"
@input period = input.int(14, "Period")

paneHeight(0.18)
paneRange(0, 100)

r = rsi(close, period)
paneBand(70, 30, color="rgba(240,185,11,0.06)")
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)")

Pane id rules

  • Lowercase letters, digits, _, and - only.
  • Maximum 32 characters.
  • "overlay" and "below" are reserved.

Sharing a pane across scripts

Two scripts with the same aux pane id collapse onto one band. They keep separate slot tables (a lineNew("trail", …) in each script doesn't conflict) but share the pane's Y axis.

Delta DSL
// Script A
@pane "macd"
@name "MACD line"
hist = macd_hist(close, 12, 26, 9)
paneFill(hist, base=0, color="rgba(240,185,11,0.4)")

// Script B (separate file, same chart)
@pane "macd"
@name "MACD signals"
line = macd_line(close, 12, 26)
sig  = macd_signal(close, 12, 26, 9)
paneLine(line, color="#0ECB81")
paneLine(sig,  color="#F6465D")

Both scripts paint into the same aux band. Disable / re-enable to reorder.

Stacking multiple aux panes

Different ids → different bands, registered in script-load order:

Delta DSL
// Script A → @pane "rsi"
// Script B → @pane "macd"
// Script C → @pane "vol"

The user sees three stacked panes below the candles. The order is fixed at registration time; to reorder, disable + re-enable in the desired sequence.

Persistent slots in a pane

Every persistent slot primitive (labelNew, boxNew, lineNew, polylineNew) accepts a pane= argument so a single script can scatter HUDs across multiple panes:

Delta DSL
@pane "rsi"
@name "RSI HUD"

r = rsi(close, 14)

labelNew("rsi_value", time[0], r[0], "RSI " + tostring(r[0], "0.0"),
         pane="rsi", anchor="left", color="#F0B90B")

The label lives in the "rsi" pane's slot table, distinct from any "overlay" or "below" slots the script might also be using.

Limitations

  • Aux pane order is registration order. To reorder, disable the scripts in the order you want and re-enable.
  • The legacy "below" pane is one shared band — any script with @pane "below" paints into it. Use a custom id for true separation.
  • Crosshair price reads from the candle pane on the candle area; over an aux pane it reads that pane's value space. The legacy "below" pane still reports candle price for backwards compatibility.

Next