Pine Script v6 Strategy Changes

Fact checked by
Mike Christensen, CFOA
March 11, 2026
Every Pine Script v6 strategy change explained: when parameter removal, 100% default margin, trade limit trimming, and strategy.exit() fixes.

Bottom Line

  • The when parameter is removed from all strategy functions in v6 and must be replaced with if blocks
  • Default margin for long and short positions changed to 100% which affects leverage-based backtesting results
  • Strategies now trim the oldest trades instead of throwing an error when exceeding the 9000 trade limit
  • strategy.exit() now honors both relative and absolute parameters simultaneously instead of ignoring relative ones

Pine Script v6 introduces four major changes to how strategies work1. If you backtest trading systems on TradingView, every one of these changes affects your results. Some strategies will produce different trade counts, different profit numbers, and different equity curves after migrating to v6, even if you do not change a single line of trading logic.

This guide walks through each strategy change in detail, with before-and-after code examples and a migration checklist so you can update your scripts with confidence.

The when Parameter Is Removed

This is the change that will break the most existing scripts. In Pine Script v5, the strategy.entry(), strategy.exit(), strategy.close(), and strategy.order() functions all accepted an optional when parameter2. This parameter controlled whether the function call would execute on a given bar.

What when Did in v5

The when parameter was a boolean condition passed directly to the strategy function. When it evaluated to true, the order was placed. When it was false, the function call was skipped entirely. Many published scripts used this pattern because it kept the code compact.

Here is a typical v5 strategy that uses when for both entry and exit:

//@version=5
strategy("v5 When Example", overlay = true)

longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))

strategy.entry("My Long Entry Id", strategy.long, when = longCondition)
strategy.entry("My Short Entry Id", strategy.short, when = shortCondition)

This code compiles and runs correctly in v5. In v6, it throws a compilation error because the when parameter no longer exists2.

How to Replace when with if Blocks

The fix is straightforward. Wrap each strategy call in an if block that uses the same condition you previously passed to when2. The Pine Editor converter handles this change automatically in most cases, but you should understand the pattern for manual migration and code review.

Here is the same strategy rewritten for v6:

//@version=6
strategy("v6 If Block Example", overlay = true)

longCondition = ta.crossover(ta.sma(close, 14), ta.sma(close, 28))
shortCondition = ta.crossunder(ta.sma(close, 14), ta.sma(close, 28))

if longCondition
    strategy.entry("My Long Entry Id", strategy.long)

if shortCondition
    strategy.entry("My Short Entry Id", strategy.short)

The behavior is identical. The if block prevents the strategy.entry() call from executing when the condition is false, just as the when parameter did in v5.

Common Patterns to Update

The when parameter was used across all strategy order functions. Here are the most common patterns and their v6 equivalents.

strategy.entry() with when:

// v5
strategy.entry("Buy", strategy.long, when = buySignal)

// v6
if buySignal
    strategy.entry("Buy", strategy.long)

strategy.close() with when:

// v5
strategy.close("Buy", when = sellSignal)

// v6
if sellSignal
    strategy.close("Buy")

strategy.exit() with when:

// v5
strategy.exit("Exit", "Buy", profit = 100, loss = 50, when = inTrade)

// v6
if inTrade
    strategy.exit("Exit", "Buy", profit = 100, loss = 50)

strategy.order() with when:

// v5
strategy.order("Scale In", strategy.long, qty = 5, when = scaleCondition)

// v6
if scaleCondition
    strategy.order("Scale In", strategy.long, qty = 5)

While the if block approach requires slightly more lines of code, it makes the control flow explicit and easier to read. You can see at a glance which conditions gate which orders.

Default Margin Changed to 100%

In Pine Script v5, the default values for the margin_long and margin_short parameters in the strategy() declaration were not explicitly set to 100%2. This meant that strategies could behave as if they had access to leverage by default, depending on the instrument and TradingView's internal defaults.

In v6, both margin_long and margin_short default to 100, meaning the strategy assumes no leverage2. Every dollar of position requires a full dollar of capital backing it.

Impact on Backtesting Results

This change can dramatically alter your strategy results if you were relying on the previous default margin behavior. A strategy that appeared to generate large returns may have been using implicit leverage. After migrating to v6 without explicitly setting margin values, the same strategy will trade with smaller positions relative to capital, producing lower absolute returns and different trade sizing.

Consider a strategy with $10,000 initial capital trading a stock at $100. With 100% margin, the strategy can buy 100 shares maximum. With 50% margin (2x leverage), it could buy 200 shares. If your v5 strategy was unknowingly using leveraged margin defaults, your v6 results will look very different.

How to Set Explicit Margin Values

If your strategy is designed to use leverage, set the margin values explicitly in your strategy() declaration. This makes your intent clear and ensures consistent behavior across Pine Script versions.

//@version=6
// No leverage (v6 default)
strategy("No Leverage Strategy", overlay = true, margin_long = 100, margin_short = 100)

// 2x leverage
strategy("2x Leverage Strategy", overlay = true, margin_long = 50, margin_short = 50)

// 4x leverage
strategy("4x Leverage Strategy", overlay = true, margin_long = 25, margin_short = 25)

The margin value represents the percentage of the position value that must be covered by capital3. A margin_long of 50 means you need 50% of the position value in capital, which effectively gives you 2x leverage. A margin_long of 25 gives 4x leverage.

Best practice: Always set margin_long and margin_short explicitly in every strategy, even if you want the 100% default. This documents your intent and protects your script from future default changes.

Trade Limit Trimming

Pine Script strategies have a maximum limit of 9,000 total orders in their results3. What happens when a strategy exceeds this limit changed significantly between v5 and v6.

v5: Runtime Error

In v5, when a strategy generated more than 9,000 orders, TradingView threw a runtime error and the strategy stopped executing2. This was a hard failure that prevented you from seeing any results at all for high-frequency strategies or strategies backtested over very long date ranges.

//@version=5
strategy("v5 Order Limit Problem", overlay = true)
// This strategy places orders every other bar, which on
// long timeframes can exceed the 9000 order limit.
if bar_index % 2 == 0
    for i = 1 to 5
        strategy.entry("Entry " + str.tostring(i), strategy.long, qty = 5)
else
    strategy.entry("Short", strategy.short, qty = 25)
// In v5, this raises a runtime error when orders exceed 9000.

v6: Trims the Oldest Orders

In v6, when the total number of orders exceeds 9,000, the strategy does not halt. Instead, it trims the oldest orders from the beginning of the results until the count is back within the limit2. The strategy continues executing, and you see results for the most recent trades.

Trimmed orders no longer show in the Strategy Tester, and referencing them using the strategy.closedtrades.* functions returns na3. This is an important consideration if your strategy logic depends on historical trade data.

strategy.closedtrades.first_index

To help you work with trimmed results, v6 introduces the strategy.closedtrades.first_index variable3. This variable returns the index of the first (oldest) trade still available in the List of Trades. Under normal conditions, this value is zero. When trades have been trimmed, it returns the index of the oldest remaining trade.

//@version=6
strategy("Trade Trimming Demo", overlay = true)

if bar_index % 2 == 0
    for i = 1 to 5
        strategy.entry("Entry " + str.tostring(i), strategy.long, qty = 5)
else
    strategy.entry("Short", strategy.short, qty = 25)

// Check if trades have been trimmed
int totalOrders = strategy.opentrades + strategy.closedtrades
if barstate.islastconfirmedhistory
    if strategy.closedtrades.first_index > 0
        log.warning("Trades trimmed. First available trade index: {0}", strategy.closedtrades.first_index)
    // Trying to reference trimmed trades returns na
    if totalOrders > 9000
        string trimmedTradePrice = "Entry price of trade #0: " +
             str.tostring(strategy.closedtrades.entry_price(0))
        log.info(trimmedTradePrice)

When Trade Trimming Matters

This change is most relevant in two scenarios. First, high-frequency strategies that place many orders per bar will hit the 9,000 limit faster. Second, strategies backtested over long date ranges with frequent trading activity can accumulate thousands of trades.

If your strategy logic uses functions like strategy.closedtrades.entry_price(), strategy.closedtrades.exit_price(), or strategy.closedtrades.profit() to make decisions based on past trade history, be aware that trimmed trades return na. Use strategy.closedtrades.first_index to check whether the trade you are trying to reference still exists.

strategy.exit() Parameter Changes

This is the most subtle change in v6, and it can significantly alter backtest results for strategies that use strategy.exit() with both relative and absolute exit parameters.

The Three Parameter Pairs

The strategy.exit() function has three sets of paired parameters, each with a relative version (tick distance from entry) and an absolute version (specific price level):

  • Take-profit: profit (relative, in ticks) and limit (absolute price)
  • Stop-loss: loss (relative, in ticks) and stop (absolute price)
  • Trailing stop activation: trail_points (relative, in ticks) and trail_price (absolute price)3

v5 Behavior: Ignored Relative Params

In Pine Script v5, when a strategy.exit() call included both the relative and absolute parameters from the same pair, the function ignored the relative parameter entirely2. Only the absolute parameter was used for order placement.

For example, if you specified both profit = 100 and limit = close + 5.0, the v5 strategy.exit() would use only the limit value and completely discard the profit value. Many traders did not realize this was happening, especially when both parameters happened to produce similar price levels.

//@version=5
strategy("v5 Exit Behavior", overlay = true, margin_long = 100, margin_short = 100)
float atr = ta.atr(14)

if bar_index % 28 == 0
    strategy.entry("Buy", strategy.long)
    // In v5: profit = 0 is IGNORED because limit is also specified
    // Only the limit value is used for the take-profit order
    // Similarly, loss = 0 is IGNORED and only stop is used
    strategy.exit("Exit", "Buy", profit = 0, limit = close + 2.0 * atr,
         loss = 0, stop = close - 2.0 * atr)

In this v5 example, setting profit = 0 alongside a limit value had no effect. The take-profit order was placed at the limit price. The profit = 0 value was silently discarded.

v6 Behavior: Evaluates Both Parameters

In v6, strategy.exit() evaluates both the relative and absolute parameters when both are specified2. It creates the exit order at whichever level would trigger first based on the entry price and market direction.

For take-profit orders, if the profit distance would trigger before the limit price is reached, the order uses the profit level. If the limit price would be reached first, it uses the limit level. The same logic applies to the loss and stop pair, and to the trail_points and trail_price pair.

//@version=6
strategy("v6 Exit Behavior", overlay = true, margin_long = 100, margin_short = 100)
float atr = ta.atr(14)

if bar_index % 28 == 0
    strategy.entry("Buy", strategy.long)
    // In v6: BOTH profit and limit are evaluated
    // The order exits at whichever level triggers first
    // profit = 0 means the take-profit is 0 ticks from entry (immediate!)
    // This produces VERY different results than v5
    strategy.exit("Exit", "Buy", profit = 0, limit = close + 2.0 * atr,
         loss = 0, stop = close - 2.0 * atr)

This is a critical difference. In the example above, profit = 0 in v6 means the take-profit level is zero ticks from the entry price. Since the limit level is further away, the profit = 0 level triggers first, causing the strategy to exit immediately. The same v5 script that held trades for meaningful profit targets will now exit on the next tick in v6.

How to Fix Affected Scripts

If your v5 strategy.exit() calls used both relative and absolute parameters, you need to review each one. The most common fix is to remove the parameter you do not need.

If you want to use absolute price levels only:

// Remove the relative parameters
strategy.exit("Exit", "Buy", limit = takeProfitPrice, stop = stopLossPrice)

If you want to use tick distances only:

// Remove the absolute parameters
strategy.exit("Exit", "Buy", profit = 100, loss = 50)

If you intentionally want both evaluated:

// v6 evaluates both and exits at whichever triggers first
// Make sure both values produce meaningful price levels
strategy.exit("Exit", "Buy", profit = 200, limit = close + 5.0 * atr,
     loss = 100, stop = close - 3.0 * atr)

When you intentionally provide both parameters in v6, the strategy creates the exit order at whichever level is expected to trigger first. For a long trade, if the profit distance produces a price level below the limit price, the profit level is used. If the limit is closer to the current price, the limit level is used.

Migration Checklist

Use this checklist when converting any v5 strategy to v6:

  • Search for when = in all strategy.entry(), strategy.close(), strategy.exit(), and strategy.order() calls. Replace each with an if block.
  • Check your strategy() declaration for margin_long and margin_short. If not set, add explicit values matching your intended leverage.
  • Review all strategy.exit() calls that use both relative and absolute parameters (profit + limit, loss + stop, trail_points + trail_price). Decide which parameter to keep or verify that both produce correct levels.
  • If your strategy accesses historical trade data with strategy.closedtrades.* functions, add checks using strategy.closedtrades.first_index to handle potential trimming.
  • Run a side-by-side comparison of v5 and v6 backtest results on the same date range and instrument to verify your migration did not change intended behavior.
  • Update the version annotation from //@version=5 to //@version=6.

Testing Your Migrated Strategy

After applying the migration changes, verify your strategy by comparing results between v5 and v6. The most reliable approach is to keep a copy of your v5 script, apply the changes to a v6 copy, and add both to the same chart.

What to Compare

Open the Strategy Tester for each version and compare these key metrics:

  • Net Profit: Should match if margin and exit logic are unchanged.
  • Total Trades: Should match unless you hit the 9,000 limit.
  • Win Rate: Different exit behavior in strategy.exit() can change which trades are winners.
  • Max Drawdown: Margin changes directly affect drawdown calculations.
  • Trade List: Walk through individual trades to confirm entry and exit prices match.

If the results differ, use the new v6 logging functions to debug the discrepancies. Add log.info() calls at entry and exit points to trace exactly where the behavior diverges.

//@version=6
strategy("Migration Verification", overlay = true, margin_long = 100, margin_short = 100)

float smaFast = ta.sma(close, 14)
float smaSlow = ta.sma(close, 28)

if ta.crossover(smaFast, smaSlow)
    strategy.entry("Long", strategy.long)
    log.info("Long entry on bar {0} at price {1,number,#.##}", bar_index, close)
    strategy.exit("Exit Long", "Long", profit = 100, loss = 50)
    log.info("Exit orders set: TP = 100 ticks, SL = 50 ticks from entry")

if ta.crossunder(smaFast, smaSlow)
    strategy.close("Long")
    log.info("Position closed on bar {0} at price {1,number,#.##}", bar_index, close)

if ta.change(strategy.closedtrades) > 0
    int lastIdx = strategy.closedtrades - 1
    log.info("Trade result: P&L = {0,number,currency}, Entry = {1,number,#.##}, Exit = {2,number,#.##}",
         strategy.closedtrades.profit(lastIdx),
         strategy.closedtrades.entry_price(lastIdx),
         strategy.closedtrades.exit_price(lastIdx))

Automating Strategies with TradersPost

Once your strategy is migrated to Pine Script v6 and validated, the next step is connecting it to a live or paper trading account. TradersPost lets you automate TradingView strategies by converting alerts into real broker orders4.

The migration to v6 is a natural checkpoint to review and improve your automation setup. With the when parameter replaced by explicit if blocks, your alert logic is clearer and easier to verify. With explicit margin settings, your live trading position sizes will match what you see in backtesting. And with the strategy.exit() fix, your stop-loss and take-profit orders will behave consistently between backtests and live execution.

TradersPost supports automated order routing from TradingView alerts to brokers for stocks, options, futures, and crypto4. You can configure position sizing, risk limits, and order types directly in TradersPost to match your strategy parameters.

Visit TradersPost to set up automated trading for your Pine Script v6 strategies.

Conclusion

Pine Script v6 brings four significant changes to strategy behavior. The when parameter removal forces cleaner code patterns with explicit if blocks. The 100% default margin eliminates hidden leverage in backtests. Trade limit trimming replaces hard crashes with graceful degradation. And the strategy.exit() fix ensures that both relative and absolute exit parameters are properly evaluated.

Each of these changes can affect your backtest results, so take the time to migrate carefully. Use the checklist above, compare results side by side, and leverage the new v6 logging system to trace any discrepancies. The result is more predictable, more transparent strategy behavior that better reflects what will happen when you move from backtesting to live trading.

References

1 Pine Script Release Notes
2 Pine Script v5 to v6 Migration Guide
3 Pine Script v6 Language Reference
4 TradersPost - Automated Trading Platform

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