DocsExamples

RSI Mean Reversion Strategy

A counter-trend strategy that buys oversold conditions and sells overbought.

Code

/** * RSI Mean Reversion Strategy * * Buys when RSI exits oversold zone * Sells when RSI enters overbought zone */ function define(ctx) { ctx.param('rsiPeriod', { type: 'int', label: 'RSI Period', default: 14, min: 2, max: 50, optimize: true }); ctx.param('oversold', { type: 'int', label: 'Oversold Level', default: 30, min: 10, max: 40 }); ctx.param('overbought', { type: 'int', label: 'Overbought Level', default: 70, min: 60, max: 90 }); } function init(ctx) { ctx.indicator('rsi', 'RSI', { period: ctx.p.rsiPeriod }); } function onBar(ctx, i) { const rsi = ctx.ind.rsi; const { oversold, overbought } = ctx.p; if (q.isNaN(rsi[i]) || i < 1) return; const pos = ctx.position('ASSET'); // Buy: RSI crosses above oversold level (exiting oversold) if (rsi[i - 1] <= oversold && rsi[i] > oversold && pos.qty === 0) { ctx.order.market('ASSET', 1, { signal: 'buy', reason: 'rsi_exits_oversold' }); } // Sell: RSI enters overbought zone if (rsi[i - 1] < overbought && rsi[i] >= overbought && pos.qty > 0) { ctx.order.close('ASSET', { signal: 'sell', reason: 'rsi_overbought' }); } }

Key Concepts

Level Crossing vs Threshold

This strategy uses level crossing (not just threshold):

// LEVEL CROSSING: RSI was below, now above if (rsi[i - 1] <= oversold && rsi[i] > oversold) { // Entering means momentum is shifting } // vs SIMPLE THRESHOLD (not used here) if (rsi[i] < oversold) { // Could be oversold for many bars }

Accessing Previous Bar

Use i - 1 to check the previous bar's value:

if (i < 1) return; // Need at least 2 bars const prevRsi = rsi[i - 1]; const currRsi = rsi[i];

Stop Loss Protection

Add a stop loss for risk management:

function onBar(ctx, i) { const pos = ctx.position('ASSET'); if (pos.qty > 0) { const pnl = (ctx.series.close[i] - pos.avgPrice) / pos.avgPrice; // Stop loss at -3% if (pnl < -0.03) { ctx.order.close('ASSET', { signal: 'stop_loss' }); return; } } // ... rest of logic }

Variation: Exit on Opposite Signal

Instead of waiting for overbought, exit when RSI returns to neutral:

// Exit when RSI returns above 50 (neutral) if (rsi[i] > 50 && pos.qty > 0) { ctx.order.close('ASSET', { signal: 'sell', reason: 'rsi_neutral' }); }

Performance Notes

  • Works best in ranging/choppy markets
  • Gets crushed in strong trends
  • Consider adding trend filter (only trade with trend)

Related

examplersimean reversionmomentumqsl