Pine v6 Reference for AlfaTactix Export: ta.*, Entries, Qty, Costs

Export-oriented map of ta.* cores, strategy.entry/exit, and commission — not a full language manual. Links official v6 reference.

📖 8 min read

📝 1,512 words

🏷️ Pine Script and TradingView

Share this article:

v6 changes that stop the script

The compiler finds all of these, so they cost time rather than money. Every row is from the official migration guide [1].

v5 codeWhy v6 rejects itFix
if someNumbernumbers no longer cast to bool implicitlyif bool(someNumber) or if someNumber != 0
na(someBool), nz(someBool)bool can no longer be naremove — a bool is true or false
plot(close, style = na)unique-type parameters reject nagive a real style
a switch returning a unique type with no defaultthe missing branch would be naadd a => default branch
strategy.entry("id", strategy.long, when = cond)when was removedwrap in if cond
6[1], true[10], color.red[3]no history on literals or built-in constantsremove the []
myObject.field[10]no direct history on a UDT field(myObject[10]).field — parentheses required
plot(close, color = a, color = b)a parameter cannot repeatkeep one
plot(close, offset = seriesValue)offset must be simple, not seriesuse a const or input value
plot(close, linewidth = 0)minimum is 1use 1 or more
plot(close, transp = 80)transp was removedcolor = color.new(myColor, 80)
ta.ema(close, mutableLen)a mutated variable is now series, and ta.ema wants simpleuse a fixed or input length

Two of these deserve a note.

when was the standard way to place a conditional order in v5, so it appears in a very large share of published v5 strategies. Every one of them needs the if rewrite. It is mechanical, but it is not optional.

The mutable-variable rule is the one people argue with. A variable that is reassigned during execution qualifies as series, and functions like ta.ema() accept only simple for their length [1]. In v5 this slipped through. It was never sound — an indicator length that changes bar to bar has no consistent history — so v6 is refusing something that was silently wrong rather than removing a feature.

The colour constants changed value

Not an error, but it belongs here because it surprises people comparing screenshots [1]:

Constantv5v6
color.red#FF5252#F23645
color.teal#00897B#089981
color.yellow#FFEB3B#FDD835

label.new() also changed its default text colour from color.black to color.white.


v6 changes that do not error

These are the migration changes that let the script compile and run, and change what it returns. They are the reason a converted strategy can backtest differently while looking identical, and they are all documented [1] — just not grouped this way.

What changedv5v6Consequence
and / or evaluationboth sides always evaluatedshort-circuitsan indicator call after a false condition is skipped, corrupting its history
margin_long / margin_short default0 — no margin checking100 — strict enforcementmargin calls where there were none
strategy.exit() with both relative and absolute levelsabsolute won, relative ignoredwhichever triggers firstprofit = 0, limit = price now exits at entry
Orders beyond 9,000runtime error, execution haltedoldest orders silently trimmedtrimmed trades return na from strategy.closedtrades.*
timeframe.period on a daily chart"D""1D"timeframe.period == "D" is now always false
5 / 2 with two const ints22.5thresholds and lookback lengths shift
A bool referenced before it existsnafalsefirst-bar logic takes the other branch
for i = 0 to exprexpr evaluated oncere-evaluated every iterationa loop whose bound mutates can run indefinitely
An int or float used as a conditionimplicitly cast to boolno longer casta truthiness test that compiled in v5 now fails to compile
array.get(-1)runtime errorreturns the last elementan off-by-one that used to shout now returns a plausible wrong value
color.red#FF5252#F23645plots change shade; color.teal and color.yellow moved too, and default label text went black to white

The lazy-evaluation one is the worst of them

Every other item on that list changes a number. This one corrupts an indicator's internal state, and the damage is invisible in the code.

In v5 both sides of and were always evaluated, so an indicator inside a condition was called on every bar and kept a continuous history. In v6 evaluation short-circuits [1], so the call is skipped on bars where the first condition is false — and an indicator that did not run on every bar no longer has the history it needs.

TradingView's own example [1]:

pine
// v6: ta.rsi() is skipped whenever close <= open,
// so its internal history is no longer continuous
if close > open and ta.rsi(close, 14) > 50
    signal := true

The fix is to pull the call into global scope, where it runs unconditionally:

pine
rsiVal = ta.rsi(close, 14)
if close > open and rsiVal > 50
    signal := true

This is worth checking in every converted script that calls a ta.* function inside an if, a switch, or the right-hand side of an and. Nothing warns you, and the backtest still produces a curve.

The margin default catches leveraged strategies

margin_long and margin_short defaulted to 0 in v5, which meant no margin checking at all and permitted overleveraging. In v6 they default to 100, which enforces margin and triggers margin calls [1].

A v5 strategy that was quietly overleveraged will now be stopped out by the engine. To reproduce the old behaviour deliberately, set them back explicitly:

pine
strategy("My strategy", margin_long = 0, margin_short = 0)

That is a choice about realism, not a bug fix — v6's default is the more honest of the two, and a strategy that only worked without margin enforcement was never going to survive live.


Using the converter, and what it misses

The Pine Editor's own converter handles most of the mechanical changes automatically [1]. Use it first — hand-migrating the table above is wasted effort.

Its documented limits [1]:

  • A script that does not compile cleanly as v5 cannot be auto-converted. Fix it as v5 first, then convert.
  • Rare cases still produce v6 compilation errors that need a manual fix.
  • Dynamic request behaviour may differ, and restoring v5 semantics can require setting dynamic_requests = false explicitly.

That last one is worth expanding, because it is a change of default rather than a change of syntax. In v5, request.*() calls were non-dynamic by default and dynamic_requests = true was needed to call them inside loops or conditionals. In v6 they are dynamic by default and the compiler disables it when it is not needed [1]. Scripts that previously needed the flag now work without it — but nested requests can behave differently, and calling request.*() in a local scope with dynamic_requests = false is now a compile error.

What the converter cannot do

Nothing in the converter addresses the silent changes above. It rewrites syntax; it does not know that your ta.rsi() inside an and no longer runs every bar, or that your strategy now enforces margin. After converting, the silent list is still yours to check.

Where exporting avoids the question

If the strategy was built in AlfaTactix rather than hand-written, there is nothing to migrate: the strategy is stored as structured data and the generator emits current v6. Re-exporting produces a file that is already v6-correct, including the defaults above.

That only helps for strategies you build here. A v5 script you wrote or inherited has to be migrated — which is what the rest of this page is for.


What the generator emits

This is an export-oriented map, not a language manual — for the full surface, the official v6 reference is the authority [2].

The wrapper. Every export is a strategy() declaration, never indicator(). That is what makes the Strategy Tester able to report trades at all [3]; a script declared as an indicator plots and nothing more.

Indicator calls. Basic export draws on the ta.* namespace — ta.rsi, ta.sma, ta.ema, ta.macd, ta.stoch, ta.atr, ta.bb, ta.cci, ta.wpr among them. Lengths are emitted as fixed or input values, never as mutated variables, which is also what v6 requires of a simple length parameter.

Entries and exits. Orders are placed with strategy.entry() wrapped in an if, and closed with strategy.exit() or strategy.close(). The if form is not a style preference — when no longer exists in v6.

Position size and costs. strategy() carries the capital, commission and slippage you set in the builder, so the Strategy Tester is costed rather than frictionless. A backtest without costs is the most common way a strategy looks profitable and is not.

What Basic export will not emit

Multi-timeframe logic, VWAP-based targets, and news filters are outside Basic. The export refuses rather than emitting something that behaves differently from what you designed — see the generator errors in Common Pine Script errors.



Tactix AI on this workflow

AlfaTactix includes Tactix AI: use Tactix Studio to describe your idea in plain language and draft timeframes, signals, filters, and risk into the same six-step Strategy Builder form — or open Tactix Guide on any step when you only need a field explained. Review every value, then export MQL5 or Pine Script from Code Generator (form-first — not untested prompt-to-code).

Frequently Asked Questions

No. It maps patterns AlfaTactix export emits to official v6 reference [1]. For hand-coding depth, use TradingView docs; for building, use Strategy Builder.

Commonly ta.rsi, ta.sma/ta.ema/ta.wma, ta.macd, ta.bb, ta.stoch, ta.cci, ta.wpr, ta.atr, ta.obv, volume compares — see playbooks on the hub.

strategy() [1] args + commission guide.

Pine riskstrategy.exit / sizing. Official: Strategies [2].

TradingView Basic track has no MTF. See repaint/lookahead · filters.

MQL5 programming reference — different language.

References

  1. TradingView. Migration guide — to Pine Script® version 6. https://www.tradingview.com/pine-script-docs/migration-guides/to-pine-version-6
  2. TradingView. Pine Script® language reference manual. https://www.tradingview.com/pine-script-reference/v6/
  3. TradingView. Script structure. https://www.tradingview.com/pine-script-docs/language/script-structure