Inputs and visuals
Expose clear settings, organise them, and choose the right plot for each output.
Inputs are the settings traders see when they click the gear on a script’s legend row. Give them clear labels and sensible ranges; defaults should produce a useful chart without any configuration.
script "MA spread"
input (
fastLength = input.int(12, title: "Fast length", min: 1, max: 200)
slowLength = input.int(26, title: "Slow length", min: 2, max: 400)
bullishColor = input.color(color.green, title: "Bullish")
bearishColor = input.color(color.red, title: "Bearish", sameLine: true)
)
data chart = subscribe(data.ohlcv)
plot spread = plot.histogram(title: "MA spread")
on chart.close {
let fast = ta.ema(chart.close, fastLength)
let slow = ta.ema(chart.close, slowLength)
let value: float? = fast == null || slow == null ? null : (fast ?? 0.0) - (slow ?? 0.0)
spread.plot(value, color: (value ?? 0.0) >= 0.0 ? bullishColor : bearishColor)
}A vertical histogram without on: gets its own pane automatically, named after the
script. Other plots go on the price pane unless you declare a pane and pass on:.
Input kinds
| Constructor | Value | Notes |
|---|---|---|
input.int(default, min:, max:) | int | A number field. |
input.float(default, min:, max:) | float | A number field. |
input.bool(default) | bool | A switch. |
input.color(default) | color | A colour picker. |
input.select(default, options: [...]) | string | A dropdown of text options. |
input.timeframe(default) | timeframe | A timeframe. |
input.exchange(default), input.exchanges(default) | string, string[] | Exchange pickers. |
Every input takes title:, description: (a tooltip), key: (keeps saved settings
when you rename the binding), sameLine: and when: (show the input only when a
condition on other inputs holds). Changing an input re-runs the script over the
loaded history.
On a chart, the settings dialog edits number, switch, colour and dropdown inputs; timeframe and exchange inputs keep their defaults there.
Organise long settings
Layout rows are written without a binding:
script "Organised settings"
input (
input.section(title: "Trend")
trendLength = input.int(50, title: "Length", min: 2)
showTrend = input.bool(true, title: "Show", sameLine: true)
input.section(title: "Signals")
signalStyle = input.select("Markers", title: "Style", options: ["Markers", "Background"])
)
data chart = subscribe(data.ohlcv)
plot (
trend = plot.line(title: "Trend", color: color.blue)
marks = plot.marker(title: "Above trend", shape: shape.circle, color: color.teal, size: 6.0)
bg = plot.bg(title: "Above trend", color: #26A69A18)
)
on chart.close {
let avg = ta.sma(chart.close, trendLength)
trend.plot(showTrend ? avg : null)
let above = (chart.close ?? 0.0) > (avg ?? 0.0)
if above && signalStyle == "Markers" {
marks.plot(chart.high)
}
if above && signalStyle == "Background" {
bg.plot()
}
}For a visibility switch, keep the plot declared and feed it null when hidden, as
trend does above, so the script’s outputs stay the same.
Choose the plot
| Plot | Use it for |
|---|---|
plot.line | Averages, bands, oscillators. style: linestyle.dotted, dashed or step; area: true shades below. |
plot.histogram | Signed quantities such as delta, from zero, coloured per bar. |
plot.candle, plot.bar | OHLC of another series, such as a higher timeframe or a synthetic index. |
plot.point | Sparse values as dots. |
plot.marker | Events at a price, with a shape:. |
plot.arrow | Up or down events; the value’s sign is the direction. |
plot.label | Short text at a price. |
plot.bg | Tint the bars where a condition holds. |
plot.cells | Rows of cells inside each bar: footprints, per-bar profiles, ladders. |
fill.between | Shade between two lines. |
Free-form drawings (lines, boxes, labels anchored to the pane) are entity pools; see repainting for the pattern of drawing at the live edge.
Cells inside a bar
plot.cells draws rows of cells inside each bar: a price band, a width, colours and
a number. It keeps them for far more bars than box entities can. This is a bid x ask
footprint on rows of 25, with the chart’s candles as a thin strip beside it:
script "Footprint cells"
data (
chart = subscribe(data.ohlcv)
vol = subscribe(data.volume)
)
plot footprint = plot.cells(
title: "Bid x Ask",
columns: 2,
candles: cellcandles.side,
format: cellformat.fixed,
decimals: 2,
)
on chart.update {
let rows = vol.bucketsByStep(25.0)
if rows != null {
footprint.clear(time: rows.time)
for row in rows {
footprint.cell(row.from, row.to, weight: row.sell, value: row.sell, color: #e0443a80, column: 0,
align: align.right, time: rows.time)
footprint.cell(row.from, row.to, weight: row.buy, value: row.buy, color: #2fa66a80, column: 1,
time: rows.time)
}
}
}- Columns. A bar has 1 to 4 columns side by side;
column:picks one,align:the edge a cell’s width grows from. - Width.
weight:is compared as the plot’sscale:says: with the largest weight on its own bar (cellscale.bar, the default), with the largest on the visible bars (cellscale.view), or taken as the width itself from 0 to 1 (cellscale.unit). Without a weight the cell fills its column. - Numbers.
value:is written in the cell when it fits.format:,decimals:,sign:andgrouping:choose3.21K,3214.56,+3,215or15.3%; a bar too narrow for that is written with fewer digits. - Candles.
candles:leaves the chart’s candles as they are (cellcandles.overlay), draws them as a thin strip at the left of each bar (cellcandles.side) or hides them (cellcandles.hidden). - Steps. The first
cellorclearfor a bar in a handler call discards what the bar held before, so a script redraws a bar by writing it again. Callclearwhere a bar may end up with no cells.
bucketsByStep puts the rows on whole multiples of the step, so the same price is
the same row on every bar. A bar holds up to 1024 cells per plot.