
Pine Script v6 is the latest major version of TradingView's scripting language, launched in November 20241. It introduced sweeping changes to the type system, dynamic data requests, new drawing types, and strategy improvements. Since launch, TradingView has shipped a new update nearly every month, adding features like footprint data, bid/ask variables, active inputs, and more1. This post is a complete chronological changelog covering every Pine Script v6 release note from the initial launch through January 2026.
The initial Pine Script v6 release was the largest update in years, bringing fundamental language changes alongside several new features1. All future Pine Script updates apply exclusively to v6, making migration from v5 essential for accessing new functionality2.
Pine Script v6 introduced enumerations, a new data type that lets programmers define a strict set of named values1. Enums provide type-safe control over which values variables, parameters, and collections can hold. They pair with the new input.enum() function to create clean dropdown menus in script settings3.
//@version=6
indicator("Enum demo")
enum SignalType
buy = "Buy Signal"
sell = "Sell Signal"
hold = "Hold"
SignalType sig = input.enum(SignalType.buy, "Signal Type")
plot(sig == SignalType.buy ? 1 : sig == SignalType.sell ? -1 : 0)
All request.*() functions now accept series string arguments for parameters that define the requested context1. A single request.*() call can change its data feed on any historical bar. Additionally, request.*() calls can now be placed inside loops, conditional structures, and exported library functions3.
//@version=6
indicator("Dynamic request demo", overlay = true)
// Symbol changes dynamically based on a condition
string sym = close > open ? "BINANCE:BTCUSD" : "BINANCE:ETHUSD"
float reqClose = request.security(sym, timeframe.period, close)
plot(reqClose, "Dynamic Close")
The new log.info(), log.warning(), and log.error() functions send formatted messages to the Pine Logs pane, giving developers a proper debugging tool1. Messages support format strings with placeholders, similar to str.format()3.
//@version=6
indicator("Logging demo")
if barstate.islast
log.info("Close: {0}, Volume: {1}", close, volume)
log.warning("Spread is wide: {0}", high - low)
plot(close)
Three significant changes affect how booleans work in v6:
true or false and can never be na. The na(), nz(), and fixnan() functions no longer accept bool arguments2.int and float types are no longer implicitly cast to bool. Code like if myFloat must now use explicit comparisons such as if myFloat != 02.and and or operators use short-circuit (lazy) evaluation. If the first operand of or is true, the second is never evaluated2.Division of two const int values can now return a fractional float result. In v5, 1 / 2 returned 0. In v6, 1 / 2 returns 0.52. Use int(1 / 2) to preserve the old truncation behavior.
Several strategy behaviors changed at launch:
when parameter was removed from all strategy.*() functions. Use if blocks instead2.strategy.closedtrades.first_index variable retrieves the index of the earliest non-trimmed order1.strategy.exit() no longer ignores relative parameters when absolute parameters are also specified. It now evaluates both and uses whichever level the market price would activate first3.The history-referencing operator [] can no longer reference the history of literal values or fields of user-defined types directly2. For example, close[1] still works, but myUDT.field[1] requires storing the field in a variable first.
The offset parameter of plot() and related functions no longer accepts series values. Only simple or const values are allowed, preventing the offset from changing on each bar2.
Labels, boxes, and table cells gained the text_formatting parameter, accepting text.format_bold, text.format_italic, or text.format_none3. Text sizes now also support integer values representing typographic points, giving finer control than the old size.* constants1.
array.get(), array.set(), array.insert(), and array.remove() now accept negative indices to reference elements from the end of an array3.syminfo.mincontract variable holds the smallest tradable unit for the current symbol3.syminfo.main_tickerid and timeframe.main_period, reference the main chart's ticker ID and timeframe regardless of the request context1.timeframe.period now always includes a multiplier (e.g., "1D" instead of "D")2.na values are no longer allowed in place of built-in constants of unique types2.The previous 550-scope limit was removed. Scripts can now contain an indefinite number of local scopes from user-defined functions, methods, loops, conditional structures, UDTs, and enums1. This unlocks significantly more complex script architectures without hitting compiler limits.
Two new built-in variables were introduced:
bid returns the highest price an active buyer is willing to pay for the instrument at its current value3.ask returns the lowest price an active seller will accept for the instrument3.These variables are only available on the "1T" (tick) timeframe. On all other timeframes, their values are na3.
The for loop structure received updated boundary-checking behavior. Previously, the loop counter's end boundary (to_num) was established before the first iteration and could not change during execution. Now, the for loop evaluates to_num dynamically before every iteration, allowing the loop to modify its own stopping condition as it runs1.
//@version=6
indicator("Dynamic for loop demo")
var int count = 0
int limit = 5
for i = 0 to limit
count += 1
if i == 3
limit := 10 // Extends the loop boundary mid-execution
plot(count)
A new setter function box.set_xloc() was added. Similar to the existing line.set_xloc() and label.set_xloc() functions, it sets the left and right coordinates of box borders and defines whether values represent bar indices or UNIX timestamps3.
The style parameter of ticker.renko(), ticker.pointfigure(), and ticker.kagi() now accepts a new argument: "PercentageLTP"1. When used, the returned ticker ID refers to a non-standard chart dataset with box sizes based on a user-defined percentage of the last trading price, providing more adaptive brick sizing for these chart types.
The time_close variable and the time_close() function received improved behavior on tick charts and price-based charts (Renko, line break, Kagi, point and figure, and range)1. Previously, it was impossible to retrieve the closing timestamp of elapsed realtime bars on these chart types because the timestamp was not saved after the closing tick.
With this update, the closing timestamp of a realtime bar on tick or price-based charts is available immediately after the bar closes. Scripts can now use time_close[1] or call time_close("", 1) with a positive bars_back argument to retrieve closing times of past realtime bars on any chart type.
Libraries can now export user-defined constant variables. Exported variables must be of the int, float, bool, color, or string type and must include the const keyword in their declaration1.
//@version=6
library("MyConstants")
export const float GOLDEN_RATIO = 1.618033988749895
export const float SILVER_RATIO = 1.0 + math.sqrt(2)
export const int MAX_LOOKBACK = 500
This allows library authors to share reusable constants that importing scripts can reference with full type safety.
All input.*() functions gained a new active parameter. When set to true, users can change the input's value in the Settings tab. When false, the input is grayed out and locked1. This lets programmers create dependent input relationships where toggling one input enables or disables others3.
//@version=6
indicator("Active input demo")
bool useSmoothing = input.bool(false, "Enable Smoothing")
int smoothLen = input.int(9, "Smoothing Length", active = useSmoothing)
float rsi = ta.rsi(close, 14)
float result = useSmoothing ? ta.ema(rsi, smoothLen) : rsi
plot(result)
The new syminfo.current_contract variable returns the ticker identifier of the underlying contract when the current symbol is a continuous futures contract. It returns na for all other symbol types3. This is useful for futures traders who need to reference the specific contract rather than the continuous symbol.
The maximum string length increased tenfold, from 4,096 characters to 40,960 encoded characters1. This benefits scripts that build large formatted text outputs for tables, tooltips, or log messages.
The Pine Editor began moving from the bottom panel to a side panel layout. The new vertical orientation overlays on the right side of the screen, with a split-view mode available for wider displays. This allows users to edit code while simultaneously viewing the Strategy Tester, Replay Trading, or other tabs. A word-wrap feature (toggled with Alt + Z or Option + Z) prevents horizontal scrolling on long lines.
The plot() function gained a new linestyle parameter that accepts plot.linestyle_solid, plot.linestyle_dashed, or plot.linestyle_dotted1. This gives indicator developers the ability to visually differentiate multiple plotted series using dashed or dotted lines without resorting to workarounds3.
//@version=6
indicator("Plot linestyle demo", overlay = true)
plot(ta.sma(close, 20), "SMA 20", color.blue, linestyle = plot.linestyle_solid)
plot(ta.sma(close, 50), "SMA 50", color.red, linestyle = plot.linestyle_dashed)
plot(ta.sma(close, 200), "SMA 200", color.gray, linestyle = plot.linestyle_dotted)
The time() and time_close() functions gained a new timeframe_bars_back parameter1. Unlike the existing bars_back parameter (which offsets on the script's main timeframe), timeframe_bars_back offsets on the separate timeframe specified by the timeframe argument3.
If positive, the function calculates the timestamp of the past bar that is N bars back on the specified timeframe. If negative, it calculates the expected timestamp N bars forward. When both bars_back and timeframe_bars_back are specified, the function first applies the chart-timeframe offset, then applies the target-timeframe offset to that result.
The new syminfo.isin variable holds the 12-character International Securities Identification Number (ISIN) for the current symbol, or an empty string if no ISIN is available3. ISINs uniquely identify securities globally and do not vary across exchanges, making this variable useful for identifying the same underlying instrument listed under different ticker symbols on different exchanges1.
//@version=6
indicator("ISIN demo")
string sym1 = input.symbol("NASDAQ:AAPL", "Symbol 1")
string sym2 = input.symbol("GETTEX:APC", "Symbol 2")
if barstate.islastconfirmedhistory
var string isin1 = request.security(sym1, "", syminfo.isin)
var string isin2 = request.security(sym2, "", syminfo.isin)
if isin1 == isin2
log.info("Both symbols refer to the same security: {0}", isin1)
else
log.info("Different securities: {0} vs {1}", isin1, isin2)
Pine Script updated its line-wrapping rules for code enclosed in parentheses. Previously, all continuation lines required indentation that was not a multiple of four spaces, since four-space indentation was reserved for local code blocks. Now, wrapped lines enclosed in parentheses can be indented by zero or more spaces, including multiples of four1.
//@version=6
indicator(
"Flexible wrapping demo",
overlay = true
)
float median = 0.5 * (
ta.highest(20) + ta.lowest(20)
)
plot(median)
Lines not enclosed in parentheses still require non-multiple-of-four indentation for continuation.
The largest update since launch added volume footprint data access through the new request.footprint() function and two new data types: footprint and volume_row1.
request.footprint() retrieves volume footprint information for the current bar, returning a footprint object ID or na if no data is available.footprint type provides functions like footprint.buy_volume(), footprint.sell_volume(), footprint.delta(), footprint.poc(), footprint.vah(), and footprint.val() for retrieving overall and row-level data.volume_row type provides functions like volume_row.up_price(), volume_row.down_price(), and volume/delta data for individual price rows within the footprint.Footprint requests require a Premium or Ultimate TradingView plan4.
//@version=6
indicator("Footprint demo", overlay = true)
int ticks = input.int(100, "Ticks per row", minval = 1)
int vaPct = input.int(70, "Value Area %", minval = 1)
footprint fp = request.footprint(ticks, vaPct)
if not na(fp)
float buyVol = fp.buy_volume()
float sellVol = fp.sell_volume()
float delta = fp.delta()
volume_row pocRow = fp.poc()
float pocHigh = pocRow.up_price()
float pocLow = pocRow.down_price()
log.info("Delta: {0}, POC: {1}-{2}", delta, pocLow, pocHigh)
The Pine Editor includes a built-in converter that handles many v5-to-v6 migrations automatically2. However, some changes require manual attention. Here is a summary of the breaking changes to watch for:
if myInt) with explicit comparisons (if myInt != 0)2.na(), nz(), or fixnan() with boolean arguments2.when parameters in strategy functions with if blocks2.int() to truncate)2.[] history references off UDT fields and onto intermediate variables2.series values in plot offsets with simple or const values2.na in place of built-in constants2.For scripts on v4 or earlier, migrate one version at a time using the corresponding migration guides before converting to v6.
Pine Script v6 makes it easier than ever to build sophisticated indicators and strategies on TradingView, but a strategy only delivers value when it executes real trades. TradersPost connects your TradingView alerts directly to your broker, automating order execution for stocks, options, futures, and crypto5. Whether you are using the new footprint data for volume analysis, dynamic requests for multi-symbol scanning, or enum-based signal logic, TradersPost turns your Pine Script alerts into live or paper trades with no coding beyond TradingView required.
Visit traderspost.io to connect your TradingView strategies to supported brokers and start automating your trades today.
1 Pine Script Release Notes
2 Pine Script v5 to v6 Migration Guide
3 Pine Script v6 Language Reference
4 Pine Script User Manual
5 TradersPost - Automated Trading Platform