Pine Script v5 vs v6 Comparison

Fact checked by
Mike Christensen, CFOA
March 11, 2026
Compare Pine Script v5 and v6 side-by-side. Learn what changed, what broke, and whether you should upgrade your TradingView scripts.

Bottom Line

  • Pine Script v6 introduces enums, runtime logging, dynamic requests, polylines, and stricter type safety compared to v5
  • Key breaking changes include removal of implicit bool casting, no more na booleans, lazy evaluation for and/or operators, and removal of the when parameter from strategy functions
  • The Pine Editor converter handles many v5 to v6 changes automatically but some require manual fixes
  • v6 has received monthly feature updates throughout 2025-2026 including footprint requests, bid/ask data, and active inputs

If you write custom indicators or strategies on TradingView, you have likely encountered the question of Pine Script v5 vs v6. Released in late 2024, Pine Script v6 is the biggest language update since v4 to v5, introducing new features, stricter type rules, and several breaking changes that affect how existing scripts behave1. This guide walks through every major difference between the two versions so you can decide whether to upgrade and know exactly what to expect when you do.

Pine Script v6 is not a minor patch. It changes how booleans work, how operators evaluate, how data requests execute, and how strategies handle trades. Some of these changes will break your v5 code. Others unlock capabilities that were simply not possible before. Below, we compare every significant difference side by side.

Quick Comparison Table

Before diving into the details, here is a high-level feature comparison showing the pine script v5 vs v6 differences at a glance.

FeaturePine Script v5Pine Script v6
Bool can be naYes (three-state: true, false, na)No (strictly true or false)
Implicit int/float to boolYes (0 = false, nonzero = true)No (explicit bool() cast required)
and/or evaluationEager (both sides always evaluated)Lazy (short-circuit evaluation)
request.*() argumentsStatic only (simple string)Dynamic (series string)
Integer division (1/2)Returns 0 (integer division)Returns 0.5 (fractional result)
EnumsNot availableFull support with input.enum()
Runtime loggingNot availablelog.info(), log.warning(), log.error()
Polyline drawingNot availablepolyline.new() with curved/closed paths
strategy when parameterAvailableRemoved
Default strategy marginVaries by broker100% (long and short)
Trade limit (9000)Error thrown, script haltsOldest orders trimmed automatically
Negative array indexingNot supportedSupported in array.get(), array.set(), etc.
Text formattingPlain text onlyBold, italic via text_formatting parameter
timeframe.period format"D" (no multiplier)"1D" (always includes multiplier)
Max scopes550Unlimited (Feb 2025 update)
String max length4,096 characters40,960 characters (Aug 2025 update)
Bid/ask variablesNot availableAvailable on tick charts (Feb 2025)
Plot line stylesSolid onlySolid, dashed, dotted (Sep 2025)
Footprint dataNot availablerequest.footprint() (Jan 2026)

Type System Changes

The most impactful breaking changes in the pine script v5 vs v6 comparison involve the type system. Pine Script v6 enforces stricter rules around how types convert and interact, which catches subtle bugs but also breaks scripts that relied on v5's lenient behavior2.

No More Implicit Bool Casting

In v5, any integer or float value could be used directly in a conditional expression. Zero and na evaluated to false, and any nonzero value evaluated to true2. This was convenient but error-prone.

In v6, you must explicitly cast numeric values to bool using the bool() function3.

v5 (implicit cast works):

//@version=5
indicator("Implicit cast demo")
color bg = bar_index ? color.green : color.red
bgcolor(bg)

v6 (explicit cast required):

//@version=6
indicator("Explicit cast demo")
color bg = bool(bar_index) ? color.green : color.red
bgcolor(bg)

Without the bool() wrapper in v6, the script throws a compilation error2. This change forces you to be explicit about when a number should be treated as a boolean, reducing a class of bugs where na values or unexpected zeros silently produced wrong results.

Booleans Cannot Be na

This is one of the most significant changes in the pine script v5 vs v6 migration. In v5, a bool variable had three possible states: true, false, or na2. The na state created subtle behavior differences because na was not equal to false when compared with ==, yet it evaluated as false in conditional expressions.

In v6, bool is strictly two-state. It is always true or false, never na. This means:

  • You cannot assign na to a bool variable
  • The na(), nz(), and fixnan() functions no longer accept bool arguments3
  • An unresolved if/switch condition returns false instead of na
  • Using the history-referencing operator [] on the first bar returns false (not na) for bool values2

v5 (three-state boolean):

//@version=5
strategy("Bool na demo v5", overlay=true)
bool isLong = if strategy.position_size > 0
    true
else if strategy.position_size < 0
    false
// When position_size == 0, isLong is na

// This works in v5
if na(isLong)
    label.new(bar_index, high, "No position")

v6 (two-state boolean):

//@version=6
strategy("Bool na demo v6", overlay=true)
// Use an int or string to represent three states instead
int positionState = strategy.position_size > 0 ? 1 : strategy.position_size < 0 ? -1 : 0

if positionState == 0
    label.new(bar_index, high, "No position")

If your v5 scripts rely on the three-state boolean pattern, you need to refactor them to use a different type (such as int or an enum) to represent the third state.

Operator Changes

Lazy Evaluation for and/or

In v5, the and and or operators always evaluate both sides of the expression, regardless of the first operand's value. This is called eager evaluation2.

In v6, these operators use lazy (short-circuit) evaluation. If the first operand of or is true, the second operand is not evaluated. If the first operand of and is false, the second operand is skipped2.

v5 (both sides always evaluated):

//@version=5
indicator("Eager eval demo")
// Both array.get() calls execute even if the first condition is true
bool result = array.size(myArray) > 0 or array.get(myArray, 0) > 100

v6 (short-circuit evaluation):

//@version=6
indicator("Lazy eval demo")
// If array.size(myArray) > 0 is true, array.get() is NOT called
// This can change behavior if the second operand had side effects
bool result = array.size(myArray) > 0 or array.get(myArray, 0) > 100

This change matters most when the second operand has side effects, such as modifying a variable or calling a function that updates state. In v5, those side effects always occurred. In v6, they may be skipped. Most of the time, lazy evaluation is what you want because it is more efficient, but review your code if you depend on both sides always executing.

Integer Division Returns Fractional Values

In v5, dividing two const int values performs integer division. The expression 1 / 2 returns 0 because both operands are integers and the result is truncated2.

In v6, the same expression returns 0.5. The compiler now allows fractional results from integer division of const values2.

v5:

//@version=5
indicator("Int division v5")
plot(1 / 2) // Plots 0

v6:

//@version=6
indicator("Int division v6")
plot(1 / 2) // Plots 0.5

If you relied on the truncating behavior of integer division, you need to explicitly use int() or math.floor() to get the same result in v6.

Dynamic Requests

Dynamic requests are arguably the most powerful new capability in v6 and a major reason to upgrade. This is one of the clearest advantages in the pine script v5 vs v6 comparison.

v5: Static Requests Only

In v5, all request.*() functions require "simple string" arguments for the ticker and timeframe parameters. This means the symbol and timeframe must be known on the very first bar and cannot change2. Requests must also execute globally and cannot be placed inside loops or conditional blocks unless you enable dynamic_requests = true in the declaration statement.

//@version=5
indicator("Static requests v5")
// Each symbol needs its own request.security() call
float aapl = request.security("NASDAQ:AAPL", "1D", close)
float msft = request.security("NASDAQ:MSFT", "1D", close)
float googl = request.security("NASDAQ:GOOGL", "1D", close)
plot((aapl + msft + googl) / 3)

v6: Dynamic Requests by Default

In v6, request.*() functions accept "series string" arguments by default. You can pass variables, use them inside loops, place them in conditional blocks, and even export library functions containing request calls2. The compiler automatically optimizes performance when dynamic requests are not needed.

//@version=6
indicator("Dynamic requests v6")
var array<string> symbols = array.from("NASDAQ:AAPL", "NASDAQ:MSFT", "NASDAQ:GOOGL")
array<float> closes = array.new<float>()

for [i, sym] in symbols
    float reqClose = request.security(sym, "1D", close)
    closes.push(reqClose)

plot(closes.avg())

This is a fundamental shift. In v5, building a multi-symbol scanner or dynamic portfolio tool required workarounds like hard-coding every ticker. In v6, you can loop through an array of symbols and request data for each one dynamically. This opens the door to custom indices, portfolio rotation strategies, and correlation matrices that were previously impractical.

If you find that a converted v6 script behaves differently with dynamic requests enabled, you can add dynamic_requests = false to your declaration statement to replicate the v5 behavior.

New Features in v6

Beyond the breaking changes, Pine Script v6 introduces several entirely new capabilities that have no equivalent in v5.

Enums (Enumerated Types)

Enums let you define a custom type with a fixed set of named values3. They provide type safety and make your code more readable by replacing magic numbers and strings with meaningful names.

//@version=6
indicator("Enum demo")

enum Signal
    buy     = "Buy Signal"
    sell    = "Sell Signal"
    neutral = "Neutral"

Signal currentSignal = close > ta.sma(close, 20) ? Signal.buy : close < ta.sma(close, 20) ? Signal.sell : Signal.neutral

color plotColor = switch currentSignal
    Signal.buy     => color.green
    Signal.sell    => color.red
    Signal.neutral => color.gray

bgcolor(plotColor, title="Signal Background")

Enums work with the new input.enum() function, which creates a dropdown menu in the script's settings panel3. They can be stored in arrays, matrices, and maps, and used as map keys for strict key control. Each enum is a unique type, so members of different enums cannot be compared or interchanged, preventing accidental misuse4.

Runtime Logging

Pine Script v6 adds log.info(), log.warning(), and log.error() functions that output messages to the "Pine Logs" menu in TradingView3. This is a game-changer for debugging.

//@version=6
indicator("Logging demo")
float rsi = ta.rsi(close, 14)

if ta.crossover(rsi, 70)
    log.warning("RSI crossed above 70: {0}", rsi)

if ta.crossunder(rsi, 30)
    log.info("RSI crossed below 30: {0}", rsi)

In v5, debugging meant plotting values on the chart or creating label objects, both of which cluttered the display and had limited usefulness. Runtime logging gives you a dedicated output channel with severity levels, formatted string support, and the ability to inspect values at specific bars without modifying your chart.

Polyline Drawing

The polyline.new() function creates multi-point drawings that connect a series of chart.point objects. Polylines can be straight or curved, open or closed, and filled with color3.

//@version=6
indicator("Polyline demo", overlay=true)
if barstate.islast
    var points = array.new<chart.point>()
    points.clear()
    for i = 0 to 9
        points.push(chart.point.from_index(bar_index - 9 + i, low[9 - i]))
    polyline.new(points, curved=true, line_color=color.blue, line_width=2)

This enables complex visualizations like support/resistance zones, custom channel drawings, and multi-segment patterns that previously required multiple line.new() calls and careful coordinate management.

Text Formatting

Labels, boxes, and table cells in v6 support a text_formatting parameter with options for bold and italic text3. Text sizes can also be defined using integer values for more granular control.

//@version=6
indicator("Text format demo", overlay=true)
if barstate.islast
    label.new(bar_index, high, "Strong Signal",
      text_formatting=text.format_bold, size=size.large)

Combined with integer-based text sizing, this gives you precise control over how text appears on charts, making published indicators and strategies look more professional.

Strategy Differences

If you use Pine Script for backtesting strategies, several v6 changes directly affect how strategies behave and report results.

The when Parameter Is Removed

In v5, strategy functions like strategy.entry(), strategy.exit(), and strategy.close() accept a when parameter that conditionally executes the function. In v6, this parameter is removed entirely2.

v5 (using when):

//@version=5
strategy("When param v5", overlay=true)
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
strategy.entry("Long", strategy.long, when=longCondition)

v6 (using if instead):

//@version=6
strategy("When param v6", overlay=true)
longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
if longCondition
    strategy.entry("Long", strategy.long)

The Pine Editor converter handles this change automatically by wrapping strategy calls in if blocks. The logic is identical, but the code is more explicit about when trades execute.

Default Margin Is Now 100%

In v5, the default margin for strategy.entry() varies depending on the broker simulation settings. In v6, both margin_long and margin_short default to 100%, meaning strategies use no leverage unless you explicitly set it2.

If your v5 strategy relied on the default margin being less than 100% for leveraged positions, you need to explicitly set the margin parameters in your v6 strategy() declaration to match the previous behavior.

Trade Limit Trimming

In v5, strategies that exceed the 9,000 trade limit throw a runtime error, halting the script. In v6, the strategy automatically trims the oldest orders to make room for new ones2. The new strategy.closedtrades.first_index variable lets you retrieve the index of the earliest non-trimmed order3.

This is a significant improvement for high-frequency strategies or long backtesting periods. Your strategy no longer crashes when it generates many trades. It simply discards the oldest records to continue running.

strategy.exit() Parameter Handling

In v5, the strategy.exit() function ignores relative take-profit and stop-loss parameters (profit, loss, trail_points, trail_offset) when the corresponding absolute parameters (limit, stop, trail_price) are also provided. In v6, both relative and absolute parameters are respected simultaneously, and the closest price level to the current price takes effect2.

Review any strategy.exit() calls that include both absolute and relative parameters. The behavior may differ between v5 and v6.

Additional Breaking Changes

Beyond the major categories above, several smaller changes in the pine script v5 vs v6 transition can affect your code.

History Referencing Restrictions

The history-referencing operator [] can no longer reference the history of literal values or fields of user-defined types directly. In v5, expressions like true[1] were allowed. In v6, you must store the value in a variable first, then reference that variable's history2.

timeframe.period Format

The value of timeframe.period now always includes a multiplier. Where v5 returned "D" for daily, v6 returns "1D". Similarly, "W" becomes "1W" and "M" becomes "1M"2. If your script compares timeframe.period against hard-coded strings like "D", you need to update those comparisons.

plot() Offset Parameter

The offset parameter of plot() and related functions no longer accepts "series" values. It requires a "simple int" value that is known at the first bar2. If your v5 script used a dynamic offset, you need to refactor the logic.

transp Parameter Removed

The transp parameter, already deprecated in v5, is fully removed in v62. Use color.new() to set transparency instead.

For Loop Boundary Evaluation

In v6, for loops re-evaluate their end boundary before every iteration. In v5, the end boundary was evaluated once2. If you modify a variable used as the loop's end boundary inside the loop body, the behavior changes in v6.

Post-Launch Feature Updates (2025-2026)

Since the initial v6 release, TradingView has shipped monthly updates that further widen the gap between v5 and v6. These features are only available in v6 scripts.

  • February 2025: Scope limit removed (previously 550 max), bid/ask variables added for tick charts1
  • March 2025: Active inputs that dynamically show/hide based on other input values1
  • June 2025: Enhanced map and matrix operations with stricter type checking1
  • August 2025: String max length increased from 4,096 to 40,960 characters1
  • September 2025: New plot line styles (dashed, dotted) via plot.style_line_dashed and plot.style_line_dotted1
  • January 2026: request.footprint() function for volume footprint and order flow data1

These ongoing improvements mean the feature gap between v5 and v6 grows every month. New capabilities are being built exclusively for v6, and v5 is effectively in maintenance mode.

Should You Upgrade?

The answer depends on your situation. Here is a practical framework for deciding.

Upgrade Now If You:

  • Are building new scripts from scratch (always start with v6)
  • Need dynamic requests for multi-symbol scanners or portfolio tools
  • Want enums for cleaner, more maintainable code
  • Need runtime logging for debugging complex strategies
  • Want access to post-launch features like footprint data or dashed plot lines

Proceed With Caution If You:

  • Have working v5 strategies running in live production with real capital
  • Rely on the three-state boolean pattern (true/false/na) in critical logic
  • Use side effects in the second operand of and/or expressions
  • Have strategy.exit() calls with both absolute and relative parameters

Migration Tips

  • Use the Pine Editor's built-in converter as a starting point (Manage Script > Convert code to v6)4
  • The converter handles many changes automatically, including wrapping strategy when parameters in if blocks
  • After conversion, test thoroughly by comparing v5 and v6 outputs side by side
  • If a converted script behaves differently, try adding dynamic_requests = false to isolate the issue2
  • Address compiler errors one at a time, starting with bool casting and na-related issues

Automating Pine Script Strategies

Whether you are running Pine Script v5 or v6 strategies, TradersPost connects your TradingView alerts to live broker accounts for automated trade execution5. Both versions generate the same webhook alert format, so your automation setup works identically regardless of which Pine Script version you use.

TradersPost supports automated execution through brokers including TradeStation, Alpaca, Interactive Brokers, Tradier, and many others5. When your Pine Script strategy fires an alert, TradersPost receives the webhook and places the corresponding order in your connected brokerage account within seconds.

If you are migrating a v5 strategy to v6, you do not need to change anything on the TradersPost side. The alert message format and webhook URL remain the same. Just update your script, verify the backtest results match expectations, and your automation continues seamlessly.

To get started with automating your Pine Script strategies, visit TradersPost and connect your TradingView account to your broker.

Conclusion

The pine script v5 vs v6 comparison reveals a clear trajectory: v6 is a stricter, more powerful, and more capable language. The breaking changes around booleans, operator evaluation, and integer division enforce better coding practices. The new features like dynamic requests, enums, runtime logging, and polylines unlock capabilities that were impossible or impractical in v5.

For new development, there is no reason to start with v5. For existing scripts, plan your migration carefully, use the built-in converter as a starting point, and test thoroughly. The ongoing monthly updates to v6 mean the feature gap will only continue to grow.

If you want to learn more about specific v6 features, check out our guides on Pine Script v6: What's New and Why It Matters, Adapting to Type System Changes in Pine Script v6, and Pine Script Strategy Automation.

References

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

Ready to automate your trading? Try a free 7-day account:
Try it for free ->