Skip to content
GetProfitable
Search

The ta.* and math.* namespaces

Lesson 7 · about 11 min

Pine ships with most of the indicators you would otherwise write yourself, grouped in namespaces. ta.* holds technical analysis functions, math.* holds arithmetic, and knowing what is already there saves you from reinventing an RSI with a subtle bug in it. This lesson is a guided tour rather than a reference; the reference manual has the full list.

Averages and oscillators

Function Returns
ta.sma(src, len) simple moving average
ta.ema(src, len) exponential moving average (simple int length)
ta.wma(src, len) weighted moving average
ta.rma(src, len) Wilder's smoothing, used inside RSI and ATR
ta.vwma(src, len) volume-weighted moving average
ta.rsi(src, len) RSI 0 to 100
ta.atr(len) average true range
ta.tr(true) true range for the current bar
ta.stoch(src, high, low, len) stochastic %K
ta.cci(src, len) commodity channel index
ta.mfi(src, len) money flow index

Several functions return more than one value as a tuple:

//@version=6
indicator("Tuple built-ins", overlay=false)
[macdLine, signalLine, hist] = ta.macd(close, 12, 26, 9)
[middle, upper, lower] = ta.bb(close, 20, 2.0)
[superTrend, direction] = ta.supertrend(3.0, 10)
plot(hist, "MACD histogram", style=plot.style_histogram, color=hist >= 0 ? color.green : color.red)
plot(macdLine, "MACD", color=color.blue)
plot(signalLine, "Signal", color=color.orange)

You must unpack every element of a tuple, but you can name the ones you do not need _, as in [_, _, hist] = ta.macd(close, 12, 26, 9).

Highs, lows and events

  • ta.highest(src, len) / ta.lowest(src, len): extreme over the last len bars, including the current one. ta.highest(high, 20)[1] is the prior 20-bar high excluding this bar, which is what a breakout test needs.
  • ta.highestbars(src, len): how many bars ago the extreme happened, as a negative offset.
  • ta.crossover(a, b) / ta.crossunder(a, b): true on the single bar where a moves above or below b. ta.cross(a, b) is either.
  • ta.change(src): src - src[1]; ta.change(src, n) for n bars.
  • ta.rising(src, len) / ta.falling(src, len): true if src rose or fell on each of the last len bars.
  • ta.barssince(cond): bars since the condition was last true.
  • ta.valuewhen(cond, src, n): the value of src the n-th most recent time cond was true (0 is the most recent).
  • ta.pivothigh(src, left, right) / ta.pivotlow: the pivot price when a bar's src is the highest of left bars before and right bars after; returns na on other bars. Because it needs right bars after the pivot, the value appears right bars late. That is lag, not repainting, but plotted labels look like they "knew" in advance.
  • ta.cum(src): running total from the first bar.
  • ta.vwap(src): volume-weighted average price, anchored to the session by default.
//@version=6
indicator("Events demo", overlay=true)
basis = ta.sma(close, 20)
barsSinceCross = ta.barssince(ta.crossover(close, basis))
ph = ta.pivothigh(high, 5, 5)
lastPivotHigh = ta.valuewhen(not na(ph), ph, 0)
plot(basis, "SMA 20", color=color.blue)
plot(lastPivotHigh, "Last pivot high", color=color.red, style=plot.style_stepline)
plotchar(barsSinceCross == 0, "Cross", char="x", location=location.belowbar, color=color.green)

math.*

math.abs, math.max, math.min, math.avg, math.round(x, precision), math.floor, math.ceil, math.sqrt, math.pow, math.log, math.sign, math.sum(src, len). Two that matter for trading specifically:

  • math.round_to_mintick(price) rounds a computed price to the symbol's tick size, which you need before using it as a stop or limit price; the emulator rejects prices between ticks.
  • math.max and math.min accept several arguments, so math.max(a, b, c) works.

Percent changes and normalisation are plain arithmetic:

atrPct = ta.atr(14) / close * 100
distFromHigh = (ta.highest(high, 52) - close) / ta.highest(high, 52) * 100

Volume and other built-in series

volume, open, high, low, close, hl2, hlc3, ohlc4, bar_index, time, time_close. Symbol details live in syminfo.*: syminfo.tickerid, syminfo.ticker, syminfo.mintick, syminfo.pointvalue, syminfo.currency, syminfo.type (stock, futures, forex, crypto and so on). Chart details are in timeframe.* and chart.*.

Key idea: Before writing a calculation, check ta.*. The built-in is faster, tested, and returns na correctly on the warm-up bars, which hand-rolled versions often do not.

Two habits

First, call ta.* functions unconditionally at the global scope and use the results conditionally, as module 2 explained. Second, when a built-in takes a length, make it an input so it is simple and adjustable; hard-coded literals in the middle of a script are the first thing you will regret.

Try it: Build a small dashboard in its own pane: RSI 14, ATR as a percent of close, and bars since the last 20-bar high (ta.barssince(high == ta.highest(high, 20))). Then add a plotchar on bars where RSI crosses above 30 using ta.crossover.

Recap

  • ta.* holds averages, oscillators, extremes, crosses, pivots and VWAP; several return tuples you unpack with [a, b, c] =.
  • ta.highest(high, n)[1] is the prior n-bar high excluding the current bar, the usual breakout reference.
  • Pivots confirm right bars late: lag, not prediction.
  • math.round_to_mintick prepares computed prices for orders; math.max/math.min take multiple arguments.
  • Prefer built-ins, call them every bar, and make lengths inputs.

See it drawn

Original diagrams for the ideas on this page. Illustrative, not real market data.

MACD line, signal line and histogram under a price chartA price line above a lower panel holding two curves and a bar histogram measured from a zero line, with the point where the faster curve rises through the slower one circled.PRICEMACD (12, 26, 9)0signalMACDbullishcrossover
MACD, signal line and histogram. The MACD line is the gap between a fast and a slow moving average, and the signal line is a smoothed copy of it. The bars show the distance between the two, and the circle marks where the faster line rises through the slower one.
A fast and a slow moving average crossingA jagged price line with two smoother average lines through it; the fast average dips below the slow one on the left and cuts back above it in the middle, where a circle marks the crossing.pricefast averageslow averagefast crosses belowfast crosses abovethe slow averageAverages of recent closes; the fast one reacts sooner than the slow one.
Fast and slow moving averages crossing. A moving average is the average of the last few closing prices, redrawn each period. An average over fewer periods turns sooner than one over many, so the two lines cross whenever the recent pace of the market changes.
A simple and an exponential moving average over the same pricesOne price line with two smoothed lines drawn through it; the exponential average bends away from the simple average as soon as price turns, and sits between price and the simple average all the way down.SAME PRICES, TWO AVERAGES (8 PERIODS)the EMA turns down firstand stays nearer to price8-day SMA8-day EMApriceIllustrative prices. Both averages smooth the same series over the same span.
Simple versus exponential averages. Both lines average the last eight prices, but the exponential version gives the newest prices the most weight while the simple version treats them all alike. That is why the exponential line bends first when price turns and then tracks it more closely.