Today, Pine graduates to v5! The new version of our indicator and strategy programming language brings a host of exciting new features and improvements. Pine is now more powerful than ever, and changes in v5 will help us take the language to new levels. This post introduces just a few of the latest features available; be sure to read our Release Notes and Migration Guide.
v4 to v5 Converter
Existing Pine scripts using previous versions of Pine will continue to run unchanged, but we have provided a conversion tool in the Pine Editor to help coders convert their v4 scripts to v5. Future improvements to Pine will be rolled out for v5 exclusively, so we recommend converting your indicators and strategies if you wish to benefit from the new features. The v4 to v5 conversion tool is available when a v4 script is loaded in the Editor, from the More dropdown menu:
Note that not all v4 code can be converted automatically. If you encounter conversion issues or prefer converting your scripts manually, our Migration Guide documenting all the changes between v4 and v5 will guide you.
A key addition to Pine that comes with v5 is libraries. Libraries are a new type of publication that allows you to create custom functions to be reused in other scripts. Once a library is published, other scripts (be it indicators, strategies, or even other libraries) can import it and use its functions. You can use libraries to include complex algorithms or frequently-used functions so that you, or the whole Pine community, can easily reuse them.
To start working with libraries, see our User Manual page on libraries. At the end of this post, you will find library examples published by members of our PineCoders team. You can see published libraries from the script feed here.
Default values for user-defined functions
An improvement that goes hand-in-hand with libraries: a default value can be defined for parameters in user-defined functions, which effectively makes them optional. In the example below, we declare a custom function customPow() that raises base to the power of exp. If exp is not specified when the function is called, 2 is used:
//@version=5 indicator("") customPow(base, exp = 2) => result = 1 for i = 1 to exp result *= base plot(customPow(11)) // 11^2 plot(customPow(11, 4)) // 11^4
The new switch statement is a twist on the familiar if statement. If you’ve ever had to create a big tree of if-else statements, you’ll appreciate how much more convenient it is to achieve the desired result with switch. You can learn more about it in our Reference Manual. See it in action in the code below. It is our built-in Average True Range indicator, which now uses a switch statement to provide different smoothing algorithms in its calculations:
//@version=5 indicator(title="Average True Range", shorttitle="ATR", timeframe="") lengthInput = input.int(title="Length", defval=14, minval=1) smoothingInput = input.string(title="Smoothing", defval="RMA", options = ["RMA", "SMA", "EMA", "WMA"]) maFunction(source, length) => switch smoothingInput "RMA" => ta.rma(source, length) "SMA" => ta.sma(source, length) "EMA" => ta.ema(source, length) => ta.wma(source, length) plot(maFunction(ta.tr(true), lengthInput), title = "ATR", color=#B71C1C)
A big quality-of-life improvement for working with Pine drawings: the new line.all, label.all, box.all, and table.all built-in array variables always contain the IDs of all the drawings of the specified type drawn by your script.
You can use it, for example, to trim the number of the drawings displayed on the chart based on a user-defined value. In the script below, we draw a line on each new daily open (up to a limit of ~50, based on the default line limit of the script). We then check if the number of lines allowed though the script’s inputs was exceeded, and delete the oldest line if so:
//@version=5 indicator("Daily Open", overlay = true) qtyOfLinesInput = input.int(10, "Draw only last n lines", minval = 0, maxval = 50) if ta.change(time("1D")) line.new(bar_index, open, bar_index + 1, open, extend = extend.right) if array.size(line.all) > qtyOfLinesInput line.delete(array.get(line.all, 0))
Another long-awaited Pine feature that comes with v5 is while loops. The while statement creates a loop that will stop when the condition is false or a break command is used in the loop.
As an example, here’s an indicator that calculates the difference between the average distance we need to look back to find the up and down volume equal to the total volume of the last n bars. The further we need to look back to find the up or down volume, the more bearish or bullish its value is:
//@version=5 var int MAX_BARS_BACK = 500 indicator("Volume bias", max_bars_back = MAX_BARS_BACK) int lookBackInput = input.int(20, "Volume Look Back (bars)", minval = 2, maxval = int(MAX_BARS_BACK / 4)) // Stop the script if the chart does not contain volume data. bool noVol = na(volume) and nz(math.sum(nz(volume), 200) == 0, true) if noVol runtime.error("No volume data.") volumeBias(lookBack, maxLookBack) => bool barUp = ta.rising(close, 1) bool barDn = ta.falling(close, 1) float upVolume = 0. float dnVolume = 0. float avgVolume = math.sum(nz(volume), lookBack) int upBarNos = array.new_int(0) int dnBarNos = array.new_int(0) int bar = 1 bool volumeFound = false while (not volumeFound) and bar < maxLookBack if barUp[bar] and upVolume < avgVolume upVolume += nz(volume[bar]) array.push(upBarNos, bar) else if barDn[bar] and dnVolume < avgVolume dnVolume += nz(volume[bar]) array.push(dnBarNos, bar) bar += 1 volumeFound := upVolume >= avgVolume and dnVolume >= avgVolume float volumeBias = bar >= maxLookBack ? na : array.avg(dnBarNos) - array.avg(upBarNos) float bias = volumeBias(lookBackInput, MAX_BARS_BACK) plot(bias, "Volume Bias", bias > 0 ? color.lime : color.fuchsia) hline(0)
The script’s while loop executes until the required volume is found in both the up and down volume, and we have not looked back past the maximum number of bars allowed. The script also showcases another feature added to Pine v5: runtime.error().
The runtime.error() function now makes it possible to halt the execution of a script and display an error message on any condition you can define in Pine. This will come in handy for script creators who want to prevent users from using their indicators incorrectly. It can also be used as an unorthodox debugging tool, to halt execution during a loop or from within a function, for example.
To use the new function, simply call the runtime.error() function when your conditions are met. When it executes, it will halt the script and display the familiar exclamation mark next to the indicator’s name. When users click on the exclamation mark icon, the message you used in the function call will appear.
The code below is a barebones VWAP indicator with two custom errors. The first one appears when the symbol does not have any volume data: VWAP is calculated based on volume, so if there is no volume, the script can’t work. The second one appears when the timeframe on the chart is 1D or higher. Basic VWAP calculations accumulate volume-weighted moving average data on each new bar and reset at the start of a new day, so the indicator is only useful on intraday timeframes.
//@version=5 indicator("VWAP with custom errors") if na(volume) // Will be true on symbols with no volume data e.g. TVC:SPX runtime.error("There is no volume data for this symbol.") else if timeframe.isdwm // Will be true on 1D and higher timeframes runtime.error("Session-based VWAP does not show meaningful data on timeframes >= 1D. Please switch to a lower timeframe.") plot(ta.vwap)
New strategy parameters
Good news for strategy coders! We have added a whole bunch of new variables and functions that give you visibility on trade properties, statistics, and metrics. Their values update as the broker emulator executes your orders, so you can follow values as your strategy progresses.
Click here to see the Pine Reference Manual for details on each one
Our community of Pine coders tells us they appreciate the unprecedented rate of additions we have made to Pine in the last few years, and we intend to sustain the same pace in the future. This, however, creates a constant stream of new Pine functions and built-in variables. To support this crazy growth, we needed to better organize the ~600 current names used in the language. We did this by adding new namespaces in order to group functions in ways that better reflect their use. Many function parameter names were also renamed to make them easier to understand.
An example of a new namespace is ta., which now includes all variables and functions related to technical analysis. This makes it easier for you to browse the Reference Manual and find all the variables and functions returning the values of common indicators. Accordingly, sma() is now ta.sma(). Remembering the new namespaces is not necessary; if you type the older name of a function without its namespace in the Editor and press the Autocomplete hotkey (Ctrl + Space, or Cmd + Space on MacOS), a popup showing matching suggestions appears:
The same goes when searching the Reference Manual; typing a familiar function name without its namespace will bring up its new name. You can see the complete list of changes to v5 in our Migration Guide.
The following publications are examples of libraries published on TradingView by the PineCoders who help us test new Pine features:
We hope you find the new features useful. And please do keep giving us feedback and suggestions — we’re building TradingView for you, and we’re always keen to know what you think about our platform updates.