RSI Scalper Template
The RSI Scalper is a mean-reversion strategy that buys when the market is oversold and sells when it is overbought, based on the Relative Strength Index. It works best in range-bound markets where price tends to revert to a mean rather than trend in one direction.
How the strategy works
The Relative Strength Index (RSI) is a momentum oscillator that measures the speed and magnitude of recent price changes. It produces a value between 0 and 100:
- RSI below 30 (default oversold level) — Price has been falling aggressively. The market may be oversold and due for a bounce.
- RSI above 70 (default overbought level) — Price has been rising aggressively. The market may be overbought and due for a pullback.
- RSI near 50 — Neutral momentum. No clear signal.
RSI calculation
The RSI is calculated without external libraries using this process:
- Compute the price change between consecutive closes over the RSI period
- Separate changes into gains (positive) and losses (negative)
- Calculate the average gain and average loss over the period
- Compute the Relative Strength (RS) = average gain / average loss
- RSI = 100 - (100 / (1 + RS))
If the average loss is zero (price only went up), RSI returns 100. If there is not enough data yet, RSI returns 50 (neutral) to avoid premature signals.
Signal flow
- Collect closing prices bar by bar
- Wait until enough bars exist to calculate RSI (default: 15 bars = RSI_PERIOD + 1)
- On each new bar, compute the RSI value
- If RSI < oversold threshold (30) and not already long: buy
- If RSI > overbought threshold (70) and not already short: sell
- Repeat until all bars are processed
Parameters
| Parameter | Default | Description |
|---|---|---|
RSI_PERIOD | 14 | Number of bars used to calculate the RSI value |
OVERBOUGHT | 70 | RSI level above which the market is considered overbought (sell signal) |
OVERSOLD | 30 | RSI level below which the market is considered oversold (buy signal) |
MAX_BARS | 0 | Maximum bars to process. 0 means process all available bars |
How to set parameters
- RSI_PERIOD — Standard value is 14 (Wilder’s original setting). Lower values (7-10) make RSI more sensitive, producing more signals. Higher values (20-30) make it smoother, producing fewer signals.
- OVERBOUGHT / OVERSOLD — The wider the gap between these thresholds (e.g., 80/20 instead of 70/30), the fewer but higher-conviction signals you get. Narrower gaps (65/35) produce more signals with more noise.
- The OVERBOUGHT value must be greater than the OVERSOLD value.
The Python code
Here is the complete strategy logic:
RSI_PERIOD = int(os.environ.get("RSI_PERIOD", "14"))OVERBOUGHT = int(os.environ.get("OVERBOUGHT", "70"))OVERSOLD = int(os.environ.get("OVERSOLD", "30"))MAX_BARS = int(os.environ.get("MAX_BARS", "0")) or int(os.environ.get("TOTAL_BARS", "999999"))
# ... (backtest session setup is auto-generated) ...
# ─── RSI SCALPER STRATEGY ───────────────────────────────closes = []position = Nonetrade_count = 0wins = 0entry_price = 0
def calc_rsi(data, period): """Calculate RSI without external libraries.""" if len(data) < period + 1: return 50 # Neutral gains = [] losses = [] for j in range(len(data) - period, len(data)): change = data[j] - data[j - 1] gains.append(max(0, change)) losses.append(max(0, -change)) avg_gain = sum(gains) / period avg_loss = sum(losses) / period if avg_loss == 0: return 100 rs = avg_gain / avg_loss return 100 - (100 / (1 + rs))
print(f"[INFO] Strategy: RSI Scalper (period={RSI_PERIOD}, OB={OVERBOUGHT}, OS={OVERSOLD})")
try: for i in range(MAX_BARS): bar = get_next_bar() if bar is None: break
closes.append(bar["c"]) read_speed() if STEP_DELAY > 0: time.sleep(STEP_DELAY)
if len(closes) < RSI_PERIOD + 1: continue
rsi = calc_rsi(closes, RSI_PERIOD) price = bar["c"]
# Buy signal: RSI below oversold if rsi < OVERSOLD and position != "LONG": if position == "SHORT": place_order(ACCOUNT_ID, CONTRACT_ID, 0, 2) if entry_price - price > 0: wins += 1 trade_count += 1 else: place_order(ACCOUNT_ID, CONTRACT_ID, 0, 1) position = "LONG" entry_price = price trade_count += 1 print(f"[TRADE] BUY @ {price:.2f} | RSI: {rsi:.1f} (oversold)")
# Sell signal: RSI above overbought elif rsi > OVERBOUGHT and position != "SHORT": if position == "LONG": place_order(ACCOUNT_ID, CONTRACT_ID, 1, 2) if price - entry_price > 0: wins += 1 trade_count += 1 else: place_order(ACCOUNT_ID, CONTRACT_ID, 1, 1) position = "SHORT" entry_price = price trade_count += 1 print(f"[TRADE] SELL @ {price:.2f} | RSI: {rsi:.1f} (overbought)")Key code details
calc_rsi(data, period)— Computes RSI from raw close prices without any external library. Returns 50 (neutral) when there is insufficient data, preventing premature signals.- Position flipping — Like the SMA Crossover, when the strategy reverses direction it places a size-2 order to close the existing position and open a new one simultaneously.
- Gain/loss separation — The RSI implementation separates positive and negative price changes, averaging them separately over the lookback period.
Example output
[INFO] Strategy: RSI Scalper (period=14, OB=70, OS=30)[INFO] Using pre-created session: NQ (CON.F.US.ENQ.H25)[INFO] Account: 12345, Contract: CON.F.US.ENQ.H25, Bars: 390────────────────────────────────────────────────────────────[TRADE] BUY @ 21485.50 | RSI: 28.3 (oversold)[TRADE] SELL @ 21510.25 | RSI: 72.1 (overbought)[TRADE] BUY @ 21492.00 | RSI: 25.7 (oversold)[TRADE] SELL @ 21518.75 | RSI: 74.5 (overbought)...────────────────────────────────────────────────────────────[DONE] Backtest Complete![DONE] Final Balance: $50,480.00[DONE] Net P&L: +$480.00[DONE] Total Trades: 22[DONE] Win Rate: 63.6%Tuning tips
Adjusting sensitivity
For more frequent trading signals:
- Set RSI_PERIOD=7 for a faster-reacting RSI
- Widen thresholds slightly: OVERBOUGHT=65, OVERSOLD=35
- Best on 1-second to 1-minute bars where you want to scalp small moves
- Expect more trades, smaller average gains, and more noise
The default settings are a solid starting point:
- RSI_PERIOD=14, OVERBOUGHT=70, OVERSOLD=30
- Works well on 1-minute to 5-minute bars
- Good balance between signal frequency and signal quality
- Standard RSI interpretation used by most traders
For fewer but higher-quality signals:
- Set RSI_PERIOD=21 for a smoother RSI
- Tighten thresholds: OVERBOUGHT=80, OVERSOLD=20
- Best on 5-minute to 15-minute bars over multiple days
- Fewer trades but higher win rate per signal
Common pitfalls
- Trending markets destroy mean-reversion strategies. If NQ is in a strong uptrend, RSI will stay above 50 (often above 70) for extended periods. The strategy will keep shorting into strength and accumulate losses. Always check if your date range includes trending conditions.
- RSI divergence is not captured. The template uses raw RSI levels only. It does not detect RSI divergence (where price makes a new high but RSI does not), which is often a stronger signal. You would need a custom strategy to implement divergence detection.
- The “dead zone.” When RSI stays between 30 and 70, the strategy does nothing. During low-volatility periods, you may see long stretches without any trades. This is by design — the strategy waits for extreme readings.
- Whipsaw near thresholds. If RSI oscillates around the 30 or 70 level, the strategy can rapidly enter and exit positions. Consider adding a cooldown period in a custom version.
Ideas for improvement
- Add a trend filter. Only take long signals (RSI oversold) when a longer-period SMA is rising, and only take short signals when the SMA is falling. This aligns mean-reversion entries with the broader trend.
- RSI divergence. Detect when price makes a new low but RSI makes a higher low (bullish divergence) for stronger buy signals.
- Take-profit levels. Instead of waiting for the opposite RSI extreme, exit when RSI crosses back to 50 (neutral) for quicker profits.
- Time filter. Avoid trading during the first 15 minutes of the session (high volatility, erratic RSI readings) or during lunch hours (low volume, unreliable signals).
- Adaptive thresholds. Adjust overbought/oversold levels based on recent volatility — wider in trending markets, tighter in ranges.
See Custom Strategies to implement these enhancements.