RoboQuant Indicators
Custom indicators add sandboxed, Python-computed overlays to RoboCharts—session boxes, custom oscillators, and liquidity tools—without changing your compiled trading strategy.
Indicators are separate entities from strategies: they do not submit orders. Use the built-in Ind runtime handles described in the strategy API reference when an indicator is part of trading logic; use this custom-indicator API when the output is only for a chart.
Minimal example
from rq_indicators import Indicator, param, ta, pl
@param("period", int, default=14, min=2, max=200, label="Period")
class MyRSI(Indicator):
def compute(self, bars: pl.DataFrame, plot, period):
close = bars["close"].to_numpy()
rsi = ta.RSI(close, timeperiod=period)
times = bars["time"].to_list()
plot.line(times, rsi, name="RSI", color="#A78BFA", pane="oscillator")
plot.hline(70, color="#EF4444", dashed=True, pane="oscillator")
plot.hline(30, color="#10B981", dashed=True, pane="oscillator")
Input data shape
bars is a polars DataFrame with columns:
| Column | Type | Meaning |
|---|---|---|
time | i64 | Unix timestamp (seconds) |
open, high, low, close, volume | float | OHLCV |
The chart passes one vectorized window per compute call.
Extra data and range limits (@needs)
Indicators can request additional data alongside bars with the
@needs(...) decorator — for example @needs("trades") for tick-level
trades or @needs("trade_flow") for per-bar aggregated order flow.
Tick-level trades data is hard-capped to protect the compute service:
at most a 45-day window and 5 million ticks per request. Beyond
either cap the indicator returns a structured range_too_wide error
telling you to zoom in to a narrower window — the chart shows the
message inline and does not retry. For wide windows, use
@needs("trade_flow") instead: it aggregates trades per bar
server-side, so it scales to any chart range.
Parameters
Declare tunables with @param on the class:
@param("period", int, default=14, min=2, max=200, label="Period")
@param("overbought", float, default=70.0, min=50, max=95, label="Overbought")
class MyIndicator(Indicator):
...
The dashboard renders controls from this schema. Values are passed into compute(self, bars, plot, **params).
Plot API
Plots are declarative — you describe series; the chart renderer draws them.
plot.line(time, values, name, color, pane="price", axis_label_visible=False)
plot.histogram(time, values, name, color, baseline=0, pane="oscillator", axis_label_visible=False)
plot.markers(time, prices, name, color, shape="circle", pane="price", axis_label_visible=False)
plot.hline(value, name, color, dashed=False, pane="oscillator", axis_label_visible=False)
plot.band(time, upper, lower, name, color, opacity=0.15, pane="price", axis_label_visible=False)
axis_label_visible=True shows this plot’s name on the chart’s right-hand price scale (default hidden). Supported on line, histogram, hline, and band — not box. On markers the same kwarg has a different effect (markers never show a price-scale pill): it draws the plot name as text next to each marker; markers draw no text by default.
Supported shapes for markers: circle, triangle-up, triangle-down, cross.
Available imports
| Symbol | Purpose |
|---|---|
Indicator | Base class — override compute() |
param | Parameter decorator |
ta | TA-Lib on numpy arrays |
np, pl | numpy / polars |
numba | @numba.njit for hot loops |
Network, filesystem, and service imports are blocked in the indicator subprocess (security).
Dashboard workflow
- Indicators section → create indicator → Code tab (AI or manual)
- Set
show_on_chart=trueto list it in RoboCharts My Indicators - Open a chart → add your indicator from the dropdown
- Parameters adjust live; results are cached per symbol/timeframe/window
Compute model
- Vectorized: full visible window in one
compute()call - On new bars, the tail window is recomputed (not an incremental state machine in v1)
- Errors return structured messages: syntax, runtime, timeout, forbidden import
Strategy vs indicator
| Strategy | Indicator | |
|---|---|---|
| Trades | Yes (ctx.buy / ctx.sell) | No |
| Runs in | Compiled backtest/live runtime | Chart compute subprocess |
| Output | Orders, equity, logs, drawings | Plot specs (JSON) |
| Source | .rq → .rqc | Python compute() entry |
Related docs
- Strategies — compiled trading logic
- Runtime reference — built-in strategy indicators