Pine Script v5 vs v6: Migration Guide & Breaking Changes

jayadev rana Avatar

As of July 2026, migrating from Pine Script v5 to v6 comes down to a handful of breaking changes: booleans are now strictly true/false (no more na), integer division returns a float, and/or evaluate lazily, the strategy when= parameter is gone, the default strategy margin jumped from 0 to 100, and dynamic requests are on by default. TradingView’s Pine Editor auto-converts about 90% of scripts in one click (“Manage script” → “Convert code to v6”), but the last 10% need manual fixes. This guide compares Pine Script v5 vs v6 line by line and shows how to fix the migration errors I see most often.

In my 8 years writing Pine Script for traders in 14+ countries, the v6 change that generates the most panicked “why did my backtest change?” messages isn’t a compile error at all — it’s the new default margin. We’ll get to that. First, the fast answer.

Pine Script v5 vs v6: the short answer

Pine Script v6 launched in late 2024 and is now the version TradingView ships every new feature on. v5 scripts still compile and run, so there is no hard deadline — but if you want enums, dynamic requests without workarounds, faster execution, or any feature added since 2025, you have to be on v6. If you are checking which build is current, see my Pine Script latest version guide for 2026.

The migration itself is usually quick. The friction is behavioural: a few v5 patterns silently change meaning in v6 instead of throwing an error, and those are the ones that cost you hours if you do not know to look for them.

How to convert v5 to v6 with the built-in converter

TradingView highlights the //@version=5 annotation of any v5 script in yellow. To upgrade:

  1. Open the script in the Pine Editor.
  2. Click the “Manage script” (More) dropdown.
  3. Select “Convert code to v6”.

The converter rewrites the version annotation and most of the syntax automatically. In my experience it clears roughly nine out of ten client scripts cleanly. The rest fail to compile after conversion, and the errors are almost always boolean-na logic, a switch without a default branch, or a removed when= argument. Those you fix by hand using the sections below.

Pine Script v5 vs v6 breaking changes (comparison table)

Area Pine Script v5 Pine Script v6
Boolean values true, false or na; int/float auto-cast to bool Strictly true/false; must cast with bool()
na()/nz()/fixnan() on bool Accepted Rejected — no boolean na
Integer division (5 / 2) 2 (for constants) 2.5 (always float)
switch as an expression Default branch optional Default branch required
and / or evaluation Strict — both sides run Lazy / short-circuit
strategy when= Supported Removed — use if blocks
Default strategy margin margin_long / margin_short = 0 margin_long / margin_short = 100
Dynamic requests Opt-in via dynamic_requests=true On by default
9000-trade limit Raises an error Trims oldest orders

The breaking changes that actually bite, with fixes

1. Booleans are strictly true or false

This is the single biggest source of migration bugs. In v5 a bool had three possible states: true, false, or na. In v6 there is no third state, and two v5 habits break because of it.

First, implicit casting is gone. v5 quietly treated any nonzero number as true; v6 makes you cast:

//@version=5
indicator("Implicit cast")
// bar_index is an int; v5 casts it to bool automatically
color c = bar_index ? color.green : color.red
//@version=6
indicator("Explicit cast")
// Wrap the numeric value in bool()
color c = bool(bar_index) ? color.green : color.red

Second, a bool can no longer hold na. Because na(), nz() and fixnan() no longer accept bool arguments, any script that used a boolean to track three states needs a rethink. The classic case is position direction — switch it to an int:

//@version=5
strategy("Direction v5")
// na on flat bars, true on long, false on short
bool isLong = strategy.position_size > 0 ? true : strategy.position_size < 0 ? false : na
//@version=6
strategy("Direction v6")
// -1 short, 0 flat, +1 long
int dir = strategy.position_size > 0 ? 1 : strategy.position_size < 0 ? -1 : 0

Also watch the first bar: in v6, referencing a bool's history with [] on bar zero returns false, where v5 returned na.

2. Integer division now returns a float

In v5, dividing two constant integers performed integer division, so 5 / 2 returned 2. In v6 division is consistent and always keeps the remainder, so 5 / 2 returns 2.5. If your lookback or array indexing relied on truncation, wrap it in int():

//@version=6
int halfLen = int(length / 2)  // force integer division back

3. switch needs a default branch

In v5 a switch used as an expression could omit the default case. In v6 it must include one or it will not compile:

//@version=6
plotStyle = switch inputStyle
    "Line"    => plot.style_line
    "Circles" => plot.style_circles
    =>           plot.style_line   // required default branch

4. Lazy evaluation of and / or

v5 evaluated both sides of every and/or expression. v6 short-circuits: if the left side of an and is false, the right side never runs. That is faster and lets you guard array access safely:

//@version=6
// Safe in v6: the size check short-circuits before the index read
bool ok = array.size(myArray) > 0 and array.get(myArray, 0) > 0

Watch the flip side: if you relied on a calculation on the right of an and/or as a side effect, it may no longer fire.

Hitting compile errors the converter left behind? I debug and migrate v5→v6 scripts every week. Message me on WhatsApp at +91 77352 68199, or explore my Pine Script development service, and I'll get your strategy compiling cleanly on v6.

5. Strategy changes: when= removed, margin defaults to 100

The when= parameter is removed from every strategy.*() function. Move the condition into an if block:

// v5
strategy.entry("L", strategy.long, when = longCondition)

// v6
if longCondition
    strategy.entry("L", strategy.long)

Now the one that quietly wrecks backtests. In v5 the default margin_long and margin_short were 0, meaning the strategy never checked whether it had enough capital — it could open positions larger than the account. In v6 both default to 100, so oversized entries are rejected and losing shorts get margin-called. A v5 strategy that looked profitable on effectively unlimited funds can post very different numbers in v6. If you want the old behaviour for a like-for-like comparison, set it explicitly:

//@version=6
strategy("Match v5 margin", margin_long = 0, margin_short = 0)

Execution settings matter here too — if your results still differ, check whether calc_on_every_tick is behaving as you expect. Two more strategy tweaks: strategies now trim their oldest orders instead of erroring at the 9000-trade limit, and strategy.exit() no longer ignores your relative (percent/ticks) parameters when absolute price parameters are supplied in the same call.

6. Dynamic requests are on by default

In v5 you had to declare dynamic_requests = true to call request.*() functions with "series" arguments or from inside loops and conditionals. In v6 dynamic requests are always available — the compiler decides when they are needed and turns the feature off when they are not. If your v5 script set dynamic_requests = false and wrapped request.security() calls inside functions, remove that argument during migration or the v6 script will raise a compilation error. If you pull higher-timeframe data, it is worth re-reading how request context works — I cover the repaint-safe pattern in my guide to request.security and lookahead.

Common v5→v6 migration errors and fixes

Error or symptom Cause Fix
"Cannot call 'na' with an argument of type 'bool'" na()/nz()/fixnan() used on a bool Compare with == true/false, or switch to an int state variable
"Cannot use 'int'/'float' where 'bool' is expected" Implicit bool cast removed Wrap the value in bool()
"The switch statement must have a default branch" Missing default case Add a => defaultValue line
"Unknown argument 'when'" when= removed from strategy calls Move the condition into an if block
Backtest P&L changed after converting Default margin moved from 0 to 100 Set margin_long=0, margin_short=0 to match v5
First-bar values differ Boolean [] now returns false, not na Handle bar zero explicitly with bar_index == 0

Frequently asked questions

Is Pine Script v6 backward compatible with v5?

Not fully. v5 scripts keep running because TradingView still supports the older engine, but v5 code will not compile as v6 without changes. The breaking areas are booleans, integer division, switch defaults, lazy operators, dynamic requests, and several strategy behaviours.

How do I convert Pine Script v5 to v6?

Open the script in the Pine Editor, click the "Manage script" (More) dropdown, and choose "Convert code to v6". The converter handles roughly 90% of scripts automatically; fix any remaining compile errors using the sections above.

Do I have to migrate from v5 to v6?

No, existing v5 scripts still work. But every new Pine feature since 2025 is v6-only, so if you want the latest functions, better performance, or ongoing support, migrating is the practical choice.

Why did my backtest results change after converting to v6?

The most common reason is the default strategy margin changing from 0 to 100, which stops the engine from taking oversized positions. Integer division now returning a float and stricter boolean logic can also shift results. Set margin_long=0, margin_short=0 to reproduce the v5 numbers.

What is the biggest breaking change in Pine Script v6?

For indicators it is strict booleans (no na, no implicit casting). For strategies it is the new default margin of 100, because it changes backtests without any error message.

Want your v5 library migrated to v6 without the guesswork? Whether it is a single indicator or a full strategy suite, send me the script on WhatsApp at +91 77352 68199. You can also see the kind of work I do on my indicator development page, and I'll return a clean, tested v6 build.

Risk disclaimer: Trading and investing carry a substantial risk of loss and are not suitable for every investor. Nothing in this article is financial advice. The code examples are for educational purposes only; test every script on a demo account and backtest thoroughly before risking real capital. Past performance does not guarantee future results.

Leave a Reply

Your email address will not be published. Required fields are marked *