DocsBacktest Engineindicators

Indicator Computation

Understanding how indicators are computed helps you write efficient strategies.

Host-Side Computation

Unlike traditional backtesting where you compute indicators in your strategy code, QSL indicators are computed by the engine before your onBar() runs.

1. define(ctx) runs - parameters collected
2. init(ctx) runs - indicator declarations collected
3. ENGINE COMPUTES ALL INDICATORS (host-side, fast)
4. onBar(ctx, i) runs - indicators already available

Why This Matters

Performance

Computing a 200-period EMA on 10,000 bars requires 10,000 calculations. If done in JavaScript for every bar, that's 100 million operations.

With host-side computation:

  • Computed once in optimized native code
  • Results passed to your strategy as arrays
  • 10x-100x faster than in-strategy computation

Consistency

All strategies use the same indicator implementations:

  • No bugs in custom indicator code
  • Results match across strategies
  • Platform-verified accuracy

Declaration in init()

function init(ctx) { // These are declarations, not computations ctx.indicator('ema', 'EMA', { period: ctx.p.period, source: 'close' }); ctx.indicator('rsi', 'RSI', { period: 14 }); ctx.indicator('macd', 'MACD', { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9 }); }

Access in onBar()

By the time onBar() runs, all indicator values are pre-computed:

function onBar(ctx, i) { // These are array lookups, not calculations const ema = ctx.ind.ema[i]; const rsi = ctx.ind.rsi[i]; const macdLine = ctx.ind.macd.macd[i]; const macdSignal = ctx.ind.macd.signal[i]; }

Warm-up Period

Indicators need historical data before producing valid values:

IndicatorWarm-up
SMA(20)20 bars
EMA(20)~20 bars
RSI(14)15 bars
MACD(12,26,9)35 bars

During warm-up, values are NaN:

function onBar(ctx, i) { // Always check for NaN if (q.isNaN(ctx.ind.ema[i])) return; // Now safe to use }

Don't Compute Manually

// WRONG - Computing in onBar (slow) function onBar(ctx, i) { let sum = 0; for (let j = i - 20; j <= i; j++) { sum += ctx.series.close[j]; } const sma = sum / 20; } // RIGHT - Declare in init (fast) function init(ctx) { ctx.indicator('sma', 'SMA', { period: 20 }); } function onBar(ctx, i) { const sma = ctx.ind.sma[i]; // Pre-computed }

Related

engineindicatorscomputationperformanceqsl