Skip to main content

Indicators

Every ta.* function returns a Series, so results can be indexed ([0], [1]), plotted, and passed into other indicators. The math is shared with the Coinray charts and scanner, so values match what you see elsewhere in the app.

GroupFunctions
Moving averagesta.sma ema rma wma hma alma vwma vwap linreg swma cum
Oscillatorsta.rsi macd cci wpr mfi cmo cog mom roc change stochK stoch stochRsi tsi
Volatilityta.tr atr stdev variance dev range bb bbw kc kcw
Trendta.dmi supertrend sar
Volumeta.obv accdist pvt iii wvad
Extremes and statisticsta.highest lowest highestbars lowestbars pivothigh pivotlow median percentrank percentileNearestRank percentileLinearInterpolation
Two seriesta.correlation(a, b, length)
Anchoredta.vwapBands(source, Anchor.Day | Anchor.Week, mult)

See the API Reference for every signature.

Multi-output indicators​

Some indicators return an object of series:

const bb = ta.bb(src.close, 20, 2.0); // bb.lower, bb.middle, bb.upper
const m = ta.macd(src.close, 12, 26, 9); // m.macd, m.signal, m.histogram
const d = ta.dmi(14, 14); // d.plus, d.minus, d.adx
const st = ta.supertrend(10, 3.0); // st.value, st.direction
const vb = ta.vwapBands(src.hlc3, Anchor.Week, 2.0); // vb.vwap, vb.upper, vb.lower

Indicators over your own formulas​

Put any formula into a series and it becomes an indicator input:

const range = series();

export function onBar(): void {
range[0] = src.high[0] - src.low[0];
const avgRange = ta.sma(range, 20);
plotPane("range", avgRange, "range");
}

Crosses, rising, bars since​

Stateful helpers are created at top level and updated every bar:

const cross = new Cross();
const since = new BarsSince();

export function onBar(): void {
const fast = ta.ema(src.close, 9)[0];
const slow = ta.ema(src.close, 21)[0];
const dir = cross.update(fast, slow); // 1 = crossed above, -1 = crossed below, 0 = none
const barsAgo = since.update(dir > 0); // bars since the last cross above, -1 if never
}

Rising and Falling report whether a value moved one way on each of the last length bars, and ValueWhen returns a value from the bar a condition last fired.

Math and helpers​

math.* mirrors Pine's math namespace: abs sign floor ceil round sqrt pow exp log log10 sin cos tan asin acos atan todegrees toradians max min avg sum roundToMintick, plus the constants math.pi e phi rphi. Every function takes a number or a series (read at the current bar).

na(x) tests for a missing value, nz(x, replacement) replaces it, and round(x, decimals) / toFixed(x, decimals) format numbers.

Shading between two levels​

fillLevels fills the band between two hlines — an RSI 30–70 zone, or the overbought and oversold backgrounds of Bollinger %b:

import { color, fillLevels, hline, plotPane } from "@coinray/strategy"

hline(70, color.withTransp(color.red, 50), Stroke.Dashed, "RSI")
hline(30, color.withTransp(color.green, 50), Stroke.Dashed, "RSI")
fillLevels(70, 30, color.withTransp(color.blue, 90), "RSI")

Declare it at module top level beside the levels it refers to, naming their prices rather than the lines; order does not matter. The band spans the pane's width, so the levels need not be visible — Pine's habit of anchoring a fill to an off-scale hline(100, display = display.none) becomes naming that price.

Shading a bar's background​

bgcolor fills the whole height of the pane behind one bar, which is how session windows, regimes and "this bar matters" states are usually drawn:

import { bgcolor, color, hour, plot, src } from "@coinray/strategy"

export function onBar(): void {
const h = hour() // UTC, like every time helper
if (h >= 12 && h < 14) bgcolor(color.withTransp(color.red, 90))
plot("close", src.close[0])
}

Call it only on the bars it applies to — a bar you skip keeps the chart's own background, which is Pine's na. The colour carries its own alpha, so Pine's transp = argument is color.withTransp(c, transp). Two calls on one bar do not composite: the last one wins, so a script layering several zones should pick the colour itself and call once. A second argument names a sub-pane to shade, exactly as in plotPane.

Colouring candles​

barcolor recolours the candle itself (Pine barcolor). Like bgcolor, call it on the bars it applies to; a bar you skip keeps the chart's candle colour, and the last call on a bar wins:

import { barcolor, color, param, src } from "@coinray/strategy"

const up = param.color("Up colour", color.green)
const down = param.color("Down colour", color.red)

export function onBar(): void {
if (src.volume[0] > src.volume[1] * 2) barcolor(src.close[0] >= src.open[0] ? up : down)
}

Notes​

  • ta.cum sums from the first loaded bar (the start of the warmup window), not from the first bar ever traded.
  • ta.vwap resets at 00:00 UTC. ta.vwapBands can anchor on the day, the week (Monday 00:00 UTC), or any number of seconds. There is no monthly anchor.
  • ta.correlation needs both series on the same timeframe.