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.
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:
| Tab | Purpose |
|---|---|
| Library | 100+ 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. |
| Presets | Save a configured indicator (e.g. "RSI 7 on M5") and reuse it across strategies, scoped to specific timeframes and symbols. |
| Custom | Author 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:
- Inputs — the tunable parameters (lengths, multipliers, thresholds, source).
- Outputs — the series, levels, and events the indicator produces.
- 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
letbinds a name to an expression so you can reuse it. Declare a name before you use it.plot(...)emits a numeric series. ItsOUTPUT_KEYmust be declared as aseriesorleveloutput.event(...)emits a boolean event (a signal). ItsOUTPUT_KEYmust be declared as aneventoutput.- Comments start with
//.
Price Series (always in scope)
These series are available without declaration:
| Name | Meaning |
|---|---|
open high low close | OHLC prices |
volume | Bar 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
| Function | Description |
|---|---|
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
| Function | Description |
|---|---|
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
| Function | Description |
|---|---|
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
| Function | Description |
|---|---|
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
| Function | Description |
|---|---|
vwap() | Cumulative volume-weighted average price |
Series Logic & Timing
| Function | Description |
|---|---|
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
| Function | Description |
|---|---|
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
| Function | Description |
|---|---|
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"] }
]
}
| Field | Notes |
|---|---|
type | int, float, bool, string, enum, source, timeframe, symbol, color, series_ref |
default min max step | Defaults and bounds for numeric inputs |
options | Choices for enum/source |
ui.control | stepper, slider, select, segmented, toggle, text, color |
ui.group | A 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" }
]
}
| Field | Notes |
|---|---|
kind | series (a line), level (a horizontal level), or event (a boolean signal) |
data_type | number for series/level, boolean for events |
plot.style | line, markers, hist, area, bands |
plot.pane | main (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
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.