Docs

Indicators Lab

The complete reference for the Setup.Cash Indicators Lab — the formula language, every built-in function, the inputs/outputs schema, worked examples, and how to use indicators in strategies.

By Setup.Cash TeamLast updated 2026-06-268 min read

The Indicators Lab is the workspace where you browse, author, test, and manage the indicators that power your strategies. This page is a complete reference: the workspace, the formula language, every built-in function, the schema, and worked examples.

The Workspace

Open the lab at /indicators. It has three tabs:

TabPurpose
Library100+ built-in indicators (RSI, MACD, Bollinger Bands, Supertrend, Ichimoku, ADX, VWAP, Stochastic, and more). Each shows its full settings and its outputs — exactly what it computes and plots.
PresetsSave a configured indicator (e.g. "RSI 7 on M5") and reuse it across strategies, scoped to specific timeframes and symbols.
CustomAuthor your own indicator — generated by AI or written directly — fully editable and owned by you.

A right-hand chart panel previews any selected indicator on real candles with per-output statistics.

Two Ways to Author an Indicator

Generate it with AI

In the Custom tab, describe the indicator in plain language. The model writes a complete indicator — inputs, outputs, and logic — and the server executes it on real candles to verify it runs, automatically correcting itself if the engine reports an error. Generation runs server-side and survives a page refresh. The result loads into the editor for review.

Write it in the formula language

You can also author an indicator directly in the editor using the lab's purpose-built formula language, documented in full below. The editor provides syntax highlighting, line numbers, and validation on save.


The Formula Language

The formula language is a declarative, vectorized, single-pass language for time series. You do not write loops over bars — every expression operates on the entire price series at once, and the engine evaluates it efficiently in one pass. This makes indicators concise and fast.

An indicator has three parts:

  1. Inputs — the tunable parameters (lengths, multipliers, thresholds, source).
  2. Outputs — the series, levels, and events the indicator produces.
  3. Source — the formula that computes the outputs from price.

Statements

The source is a list of statements, one per line:

let NAME = EXPRESSION        // declare a reusable series or value
plot("OUTPUT_KEY", EXPRESSION)        // emit a numeric series output
event("OUTPUT_KEY", BOOLEAN_EXPRESSION)   // emit a boolean signal output
  • let binds a name to an expression so you can reuse it. Declare a name before you use it.
  • plot(...) emits a numeric series. Its OUTPUT_KEY must be declared as a series or level output.
  • event(...) emits a boolean event (a signal). Its OUTPUT_KEY must be declared as an event output.
  • Comments start with //.

Price Series (always in scope)

These series are available without declaration:

NameMeaning
open high low closeOHLC prices
volumeBar volume
hl2(high + low) / 2
hlc3(high + low + close) / 3
ohlc4(open + high + low + close) / 4

You can also select a source dynamically with src("close"), src("hl2"), etc. — useful when "source" is an input.

Operators

Arithmetic and comparison operators work element-wise across the series:

  • Arithmetic: + - * /
  • Comparison (produce a boolean series): > >= < <= == !=

For example, close > ema(close, 50) produces a boolean series that is true on every bar where the close is above its 50-period EMA.


Function Reference

Every function operates element-wise over the full series. x, a, b are series or values; len, n are integers.

Moving Averages & Regression

FunctionDescription
sma(x, len)Simple moving average
ema(x, len)Exponential moving average
rma(x, len)Wilder's smoothed moving average
wma(x, len)Linearly weighted moving average
linreg(x, len)Linear-regression value at the current bar (endpoint of the best-fit line over len)
slope(x, len)Slope of that linear-regression line (rate of change of trend)

Momentum & Oscillators

FunctionDescription
rsi(x, len)Relative Strength Index (0–100)
roc(x, len)Rate of change (percent)
zscore(x, len)Standard deviations from the rolling mean
change(x, n)x minus its value n bars ago (default n = 1)
mom(x, n)Momentum — same as change with default n = 10
percentrank(x, len)Percent of the last len values below the current value (0–100)

Volatility

FunctionDescription
atr(len)Average True Range
tr()True Range (single bar)
stdev(x, len)Rolling standard deviation
variance(x, len)Rolling variance
dev(x, len)Rolling mean absolute deviation (used by CCI-style measures)

Range, Extremes & Stats

FunctionDescription
highest(x, len)Highest value over len bars
lowest(x, len)Lowest value over len bars
median(x, len)Rolling median
sum(x, len)Rolling sum over len bars
cum(x)Cumulative sum from the first bar
correlation(a, b, len)Rolling Pearson correlation of two series (−1 to 1)

Volume

FunctionDescription
vwap()Cumulative volume-weighted average price

Series Logic & Timing

FunctionDescription
shift(x, bars)The value of x shifted bars to the right (the value bars ago)
crossover(a, b)True on the bar where a crosses above b
crossunder(a, b)True on the bar where a crosses below b
cross(a, b)True on any cross (above or below)
rising(x, n)True when x has risen for n consecutive bars
falling(x, n)True when x has fallen for n consecutive bars
barssince(cond)Number of bars since cond was last true
valuewhen(cond, x, occurrence)The value of x the last (or N-th last) time cond was true

Conditional & Math

FunctionDescription
if(cond, a, b)Element-wise select: a where cond is true, else b
between(x, lo, hi)True where lo <= x <= hi
clamp(x, lo, hi)Constrain x to the range [lo, hi]
abs(x) min(a, b) max(a, b)Absolute value, element-wise min, element-wise max
pow(a, b) sqrt(x) log(x) exp(x)Power, square root, natural log, exponential
sign(x) round(x) floor(x) ceil(x)Sign (−1/0/1), rounding

Boolean

FunctionDescription
and(a, b) or(a, b) not(x)Boolean combinators over boolean series

Use only the functions and series above. The engine validates this when you save — an unknown name or function is rejected with a clear message, so an indicator that saves is an indicator that runs.


Inputs Schema

inputs_schema exposes every tunable parameter:

{
  "version": 1,
  "inputs": [
    { "key": "len", "label": "Length", "type": "int", "default": 14, "min": 1, "max": 500, "step": 1, "required": true, "ui": { "control": "stepper", "group": "Parameters" } },
    { "key": "src", "label": "Source", "type": "source", "default": "close", "options": ["open","high","low","close","hl2","hlc3","ohlc4"] }
  ]
}
FieldNotes
typeint, float, bool, string, enum, source, timeframe, symbol, color, series_ref
default min max stepDefaults and bounds for numeric inputs
optionsChoices for enum/source
ui.controlstepper, slider, select, segmented, toggle, text, color
ui.groupA label used to group inputs in the editor

Reference any input by its key directly in the source (an input with key len is used as len).

Outputs Schema

outputs_schema declares everything the indicator produces:

{
  "version": 1,
  "outputs": [
    { "key": "value", "label": "Value", "kind": "series", "data_type": "number", "plot": { "style": "line", "pane": "sub", "line_width": 2 } },
    { "key": "buy", "label": "Buy", "kind": "event", "data_type": "boolean" }
  ]
}
FieldNotes
kindseries (a line), level (a horizontal level), or event (a boolean signal)
data_typenumber for series/level, boolean for events
plot.styleline, markers, hist, area, bands
plot.panemain (over price) or sub (separate pane)

Every plot("key", …) and event("key", …) must reference a declared output key.


Worked Examples

1. RSI with bands and crossover signals

Inputs: len (int, 14), ob (int, 70), os (int, 30), src (source, close). Outputs: rsi (series, sub), buy (event), sell (event).

let r = rsi(src(src), len)
plot("rsi", r)
event("buy", crossover(r, os))
event("sell", crossunder(r, ob))

2. Bollinger Bands with a squeeze event

Inputs: len (int, 20), mult (float, 2). Outputs: upper (series, main), basis (series, main), lower (series, main), squeeze (event).

let basis = sma(close, len)
let band = stdev(close, len) * mult
plot("upper", basis + band)
plot("basis", basis)
plot("lower", basis - band)
event("squeeze", band < median(band, 50) * 0.6)

3. Adaptive RSI (length tightens with volatility)

Uses zscore and clamp to shorten the RSI length when volatility expands.

let vol = zscore(atr(14), 50)
let adaptiveLen = round(clamp(len - vol * 4, 5, 40))
let r = rsi(close, adaptiveLen)
plot("rsi", r)
plot("signal", ema(r, 5))
event("bull", crossover(r, ema(r, 5)))

4. Volume-pressure / relative volume

Inputs: len (int, 20), spike (float, 2). Outputs: rvol (series, sub), vol_ma (series, sub), high_volume (event).

let vavg = sma(volume, len)
let rvol = volume / vavg
plot("rvol", rvol)
plot("vol_ma", vavg)
event("high_volume", rvol > spike)

5. Trend strength via regression slope

let s = slope(close, 50)
plot("slope", s)
event("trend_up", s > 0 and rising(s, 3))
event("trend_down", s < 0 and falling(s, 3))

Preview, Customize, and Use

  • Preview / Test: select a symbol, timeframe, and candle window, then render candles with your indicator overlaid, plus per-output statistics (min, max, last value, signal counts).
  • Customize a built-in: built-in indicators are shared and read-only; the Customize action creates your own editable copy, saved to your profile only — it never affects the built-in or other users.
  • Use in a strategy: reference your indicator by name in text-to-strategy, add the Custom Indicator block in the simple builder, or wire its custom node in the blueprint builder.

Custom indicators are strictly per-user: you can only edit your own, and nothing you do affects the shared library or anyone else's work.

Next Steps

Not financial advice. Trading involves risk. These docs describe software workflows and risk controls, not guaranteed outcomes.

Start here

Build your trading bot workflow with structure

Use Setup.Cash to create, backtest, and paper trade rule-based strategies without relying on guesswork. Not financial advice. Trading involves risk.