RoboQuant
RoboQuant engine

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:

ColumnTypeMeaning
timei64Unix timestamp (seconds)
open, high, low, close, volumefloatOHLCV

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

SymbolPurpose
IndicatorBase class — override compute()
paramParameter decorator
taTA-Lib on numpy arrays
np, plnumpy / polars
numba@numba.njit for hot loops

Network, filesystem, and service imports are blocked in the indicator subprocess (security).

Dashboard workflow

  1. Indicators section → create indicator → Code tab (AI or manual)
  2. Set show_on_chart=true to list it in RoboCharts My Indicators
  3. Open a chart → add your indicator from the dropdown
  4. 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

StrategyIndicator
TradesYes (ctx.buy / ctx.sell)No
Runs inCompiled backtest/live runtimeChart compute subprocess
OutputOrders, equity, logs, drawingsPlot specs (JSON)
Source.rq.rqcPython compute() entry