DocsType Reference
Helper Functions (q)
The q namespace provides 12 utility functions available globally in onBar(). These are pure functions — they do not modify state.
Reference
| Function | Signature | Description |
|---|---|---|
q.crossOver | (a: number[], b: number[]|number, i: number) => boolean | a crosses above b at bar i |
q.crossUnder | (a: number[], b: number[]|number, i: number) => boolean | a crosses below b at bar i |
q.highest | (series: number[], period: number, i: number) => number | Highest value in lookback |
q.lowest | (series: number[], period: number, i: number) => number | Lowest value in lookback |
q.sma | (series: number[], period: number, i: number) => number | Simple moving average over lookback |
q.isNaN | (value: number) => boolean | Check if indicator is not yet computed |
q.clamp | (value: number, min: number, max: number) => number | Constrain value within range |
q.between | (value: number, min: number, max: number) => boolean | Check if value is within range |
q.pctChange | (a: number, b: number) => number | Percentage change from b to a |
q.sign | (value: number) => -1 | 0 | 1 | Sign of a number |
q.abs | (value: number) => number | Absolute value |
q.round | (value: number, decimals: number) => number | Round to N decimal places |
Examples
function onBar(ctx, i) { const close = ctx.series.close; const ema = ctx.ind.ema; // Skip bars where indicator isn't ready if (q.isNaN(ema[i])) return; // Detect crossover if (q.crossOver(close, ema, i)) { ctx.order.market('ASSET', 1, { signal: 'buy' }); } // Use a constant threshold if (q.crossUnder(ctx.ind.rsi, 30, i)) { ctx.order.market('ASSET', 1, { signal: 'rsi_oversold' }); } // Donchian-style breakout using helpers const highest20 = q.highest(ctx.series.high, 20, i); if (close[i] > highest20) { ctx.order.market('ASSET', 1, { signal: 'breakout' }); } // Inline SMA for volume filter const avgVol = q.sma(ctx.series.volume, 20, i); if (ctx.series.volume[i] < avgVol * 0.5) return; // Low volume, skip // Position sizing with clamp const rawSize = q.round(10000 / close[i], 4); const size = q.clamp(rawSize, 0.01, 5); // RSI neutral zone check if (q.between(ctx.ind.rsi[i], 40, 60)) { // Neutral — no strong signal } }
Notes
q.crossOverandq.crossUnderaccept either an array or a constant as the second argument- All lookback functions (
highest,lowest,sma) returnNaNif the lookback window extends before bar 0 q.pctChange(a, b)returns(a - b) / bas a decimal (0.05 = 5%)
helpersqcrossOvercrossUnderisNaNhighestlowestsmaclampbetweenpctChangesignabsround