Skip to main content
← Back to blog

Pine Script: Using [1] on ta.dmi, ta.macd and Other Tuples

📅 2026-10-27
✍️ Strategy Arena
pine script tradingview ta.dmi tuple request.security debugging

Searching for "ta.dmi" "[1]" "tuple" usually means one thing: a Pine Script line like ta.dmi(14, 14)[1] refuses to compile. This short guide gives the rule behind the error, the fix, and the same fix for every built-in that returns several values at once.

Short answer: ta.dmi returns a tuple of three series. The history operator [1] works on a series, not on a function call that returns a tuple. Unpack the tuple into variables first, then use [1] on the variable you need.

The error and the fix

The line that fails:

//@version=5
indicator("ADX previous bar")
adxPrev = ta.dmi(14, 14)[1]   // does not compile: [1] on a tuple-returning call

The version that works:

//@version=5
indicator("ADX previous bar")
[diPlus, diMinus, adx] = ta.dmi(14, 14)
adxPrev = adx[1]
plot(adx, "ADX")
plot(adxPrev, "ADX, previous bar")

Two details matter here:

  • The order is fixed: ta.dmi(diLength, adxSmoothing) returns [+DI, -DI, ADX]. If you write [adx, diPlus, diMinus], the script still compiles, because all three are numbers, and your strategy silently trades on the wrong line.
  • Every element gets a name. If you only need the ADX, still name all three, for example [_dip, _dim, adx], and ignore the first two.

The same rule for every tuple

Several ta.* built-ins return more than one series. The fix is always the same: destructure, then index.

Built-in Returns, in order Previous value of the last element
ta.dmi(14, 14) +DI, -DI, ADX [p, m, adx] = ta.dmi(14, 14) then adx[1]
ta.macd(close, 12, 26, 9) MACD line, signal line, histogram [m, s, h] = ta.macd(close, 12, 26, 9) then h[1]
ta.bb(close, 20, 2) middle, upper, lower band [mid, up, lo] = ta.bb(close, 20, 2) then lo[1]
ta.kc(close, 20, 1.5) middle, upper, lower channel [mid, up, lo] = ta.kc(close, 20, 1.5) then lo[1]
ta.supertrend(3, 10) SuperTrend line, direction [st, dir] = ta.supertrend(3, 10) then dir[1]

Built-ins that return a single series accept [1] directly: ta.rsi(close, 14)[1], ta.ema(close, 20)[1] or ta.stoch(close, high, low, 14)[1] all compile.

SuperTrend: what does direction < 0 mean?

With [st, dir] = ta.supertrend(3, 10), a negative direction means the uptrend (the line sits below price) and a positive direction means the downtrend. That is why the usual plot reads plot(dir < 0 ? st : na, "Up direction"). A direction change is simply dir != dir[1], which again works only on the destructured variable.

request.security with a tuple

request.security accepts an expression that returns a tuple, so this works:

[dPlus, dMinus, adxD] = request.security(syminfo.tickerid, "D", ta.dmi(14, 14))

But that line behaves differently live and in the backtest: on historical bars the daily value only appears once the day is over, while in real time it updates during the day. To use the previous, finished daily bar without repainting, move the [1] inside a function and request it with lookahead_on:

//@version=5
indicator("Daily ADX, previous finished day")
dmiPrev() =>
    [p, m, a] = ta.dmi(14, 14)
    [p[1], m[1], a[1]]

[dPlusPrev, dMinusPrev, adxPrevD] = request.security(syminfo.tickerid, "D", dmiPrev(), lookahead = barmerge.lookahead_on)
plot(adxPrevD, "Daily ADX, previous day")

The [1] inside the function plus lookahead_on is the standard non-repainting pattern: each daily value is used only once that day is closed.

Two neighbours of the same error

  • ta.obv(close, volume) does not compile in Pine Script v5: ta.obv is a built-in variable, not a function. Write ta.obv, or its formula ta.cum(math.sign(ta.change(close)) * volume) if you need another source.
  • ta.vwap exists both as a variable (ta.vwap, based on hlc3) and as a function (ta.vwap(close)). Called with a standard-deviation multiplier, recent versions return a tuple [vwap, upper, lower], and the destructure-then-index rule applies again.

Also keep history-dependent built-ins such as ta.dmi or ta.ema out of if blocks: Pine Script warns about it, because a function skipped on some bars no longer computes the same series. Compute it on every bar, then use the result inside the condition.

Once it compiles: check the trades, not only the chart

A script that compiles can still trade on the wrong line, on a repainting value, or on a filter computed only on some bars. The Strategy Tester shows the result of the settings you chose; it does not tell you whether the rule holds on data you never looked at.

Strategy Arena Lab is a free Windows and Linux app that replays supported Pine on your PC and compares its trades one by one with TradingView's. Its supported subset includes ADX thresholds and +DI/-DI direction rules from ta.dmi, ta.mfi and ta.obv (details on backtesting Pine Script locally). It then judges the strategy on a period kept sealed during the search. For more ready-made scripts, see the free Pine Script library and 7 free Pine Script strategies.

Frequently asked questions

Why does ta.dmi(14, 14)[1] not compile in Pine Script? ta.dmi returns a tuple of three series (+DI, -DI, ADX). The history operator [1] applies to a series, not to a function call that returns a tuple. Destructure first, then index the variable: [diPlus, diMinus, adx] = ta.dmi(14, 14), then adx[1].

In which order does ta.dmi return its values? ta.dmi(diLength, adxSmoothing) returns [+DI, -DI, ADX], in that order. Swapping the names silently gives a wrong strategy, because all three are numbers.

How do I get the previous daily ADX with request.security without repainting? Wrap the calculation in a function that destructures ta.dmi and returns the [1] values, then call request.security on the daily timeframe with lookahead = barmerge.lookahead_on. The [1] offset makes the daily value final before it is used.

Is ta.obv(close, volume) valid Pine Script v5? No. In Pine Script v5, ta.obv is a built-in variable, not a function: write ta.obv. Its equivalent formula is ta.cum(math.sign(ta.change(close)) * volume).


Educational content on Pine Script syntax. Strategy Arena gives no investment advice, and the Lab places no order.

⚠️ Disclaimer — This article is for informational and educational purposes only. It does not constitute investment advice or a buy/sell recommendation. Past performance does not guarantee future results. Strategy Arena is an educational simulator with virtual capital. Always do your own research before making investment decisions.

Enjoyed this article? Share it

𝕏 Share on X ✈️ Telegram

Turn a local result into durable proof

The Lab runs free on your PC. Paid options only keep or expand the work — they never change the verdict.

Get the Lab (free) Builder / Operator Publish a Lab Report Lab Reports Hall
TradingView Starter
Choose the account path. Prove the strategy separately.
Your first chart and price alert do not require the Lab. Strategy Arena proof remains required before trusting or exporting a strategy.
Partner attribution is for first-time users and web purchases only. Strategy Arena may earn a commission on eligible purchases; starting with a free account needs no payment.
I have never had an account · Start free I already have an account Check a strategy
More TradingView paths
Evidence-gated Pine review