Builtins: series maths

Every length must be a positive whole number. Window functions return nan until a complete window of finite values exists, which is normal at the left edge of the chart.

SignatureReturns
ta.sma(source: float, length: int) -> floatMean of a complete window
ta.ema(source: float, length: int) -> floatExponential average, alpha 2 / (length + 1), seeded from the first finite value
ta.rma(source: float, length: int) -> floatWilder average, alpha 1 / length
ta.wma(source: float, length: int) -> floatLinearly weighted mean, newest weighted length
ta.sum(source: float, length: int) -> floatSum of a complete window
ta.variance(source: float, length: int) -> floatPopulation variance
ta.stdev(source: float, length: int) -> floatSquare root of the population variance
ta.dev(source: float, length: int) -> floatMean absolute deviation from the window mean
ta.highest(source: float, length: int) -> floatMaximum of a complete window
ta.lowest(source: float, length: int) -> floatMinimum of a complete window
ta.change(source: float [, length: int]) -> floatsource minus source length bars ago, default 1
ta.crossover(a: float, b: float) -> boola was at or below b and is now above
ta.crossunder(a: float, b: float) -> boola was at or above b and is now below
ta.cross(a: float, b: float) -> boolEither of the two

Indicators

The usual indicators, with the same names and arguments as Pine Script where Pine has them. len is a positive whole number of bars.

SignatureReturns
ta.tr([handle_na: bool]) -> floatTrue range. On the first bar it is high minus low, or nan with false
ta.atr(len) -> floatAverage true range, Wilder smoothed
ta.rsi(source, len) -> floatRelative strength index, 0 to 100
ta.macd_line(source, fast, slow) -> floatFast EMA minus slow EMA
ta.macd_signal(source, fast, slow, signal) -> floatEMA of the MACD line
ta.macd_hist(source, fast, slow, signal) -> floatLine minus signal
ta.bb_upper(source, len, mult) -> float, ta.bb_lower(...)Bollinger bands: the SMA plus or minus mult standard deviations
ta.bb_width(source, len, mult) -> floatBand width as a percent of the SMA
ta.kc_upper(source, len, mult) -> float, ta.kc_lower(...)Keltner channels: the EMA plus or minus mult times the EMA of the true range
ta.stoch(source, high, low, len) -> floatStochastic, 0 to 100
ta.cci(source, len) -> floatCommodity channel index
ta.mfi(source, len) -> floatMoney flow index, 0 to 100
ta.wpr(len) -> floatWilliams %R, -100 to 0
ta.cmo(source, len) -> floatChande momentum oscillator, -100 to 100
ta.tsi(source, short, long) -> floatTrue strength index, -1 to 1
ta.plus_di(len) -> float, ta.minus_di(len) -> floatDirectional indicators
ta.adx(di_len, adx_len) -> floatAverage directional index
ta.supertrend(factor, atr_len) -> floatThe SuperTrend line
ta.supertrend_dir(factor, atr_len) -> float-1 in an up trend, 1 in a down trend
ta.psar(start, increment, maximum) -> floatParabolic SAR
ta.obv() -> floatOn balance volume
ta.cum(source) -> floatRunning total since the first bar
ta.mom(source, len) -> float, ta.roc(source, len) -> floatChange over len bars, and the same as a percent
ta.rising(source, len) -> bool, ta.falling(source, len) -> boolAbove, or below, every one of the previous len values
ta.hma, ta.vwma, ta.dema, ta.tema(source, len) -> floatHull, volume weighted, double and triple exponential averages
ta.alma(source, len, offset, sigma) -> floatArnaud Legoux average
ta.swma(source) -> floatSymmetric weighted average of the last four values
ta.linreg(source, len, offset) -> floatLeast squares line value, offset bars back from the newest
ta.correlation(a, b, len) -> floatPearson correlation
ta.percentrank(source, len) -> floatPercent of the previous len values at or below this one
ta.median(source, len) -> floatMedian of the window
ta.percentile_nearest(source, len, percent) -> float, ta.percentile_linear(...)Percentile by nearest rank, or interpolated
ta.range(source, len) -> floatHighest minus lowest
ta.pivothigh([source,] left, right) -> float, ta.pivotlow(...)The pivot value, on the bar right bars after it, otherwise nan
ta.barssince(condition) -> floatBars since the condition was last true, 0 on that bar, nan before it ever was
ta.highestbars(source, len) -> float, ta.lowestbars(...)Offset of the extreme, 0 or negative
ta.valuewhen(condition, source, occurrence) -> floatsource on the bar of an earlier true condition, 0 being the latest
ta.avg_when(condition, source, n) -> float, ta.sum_when(...)Average or sum of source over the last n bars where the condition was true, n from 1 to 500
ta.vwap() -> floatThe session VWAP the chart draws, reset at 18:00 New York
ta.vwap_band(k: int) -> floatThat VWAP plus k standard deviations, k from -3 to 3
  • They follow Pine Script: ta.rsi, ta.atr and the directional indicators use Wilder smoothing seeded with a simple average, and ta.ema is seeded with the first value. ta.rma on its own is seeded with the first value, as it always was.
  • A nan anywhere in a window gives nan for that window, where Pine skips na in some functions.
  • ta.pivothigh and ta.pivotlow confirm late: the pivot is reported right bars after the bar it happened on, and equal neighbours are not a pivot.
  • ta.supertrend_dir is -1 in an up trend, as in Pine. Both SuperTrend calls are nan while the ATR warms up.
  • ta.median and the percentiles take windows up to 1,000 bars.
  • ta.valuewhen, ta.avg_when and ta.sum_when must be called on every bar with the condition, not from inside an if.

These read the value you pass on each bar at that call site. Put the call where it runs on every bar, at the top level, so its window is continuous. A call inside an if branch, or inside one arm of ? :, only samples the bars where it runs. They cannot be called inside a loop.

let fast: float = ta.ema(close, 9)
let slow: float = ta.ema(close, 21)
let crossed_up: bool = ta.crossover(fast, slow)
let spread_of_closes: float = ta.dev(close, 20)

Every layer of the market, Orderflow to optionflow, on one chart.

Institutional grade Orderflow data with backtesting and journaling built in. Join the waitlist for early access.

Get Access