# EdgeVault script language EdgeVault has its own small language for chart scripts: indicators that plot lines, mark bars, shade the background and raise alerts. This page is the whole reference. Everything in it is read from the checker that runs a script, so a script that follows it is accepted. Instructions for an AI assistant writing a script from this page: - Reply with one script and nothing else unless asked, in a code block, starting with a script "Title" overlay or script "Title" pane line. - Use only the statements, functions, series and arguments listed here. If a function is not listed it does not exist. Do not write Pine. - A script is facts about candles drawn on a chart. It does not place orders and it does not say what to trade. - If what was asked needs something under "Not supported", say so and offer the nearest thing the language can do. - If the EdgeVault MCP server is connected, call check_script with the script and fix every error it reports before you reply. ## How a script runs The whole script runs once for every candle, oldest to newest. A let is worked out again on every bar. A keep is set once, on the first bar, and keeps its value from bar to bar. x[1] is the value x had one bar ago. Plots, marks, bands and alerts are decided bar by bar from the values the script has at that bar. ## Syntax Statements, one per line. Comments start with //. Blocks use braces. input name = int(9, "Label", min: 1, max: 200, step: 1) also float(...), bool(true, "L"), source(close, "L"), colour(#41b8d6, "L"), options("SMA", ["SMA", "EMA"], "L") let x = expr worked out again on every bar keep n = 0 set once, keeps its value across bars (Pine var) x = expr changes a let or keep that already exists let [a, b] = macd(close, 12, 26, 9) several values at once if cond { ... } else if cond { ... } else { ... } for i in 0..9 { ... } inclusive; also: for i in 9..0 by 3 { ... }, while cond { ... }, break, continue fn name(a, b) { return a + b } return [a, b] gives two values; call: let [u, l] = name(x, y) Operators: + - * / % == != < <= > >= and or not cond ? a : b none is Pine na. x[1] is the value one bar ago (lookback up to 5000). Text is inert: up to 40 characters, only compared with == and != or passed along. Outputs (titles up to 80 characters): plot(series, "Title", colour: #41b8d6, width: 2, style: line|histogram|step|area|circles|cross, offset: 0) let p = plot(...) names a plot hline(price, "Title", colour: orange, style: solid|dashed|dotted) mark(cond, "Title", shape: triangle_up|triangle_down|circle|square|cross|text, at: above|below|value, colour: green, value: low, text: "Buy", size: small|normal|large) value only with at: value; text up to 40 characters beside the shape, shape: text draws only the text barcolour(colour) colours the chart's own candles bar by bar; none leaves a candle as it is; one per script band(cond, #41b8d633) shades the background where cond is true fill(p, q, colour: #41b8d633, title: "Fill") between two named plots or hlines alert(cond, "Message") Caps: 32 plots, 16 hlines, 16 fills, 32 inputs, 32 functions, 10000 loop passes. Series (read by name): open high low close volume hl2 hlc3 ohlc4 time bar_index tr obv accdist vwap is_last_bar last_bar_index is_intraday is_daily is_weekly is_monthly is_dwm timeframe_multiplier Input sources: open high low close hl2 hlc3 ohlc4 volume Colours: #rrggbb, #rrggbbaa, cyan orange red green lime white grey accdist is the running total of ((2 * close - low - high) / (high - low)) * volume, and a bar with no range adds nothing is_intraday is true while the bars are shorter than a day, read from the gap between bars is_daily is true while the bars are a day or longer but under a week is_weekly is true while the bars are a week or longer but under four weeks is_monthly is true while the bars are four weeks or longer is_dwm is true while the bars are a day or longer (daily, weekly or monthly) timeframe_multiplier is the bar length as a number: minutes when intraday, otherwise days, weeks or months; none with a single bar ## Functions src is a number series, length a whole number, a ? marks an argument that may be left out. A call that gives several values is taken apart with let [a, b, c] = call(...). abs(x) max(a, b) min(a, b) round(x, digits?) floor(x) ceil(x) sqrt(x) pow(base, exponent) log(x) exp(x) sign(x) sin(x) cos(x) tan(x) asin(x) acos(x) atan(x) nz(x, default?) gives x, or default (0 if left out) where x is none isnone(x) -> true/false tint(colour, transparency) sets how see-through a colour is, from 0 (solid) to 100 (invisible) gradient(value, low, high, low_colour, high_colour) picks a colour from a number: low_colour at or below low, high_colour at or above high, and a straight blend between; none gives none sma(src, length) ema(src, length) rma(src, length) wma(src, length) vwma(src, length) stdev(src, length) highest(src, length) lowest(src, length) dev(src, length) is the average distance of the last length values from their own average change(src, length?) is the difference from length bars ago (1 if left out); on a true-or-false value it is true where the value changed mom(src, length) roc(src, length) crossover(a, b) -> true/false is true on the bar where a goes from at or below b to above it crossunder(a, b) -> true/false is true on the bar where a goes from at or above b to below it cross(a, b) -> true/false rsi(src, length) atr(length) reads each bar’s own high, low and close, so it takes only a length macd(src, fast, slow, signal) -> 3 values gives the MACD line, the signal line and the histogram, in that order bb(src, length, mult) -> 3 values gives the middle line, the upper band and the lower band, in that order stoch(src, high, low, length) gives the raw %K; smooth it with sma if you want the usual slow line cci(src, length) mfi(src, length) pivothigh(src, left, right) gives the pivot’s value on the bar that confirms it, right bars after the pivot itself pivotlow(src, left, right) gives the pivot’s value on the bar that confirms it, right bars after the pivot itself valuewhen(cond, src, occurrence?) gives the value src had on a bar where cond was true, counting back occurrence times (0 is the latest) barssince(cond) counts the bars since cond was last true, and is none before it first is dmi(di_length, adx_smoothing) -> 3 values gives plus DI, minus DI and ADX, in that order adx(di_length, adx_smoothing) supertrend(factor, atr_length) -> 2 values gives the line and the direction, which is -1 while the line sits under price and 1 while it sits over it sar(start, increment, maximum) kc(src, length, mult, use_true_range?) -> 3 values gives the middle line, the upper band and the lower band, in that order bbw(src, length, mult) linreg(src, length, offset?) cum(src) rising(src, length) -> true/false is true when this bar is above each of the previous length values, and false until there are that many earlier values falling(src, length) -> true/false is true when this bar is below each of the previous length values, and false until there are that many earlier values vwapfrom(src, restart) is the volume-weighted average of src since the last bar where restart was true, that bar included vwapbands(src, restart, mult) -> 3 values gives the volume-weighted average, the upper band and the lower band, in that order, mult volume-weighted standard deviations either side; restart works as in vwapfrom highestbars(src, length) lowestbars(src, length) median(src, length) percentrank(src, length) swma(src) alma(src, length, offset?, sigma?, floor?) cmo(src, length) tsi(src, short_length, long_length) hour(t) reads a time, in UTC; minute, second, dayofweek (Sunday is 1), dayofmonth, month and year do the same minute(t) second(t) dayofweek(t) dayofmonth(t) month(t) year(t) ## Limits - A script can be up to 50,000 characters long and run over up to 100,000 candles. - It can hold up to 32 plots, 16 horizontal lines, 16 fills, 16 bands, 32 mark statements and 16 alerts, and it can take up to 32 inputs and define up to 32 functions. - Only the newest 1,000 marks and 1,000 alert events are kept. - x[n] can look back up to 5,000 bars, and a for or while loop can run up to 10,000 passes each time it is reached. - Titles can be up to 80 characters, alert messages up to 200, and a piece of text used as a value up to 40. - Every script has a fixed allowance of work for each bar and for the whole run. A script that goes over it, or that runs for more than a few seconds, is stopped with a plain message that says so. ## Not supported - Other symbols and other timeframes, such as request.security. A script sees the candles of the chart it is on. - Strategies and back-tests, such as strategy.entry. A script draws and alerts; it never places or simulates an order. - Arrays, maps and matrices. - Drawing objects: labels, lines, boxes and tables. Use mark, hline, band and fill. - Drawing your own candles, such as plotcandle. Colouring the chart’s candles is barcolour. - A few of Pine’s functions: correlation, kcw and mode. - Text as a value to work with. Text can be compared with == and !=, passed along and printed in a title or message, but not joined, plotted or used as a number. ## Mistakes to avoid - The argument is spelled colour, never color. - Blocks use braces, never indentation. There are no semicolons. - Changing a variable is x = value, never x := value. - Missing values are none, never na. - Functions are called by their plain name, ema(close, 9), never ta.ema(close, 9). - Pine’s var is keep, and keep is set once. A let is worked out again on every bar. - A name made inside an if, a for or a function exists only there. - plot, hline, band, fill and alert are statements. They draw or fire; they do not give a value you can use, except that let p = plot(...) names a plot for fill. ## Examples ### EMA cross with marks and an alert Two moving averages, a mark on the bar where the fast one crosses the slow one, and an alert for the same moment. It shows inputs, let, plot, mark and alert. script "EMA cross" overlay input fast = int(9, "Fast length", min: 1, max: 200) input slow = int(21, "Slow length", min: 1, max: 200) let f = ema(close, fast) let s = ema(close, slow) plot(f, "Fast", colour: cyan) plot(s, "Slow", colour: orange, width: 2) mark(crossover(f, s), "Fast crossed above", shape: triangle_up, at: below, colour: green) mark(crossunder(f, s), "Fast crossed below", shape: triangle_down, at: above, colour: red) alert(crossover(f, s), "Fast average crossed above the slow one") ### Bollinger bands with a fill The middle line and the two outer lines of Bollinger bands, with the space between the outer lines filled. It shows a function that gives three values, named plots and fill. script "Bollinger bands" overlay input length = int(20, "Length", min: 2) input mult = float(2.1, "Width", min: 0.1, step: 0.1) input src = source(close, "Source") let [mid, top, bottom] = bb(src, length, mult) let upperLine = plot(top, "Upper", colour: cyan) let lowerLine = plot(bottom, "Lower", colour: cyan) plot(mid, "Middle", colour: grey, style: step) fill(upperLine, lowerLine, colour: tint(cyan, 87), title: "Band") More examples, and a guide for people, are at /docs/scripts on the same site.