init()
Declare indicators and initialize state. Called once before the backtest starts.
Signature
function init(ctx)
Parameters
| Name | Type | Description |
|---|---|---|
ctx | InitContext | Context for indicator declaration and state |
ctx.indicator()
Declare indicators that will be pre-computed by the engine:
ctx.indicator(name, type, options)
| Argument | Type | Description |
|---|---|---|
name | string | Unique name to access via ctx.ind.name |
type | string | Indicator type (see available indicators) |
options | object | Indicator-specific options |
Key insight: Indicators are computed by the engine on the host side before onBar runs. This is much faster than computing them yourself.
Display Option
Add display: true to show the indicator on the chart:
// This indicator will appear on the price chart ctx.indicator('ema', 'EMA', { period: 21, source: 'close', display: true }); // This indicator is computed but NOT shown on chart (default) ctx.indicator('rsi', 'RSI', { period: 14 });
Example
function init(ctx) { // Trend indicators - shown on chart ctx.indicator('fastEma', 'EMA', { period: ctx.p.fastLength, source: 'close', display: true }); ctx.indicator('slowEma', 'EMA', { period: ctx.p.slowLength, source: 'close', display: true }); // Momentum - not displayed (used for signal logic only) ctx.indicator('rsi', 'RSI', { period: 14 }); ctx.indicator('macd', 'MACD', { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9 }); // Volatility ctx.indicator('atr', 'ATR', { period: 14 }); ctx.indicator('bbands', 'BBANDS', { period: 20, stdDev: 2 }); // Initialize state ctx.state.tradeCount = 0; ctx.state.lastSignalBar = -1; ctx.state.inPosition = false; }
Available Indicators
Moving Averages
| Indicator | Options | Output |
|---|---|---|
SMA | period, source | number[] |
EMA | period, source | number[] |
WMA | period, source | number[] |
DEMA | period, source | number[] |
TEMA | period, source | number[] |
Trend
| Indicator | Options | Output |
|---|---|---|
MACD | fastPeriod, slowPeriod, signalPeriod | { line, signal, histogram } |
ADX | period | { adx, pdi, mdi } |
PSAR | step, max | number[] |
ICHIMOKU | tenkanPeriod, kijunPeriod, senkouBPeriod | { tenkan, kijun, senkouA, senkouB, chikou } |
TRIX | period, source | number[] |
Momentum / Oscillators
| Indicator | Options | Output |
|---|---|---|
RSI | period, source | number[] |
STOCH | kPeriod, dPeriod | { k, d } |
STOCHRSI | rsiPeriod, stochPeriod, kPeriod, dPeriod | { k, d } |
CCI | period | number[] |
WILLIAMSR | period | number[] |
ROC | period, source | number[] |
AO | fastPeriod, slowPeriod | number[] |
PPO | shortGamma, longGamma, accuracy | number[] |
Volatility
| Indicator | Options | Output |
|---|---|---|
BBANDS | period, stdDev | { upper, middle, lower } |
ATR | period | number[] |
DONCHIAN | period | { upper, middle, lower } |
KELTNER | period, multiplier | { upper, middle, lower } |
Volume
Source Options
The source option can be:
'open','high','low','close','volume''hl2'— (high + low) / 2'hlc3'— (high + low + close) / 3'ohlc4'— (open + high + low + close) / 4
ctx.state
Initialize mutable state that persists across bars:
function init(ctx) { ctx.state.consecutiveLosses = 0; ctx.state.peakEquity = 0; ctx.state.lastEntryPrice = null; }
State is accessed in onBar via ctx.state:
function onBar(ctx, i) { ctx.state.consecutiveLosses++; }
Multi-Output Indicators
Some indicators return multiple series:
function init(ctx) { ctx.indicator('macd', 'MACD', { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9 }); ctx.indicator('bbands', 'BBANDS', { period: 20, stdDev: 2 }); } function onBar(ctx, i) { // Access MACD components const macdLine = ctx.ind.macd.macd[i]; const signalLine = ctx.ind.macd.signal[i]; const histogram = ctx.ind.macd.histogram[i]; // Access Bollinger Bands const upper = ctx.ind.bbands.upper[i]; const middle = ctx.ind.bbands.middle[i]; const lower = ctx.ind.bbands.lower[i]; }
Common Mistakes
Computing indicators in onBar
// WRONG - Don't compute indicators yourself function onBar(ctx, i) { const ema = calculateEma(ctx.series.close, 20); // Slow! } // RIGHT - Declare in init, engine computes them function init(ctx) { ctx.indicator('ema', 'EMA', { period: 20 }); }
Forgetting to initialize state
// WRONG - state.count is undefined on first bar function onBar(ctx, i) { ctx.state.count++; // NaN! } // RIGHT - Initialize in init function init(ctx) { ctx.state.count = 0; }
Related
- define() — Parameter declaration
- onBar() — Trading logic
- Available Indicators — Full indicator reference
lifecycleinitindicatorsstateqsl