Skip to content

VP Script

Reference

Everything a script can call. Names are as you type them; a leading namespace means it lives on that object.

Writing this with an AI assistant?

Copy the language, its full reference and its rules as one Markdown document, then paste it into a new chat before you ask for an indicator. Without it you will get Pine, which does not run here.

Open ChatGPTOpen Claude

It is also a plain URL, if your tool can fetch one: /docs/script/llms

Declaring the script

indicator(title, { shortTitle?, pane?, precision?, scale? })
Names the script and says where it draws. pane: 'separate' puts it below the price instead of on it.

The bars

open
Open of every bar, as a series.
high
High of every bar.
low
Low of every bar.
close
Close of every bar. The default source for most studies.
volume
Volume of every bar. Zero or absent on instruments that do not report it.
hl2
(high + low) / 2.
hlc3
(high + low + close) / 3, the typical price.
ohlc4
(open + high + low + close) / 4.
bars
The raw bar objects, when a series is not enough.
barCount
How many bars there are — bars.length, named for readability.
barAt(timeMs)
Where a timestamp falls on the time axis, as a FRACTIONAL bar index — the same resolution a { time } anchor uses. Past the last bar it extrapolates with the feed's own bar span, which is how a session box reaches its close before that bar exists. null when there is no bar duration to project against.

Inputs

input.float(title, default, { min?, max?, step?, group?, tooltip? })
A decimal — a multiplier, a threshold. Give a step: the spinner defaults to free-form, and arrow keys on a 0-to-1 ratio want 0.05, not 1.
input.color(title, default, { group?, tooltip? })
A colour, with an opacity slider attached.
input.string(title, default, { options?, group?, tooltip? })
Free text, or a dropdown when options is given.
input.timeframe(title, default, { options?, group?, tooltip? })
A resolution the reader can change — '5', '60', '1D'. Refuses a value the datafeed cannot read, naming the input, rather than letting it become a request nothing answers.
input.source(title, default?, { group?, tooltip? })
Lets the reader choose which price series feeds the study.

Drawing

plot(series, { title?, color?, width?, style?, lineStyle?, offset?, ignoreScale? })
Draw a series as a line, histogram, area, stepline or circles. color takes one colour or one per bar; offset displaces the DRAWING only, leaving the values where they were computed. Returns an id fill can use.
hline(price, { color?, lineStyle?, title? })
A horizontal line at a fixed price — a zero line, an overbought level.
fill(fromPlot, toPlot, { color?, offset? })
Shade the band between two plots, or between two fixed prices. color takes one colour or one per bar, so a cloud can change colour where its edges cross; the displacement follows the plots unless you say otherwise.
marker(condition, { shape?, color?, location?, text? })
A shape on every bar where the condition is truthy. The usual way to show a signal.
label(at, price, text, { color?, background?, size?, align?, offset? })
Text anchored at one price. at is a bar index, { index } or { time }. Newlines break as lines. offset displaces the drawing only, so a label can sit in the empty space right of the last bar.
line(pointA, pointB, { color?, width?, lineStyle?, extend?, offset? })
A segment between two points. Each point is { index, price } or { time, price }. Returns an id linefill can use. offset displaces the drawing only.
polyline(points, { color?, width?, lineStyle?, closed?, fillColor?, offset? })
A curve through many points, each { index, price } or { time, price }. Use it where a plot cannot: a plot is one value per BAR, and a curve sampled from intrabar data has several points inside one bar and none in the next. A fillColor closes the path.
linefill(lineA, lineB, { color? })
Shade the band between two lines, by the ids line() returned. The band is the quadrilateral between their endpoints, so two segments that do not span the same range give a wedge rather than a guess about where either continues.
box(cornerA, cornerB, { color?, fillColor?, text?, offset? })
A rectangle between two corners, each { index, price } or { time, price } — a session range, a supply zone. offset displaces the drawing only.
table(rows, { position?, background?, border?, color?, size? })
A dashboard pinned to a corner of the pane, below whatever chrome already covers it (the legend) — rows of cells, each a string or { text, color, background, align, bold, size }. Columns are measured and lined up for you. Use this rather than a label full of newlines: a label is anchored to a bar, so it slides off screen when you pan, and its columns cannot line up in a proportional font.
bgcolor(condition, { color? })
Tint the background of every bar where the condition is truthy.
barcolor(colors)
Recolour the price bars themselves. One entry per bar; null keeps a bar's normal colour.
plotcandle(open, high, low, close, { upColor?, downColor?, wickColor?, title? })
Draw your own OHLC series as candles — Heikin-Ashi, a smoothed series, another timeframe.

Indicators and statistics

ta.sma(source, length)
Simple moving average.
ta.ema(source, length)
Exponential moving average.
ta.rma(source, length)
Wilder's smoothing — what RSI and ATR are built on.
ta.wma(source, length)
Linearly weighted moving average.
ta.stdev(source, length)
Rolling standard deviation.
ta.rsi(source, length)
Relative Strength Index, 0 to 100.
ta.change(source, length?)
Difference from length bars ago (default 1).
ta.crossover(a, b)
True on the bar where a crosses above b.
ta.crossunder(a, b)
True on the bar where a crosses below b.
ta.cross(a, b)
True on a cross in either direction.
ta.highest(source, length)
Highest value over the last length bars.
ta.lowest(source, length)
Lowest value over the last length bars.
ta.midline(length)
Midpoint of the rolling high/low channel — the Donchian centre.
ta.atr(length)
Average true range.
ta.tr()
True range, unsmoothed.
ta.cum(source)
Running total from the first bar.
ta.dev(source, length)
Mean absolute deviation.
ta.rising(source, length)
True when the series rose on each of the last length bars.
ta.falling(source, length)
True when it fell on each of the last length bars.
ta.barssince(condition)
Bars since the condition was last true. 0 on the bar it is true.
ta.valuewhen(condition, source, occurrence?)
The value of source when the condition was last true.
ta.pivothigh(source, left, right)
Pivot high, reported right bars later — when it first becomes knowable, not when it happened.
ta.pivotlow(source, left, right)
Pivot low, on the same delayed basis.
ta.macd(source, fast?, slow?, signal?)
Returns the MACD line, its signal and the histogram.
ta.bb(source, length?, mult?)
Bollinger Bands: basis, upper and lower.
ta.kc(length?, mult?)
Keltner Channels, from ATR rather than deviation.
ta.cci(length?)
Commodity Channel Index.
ta.obv()
On-balance volume.
ta.mfi(length?)
Money Flow Index — RSI weighted by volume.
ta.roc(source, length)
Rate of change, as a percentage.
ta.mom(source, length)
Momentum — the raw difference.
ta.linreg(source, length, offset?)
Linear regression value at the end of the window.
ta.percentrank(source, length)
Where the current value sits in its own recent range, 0 to 100.
ta.correlation(a, b, length)
Rolling correlation between two series.
ta.stoch(k?, d?, smooth?)
Stochastic oscillator: %K and %D.
ta.supertrend(factor?, length?)
SuperTrend line and its direction.
ta.hma(source, length)
Hull moving average: weighted averages combined to reduce lag.
ta.swma(source)
Symmetrically weighted four-bar moving average using the fixed 1, 2, 2, 1 kernel.
ta.vwma(source, length)
Volume-weighted moving average. A bar without volume is a gap rather than a zero-weight observation.
ta.alma(source, length, offset?, sigma?)
Arnaud Legoux moving average. offset defaults to 0.85 and sigma to 6.
ta.vwap(source?)
Session-anchored volume-weighted average price. The source defaults to hlc3.
ta.dmi(diLength?, adxSmoothing?)
Wilder directional movement: returns { plus, minus, adx }. Both lengths default to 14.
ta.adx(diLength?, adxSmoothing?)
Average Directional Index without the two directional-indicator series.
ta.sar(start?, increment?, maximum?)
Parabolic SAR. Defaults are 0.02, 0.02 and 0.2.
ta.tsi(source, shortLength?, longLength?)
True Strength Index. The short and long smoothing lengths default to 13 and 25.
ta.cmo(source, length)
Chande Momentum Oscillator, from -100 to 100.
ta.wpr(length?)
Williams %R, from -100 to 0. The length defaults to 14.
ta.bbw(source, length?, mult?)
Bollinger bandwidth: the band's span as a fraction of its basis.
ta.variance(source, length)
Rolling population variance.
ta.cog(source, length)
Ehlers Centre of Gravity oscillator.
ta.highestbars(source, length)
Bars back to the window's highest value. Returns 0 or a negative offset.
ta.lowestbars(source, length)
Bars back to the window's lowest value. Returns 0 or a negative offset.
ta.percentile_linear_interpolation(source, length, percentage)
Rolling percentile with linear interpolation between neighbouring values.
ta.percentile_nearest_rank(source, length, percentage)
Rolling nearest-rank percentile; the answer is always a value that occurred in the window.
ta.mode(source, length)
Most frequent value in the window. Ties resolve to the smallest value.

Arithmetic that respects gaps

A series has holes, and a + b on a hole gives NaN — which draws as a break nobody asked for. These propagate the hole instead.

math.add(a, b)
Add two series, or a series and a number.
math.div(a, b)
Divide. Division by zero gives NaN, never Infinity.
math.abs(a)
Absolute value.
math.min(a, b)
Smaller of the two, bar by bar.
math.max(a, b)
Larger of the two, bar by bar.
math.shift(a, n)
Move a series forward (+) or back (−) by n bars.
math.pow(a, b)
Raise each value in a to the corresponding power in b. Either input may be a number or series.
math.sqrt(a)
Square root, bar by bar.
math.log(a)
Natural logarithm, bar by bar.
math.log10(a)
Base-10 logarithm, bar by bar.
math.exp(a)
Exponential function, bar by bar.
math.floor(a)
Round each value down to an integer.
math.ceil(a)
Round each value up to an integer.
math.sign(a)
Return -1, 0 or 1 for each value's sign.
math.round(a, decimals?)
Round each value to decimals places. Negative decimals values round to tens, hundreds and beyond.
math.avg(a, b)
Element-wise mean of two numbers or series.
math.clamp(a, low, high)
Clamp each value into the inclusive range from low to high.

The chart itself

Mostly for multi-timeframe studies: a layer finer than the chart is not a view of anything, and this is how a script declines to draw one.

timeframe.period
The chart's own resolution, as the datafeed spells it — '60', '1D', '1W'.
timeframe.seconds
How long one chart bar is, in seconds. 0 when the resolution cannot be parsed.
timeframe.secondsOf(resolution)
Any resolution's length in seconds — timeframe.secondsOf('1W') — or 0 if it cannot be read. Saves carrying your own table of resolution strings.
timeframe.compare(a, b)
-1 if a is shorter than b, 1 if longer, 0 if equal — or if either cannot be read, so an unknown resolution never hides a layer.

Time zones and sessions

Every one takes an epoch-millisecond time — a bar.time, or one from request.security_lower_tf — and an IANA zone name such as America/New_York. An unknown zone throws rather than answering in UTC: a session drawn five hours from where you put it looks entirely normal, and a refusal names the zone.

time.zoned(timeMs, zone)
Every wall-clock piece at once — { year, month, day, hour, minute, second, weekday, minuteOfDay, offsetMinutes }.
time.hour(timeMs, zone)
The hour in that zone, 0–23.
time.minute(timeMs, zone)
The minute past the hour.
time.minuteOfDay(timeMs, zone)
hour * 60 + minute — the form a session window is written in. 09:30 New York is 570.
time.dayOfWeek(timeMs, zone)
0 = Sunday, as Date has it.
time.offsetMinutes(timeMs, zone)
Minutes east of UTC at that instant, DST included. Subtract two to show one session's clock beside another's without a table that goes stale twice a year.
time.formatMinuteOfDay(minuteOfDay)
570 → '09:30'. Wraps past midnight in both directions.

Trading sessions

session.isIn(timeMs, spec, zone?)
Whether an instant is inside a trading session. The zone defaults to syminfo.timezone.
session.minutesInto(timeMs, spec, zone?)
Minutes since the session opened, or null outside it. The zone defaults to syminfo.timezone.

The instrument

syminfo
The frozen instrument descriptor: ticker, description, exchange, type, currency, mintick, pricescale, timezone and session.

Calculated colours

color.rgb(r, g, b, transp?)
Build a colour from 0-to-255 channels. Pine transparency is used: 0 is opaque and 100 is invisible.
color.new(color, transp)
Restate a colour at a new Pine-style transparency, replacing its existing alpha.
color.r(color)
Red channel, from 0 to 255.
color.g(color)
Green channel, from 0 to 255.
color.b(color)
Blue channel, from 0 to 255.
color.t(color)
Pine-style transparency, from 0 for opaque to 100 for invisible.
color.mix(from, to, weight)
Blend colours and alpha. A weight of 0 returns from; 1 returns to.
color.fromGradient(value, low, high, lowColor, highColor)
Map a clamped numeric range to a two-colour gradient.

Number formatting

str.number(value, decimals?)
A number with grouped thousands and a dot decimal separator. Decimals default to 2.
str.price(value, decimals?)
A price using the instrument's quoted tick precision unless decimals is provided.
str.percent(value, decimals?, fraction?)
A percentage string. Set fraction when 0.523 means 52.3 percent.
str.compact(value, decimals?)
Compact large numbers with K, M, B or T suffixes.

Other symbols and timeframes

request.security(symbol, resolution, compute?, { warmupBars? })
A value from another symbol or timeframe, projected causally: a foreign bar appears only from the chart bar that opened after it closed. warmupBars asks for extra history BEFORE the visible range, which an indicator with a long lookback needs.
request.security_lower_tf(symbol, resolution)
The finer bars INSIDE each chart bar, one array per bar. null where the finer feed does not fully cover the bar.

Alerts

alertcondition(condition, { title, message? })
Ask the host to watch a condition. Fires on closed bars only, at most once per bar, never for history.

While you are writing

Development only. Capture is refused for any script the reader did not write, so an installed indicator's log calls do nothing on their chart and you never have to strip them before publishing.

log(...values)
Print while you are writing. Shown in the editor's console for a script you wrote yourself, and captured for nobody else — a published indicator's log calls do nothing on a reader's chart, so you never have to strip them before publishing.

Found what you need? Open a chart and run it from the Scripts panel, or see how others use these functions in community indicators.