Strategy · Pine Script v5 · On the chart

Mean Reversion

by nxtaiapp

This strategy executes mean-reversion trades using Bollinger Bands combined with a fast RSI oscillator and MACD confirmation.

View on GitHub

GitHub stars2on the repository
Pine versionv5runs as is
Lines of code261
Settings30inputs
LicenceMIT
Last update11 months ago30 Nov 2025

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

261 lines of Pine Script v5 from Mean reversion scalper corrected.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

Mean reversion scalper corrected.pine
//@version=5
strategy("Mean Reversion",
     overlay=true, initial_capital=50000,
     default_qty_type=strategy.fixed, default_qty_value=1,
     calc_on_every_tick=false,
     calc_on_order_fills=true, process_orders_on_close=false)

// ========================================
// USER INPUTS
// ========================================
// Moving Average & Standard Deviation Settings
maLength = input.int(21, "MA Length")
stdDevMultiplier = input.float(2.0, "Standard Deviation Multiplier", step=0.1)

// RSI Settings
rsiLength = input.int(5, "RSI Length")
rsiOversold = input.int(20, "RSI Oversold Level")
rsiOverbought = input.int(80, "RSI Overbought Level")

// Trade Management (in ticks)
profitTicks = input.int(21, "Profit Target (ticks)")
stopTicks = input.int(34, "Stop Loss (ticks)")
tickValue = input.float(12.50, "Tick Value ($)", tooltip="ES = $12.50, NQ = $5.00")

// Position Sizing
initialContracts = input.int(10, "Initial Contracts")
maxContracts = input.int(10, "Maximum Contracts")

// Time Filter
useTimeFilter = input.bool(true, "Use Trading Hours Filter")
startHour = input.int(8, "Start Hour (EST)")
startMinute = input.int(30, "Start Minute")
endHour = input.int(14, "End Hour (EST)")
endMinute = input.int(0, "End Minute")

// Daily Limits
useDailyLimits = input.bool(true, "Use Daily P&L Limits")
dailyProfitTarget = input.float(999, "Daily Profit Target ($)")
dailyLossLimit = input.float(500, "Daily Loss Limit ($)")
maxDailyTrades = input.int(2, "Max Daily Trades")

// ========================================
// CALCULATE INDICATORS
// ========================================
// Bollinger Bands (for standard deviation)
basis = ta.sma(close, maLength)
stdDev = ta.stdev(close, maLength)
upperBand = basis + (stdDevMultiplier * stdDev)
lowerBand = basis - (stdDevMultiplier * stdDev)

// RSI
rsi = ta.rsi(close, rsiLength)

// === MACD (added) ===
// MACD Inputs
macd_fast_length = input.int(8, "MACD Fast Length")
macd_slow_length = input.int(21, "MACD Slow Length")
macd_signal_length = input.int(8, "MACD Signal Length")
macd_src = input.source(close, "MACD Source")

sma_source_macd = input.string("EMA", "MACD Oscillator MA Type", options=["SMA", "EMA"])
sma_signal_macd = input.string("EMA", "MACD Signal MA Type", options=["SMA", "EMA"])
// MACD confirmation mode (expanded)
macdConfirm = input.string("None", "MACD Confirmation", options=["None", "Histogram > 0", "Histogram Rising", "MACD > Signal", "MACD Cross Signal"], tooltip="Choose how MACD must confirm entries")
requireRSIandMACD = input.bool(true, "Require RSI oversold/overbought AND MACD rising/falling", tooltip="If true, longs require RSI oversold AND MACD histogram rising; shorts require RSI overbought AND MACD histogram falling")

// Price action confirmation
requirePriceAction = input.bool(false, "Require Price Action Confirmation", tooltip="Require a small engulfing or wick rejection before entry")
priceActionType = input.string("Lower Wick", "Price Action Type", options=["Engulfing", "Lower Wick"], tooltip="Type of price-action confirmation to require")
wickFactor = input.float(1.5, "Wick Factor (lower/upper wick vs body)", step=0.1)

fast_ma = sma_source_macd == "SMA" ? ta.sma(macd_src, macd_fast_length) : ta.ema(macd_src, macd_fast_length)
slow_ma = sma_source_macd == "SMA" ? ta.sma(macd_src, macd_slow_length) : ta.ema(macd_src, macd_slow_length)
macd = fast_ma - slow_ma
signal = sma_signal_macd == "SMA" ? ta.sma(macd, macd_signal_length) : ta.ema(macd, macd_signal_length)
hist = macd - signal

// Price-action helper functions
isBullishEngulfing() =>
    close > open and close[1] < open[1] and open < close[1] and close > open[1]

isBearishEngulfing() =>
    close < open and close[1] > open[1] and open > close[1] and close < open[1]

isLowerWickRejection() =>
    // bullish candle with lower wick significantly larger than body
    close > open and (math.min(open, close) - low) > (math.abs(close - open) * wickFactor)

isUpperWickRejection() =>
    // bearish candle with upper wick significantly larger than body
    close < open and (high - math.max(open, close)) > (math.abs(close - open) * wickFactor)

// ========================================
// TRADING SESSION FILTER
// ========================================
isInSession() =>
    if useTimeFilter
        sessionTime = hour * 60 + minute
        startTime = startHour * 60 + startMinute
        endTime = endHour * 60 + endMinute
        sessionTime >= startTime and sessionTime <= endTime
    else
        true

// ========================================
// DAILY TRADE TRACKING
// ========================================
var float dailyPnL = 0.0
var int dailyTradeCount = 0
var int lastTradeDay = 0
var int lastClosedTrades = 0

// Reset daily counters
currentDay = dayofmonth
if currentDay != lastTradeDay
    dailyPnL := 0.0
    dailyTradeCount := 0
    lastTradeDay := currentDay
    lastClosedTrades := strategy.closedtrades

// Check if we can trade based on daily limits
canTradeToday() =>
    if useDailyLimits
        withinProfitLimit = dailyPnL < dailyProfitTarget
        withinLossLimit = dailyPnL > -dailyLossLimit
        withinTradeLimit = dailyTradeCount < maxDailyTrades
        withinProfitLimit and withinLossLimit and withinTradeLimit
    else
        true

// ========================================
// ENTRY CONDITIONS
// ========================================
// Long Entry: Price touches lower band AND RSI oversold
// Apply MACD filter logic
// MACD confirmation logic
macdLongOk = false
macdShortOk = false
if macdConfirm == "None"
    macdLongOk := true
    macdShortOk := true
else
    macdLongOk := macdConfirm == "Histogram > 0" and hist > 0 or macdConfirm == "Histogram Rising" and hist > hist[1] or macdConfirm == "MACD > Signal" and macd > signal or macdConfirm == "MACD Cross Signal" and ta.crossover(macd, signal)
    macdShortOk := macdConfirm == "Histogram > 0" and hist < 0 or macdConfirm == "Histogram Rising" and hist < hist[1] or macdConfirm == "MACD > Signal" and macd < signal or macdConfirm == "MACD Cross Signal" and ta.crossunder(macd, signal)

// price-action confirmation
paLongOk = true
paShortOk = true
if requirePriceAction
    paLongOk := (priceActionType == "Engulfing" and isBullishEngulfing()) or (priceActionType == "Lower Wick" and isLowerWickRejection())
    paShortOk := (priceActionType == "Engulfing" and isBearishEngulfing()) or (priceActionType == "Lower Wick" and isUpperWickRejection())

// combine RSI+MACD rising requirement if enabled
macdRiseOkLong = true
macdRiseOkShort = true
if requireRSIandMACD
    macdRiseOkLong := hist > hist[1]
    macdRiseOkShort := hist < hist[1]

longCondition = close <= lowerBand and rsi < rsiOversold and isInSession() and canTradeToday() and macdLongOk and paLongOk and macdRiseOkLong

// Short Entry: Price touches upper band AND RSI overbought
shortCondition = close >= upperBand and rsi > rsiOverbought and isInSession() and canTradeToday() and macdShortOk and paShortOk and macdRiseOkShort

// ========================================
// POSITION SIZING LOGIC
// ========================================
currentPosition = strategy.position_size
canAddPosition = math.abs(currentPosition) < maxContracts

// Determine contract size for new entry
getContractSize() =>
    if math.abs(currentPosition) == 0
        initialContracts
    else if canAddPosition
        1
    else
        0

contractSize = getContractSize()

// ========================================
// EXECUTE TRADES
// ========================================
// Calculate tick-based stops and targets
tickSize = syminfo.mintick
profitDistance = profitTicks * tickSize
stopDistance = stopTicks * tickSize

// Long Trades
if longCondition and (currentPosition >= 0) and canAddPosition
    entryPrice = close
    stopPrice = entryPrice - stopDistance
    targetPrice = entryPrice + profitDistance
    
    entryID = "Long" + str.tostring(math.abs(currentPosition) + 1)
    
    strategy.entry(entryID, strategy.long, qty=contractSize)
    strategy.exit(entryID + "_Exit", entryID, limit=targetPrice, stop=stopPrice, comment="TP/SL")
    
    if math.abs(currentPosition) == 0
        dailyTradeCount += 1

// Short Trades
if shortCondition and (currentPosition <= 0) and canAddPosition
    entryPrice = close
    stopPrice = entryPrice + stopDistance
    targetPrice = entryPrice - profitDistance
    
    entryID = "Short" + str.tostring(math.abs(currentPosition) + 1)
    
    strategy.entry(entryID, strategy.short, qty=contractSize)
    strategy.exit(entryID + "_Exit", entryID, limit=targetPrice, stop=stopPrice, comment="TP/SL")
    
    if math.abs(currentPosition) == 0
        dailyTradeCount += 1

// ========================================
// TRACK P&L
// ========================================
if strategy.closedtrades > lastClosedTrades
    newClosedTrades = strategy.closedtrades - lastClosedTrades
    
    for i = 0 to newClosedTrades - 1
        tradeIndex = strategy.closedtrades - 1 - i
        tradePnL = strategy.closedtrades.profit(tradeIndex)
        tradePnLDollars = tradePnL * tickValue / tickSize
        dailyPnL += tradePnLDollars
    
    lastClosedTrades := strategy.closedtrades

// ========================================
// PLOTTING
// ========================================
// Plot Bollinger Bands
plot(basis, "MA", color=color.blue, linewidth=2)
p1 = plot(upperBand, "Upper Band", color=color.red, linewidth=1)
p2 = plot(lowerBand, "Lower Band", color=color.green, linewidth=1)
fill(p1, p2, color=color.rgb(33, 150, 243, 95))

// Plot Entry Signals
plotshape(longCondition and canAddPosition, "Long Signal", shape.triangleup, location.belowbar, color=color.green, size=size.small)
plotshape(shortCondition and canAddPosition, "Short Signal", shape.triangledown, location.abovebar, color=color.red, size=size.small)

// Background color for RSI conditions
bgcolor(rsi < rsiOversold ? color.new(color.green, 90) : na, title="Oversold")
bgcolor(rsi > rsiOverbought ? color.new(color.red, 90) : na, title="Overbought")

// === MACD PLOTTING ===
hline(0, "MACD Zero", color=color.new(color.gray, 80))
plot(hist, title = "MACD Histogram", style=plot.style_columns, color = hist >= 0 ? color.new(color.green, 0) : color.new(color.red, 0))
plot(macd, title = "MACD", color = color.blue)
plot(signal, title = "MACD Signal", color = color.orange)

// ========================================
// ALERTS
// ========================================
alertcondition(longCondition and canAddPosition, "Long Entry Signal", "Mean Reversion: Long signal triggered")
alertcondition(shortCondition and canAddPosition, "Short Entry Signal", "Mean Reversion: Short signal triggered")
alertcondition(dailyPnL >= dailyProfitTarget and useDailyLimits, "Daily Profit Target Hit", "Daily profit target reached!")
alertcondition(dailyPnL <= -dailyLossLimit and useDailyLimits, "Daily Loss Limit Hit", "Daily loss limit reached!")

Overview

Mean Reversion enters long or short positions when price reaches band extremes during oversold or overbought RSI levels, with optional MACD trend direction or price action candle filters such as wicks or engulfing patterns. Positions close via fixed tick-based profit targets and stop losses. The strategy overlays on the price chart and incorporates a time-of-day session filter, daily maximum trade limits, and daily profit or loss cutoffs.

Details

Published by

nxtaiapp on GitHub

Type

Strategy, Pine Script v5

Draws

On the price chart

Category

Mean reversion, Scalping, Oscillators & momentum, Volatility & bands

Markets

Indices

Timeframes

M1-M5, M15-H1

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
MA Lengthint21maLength
Standard Deviation Multiplierfloat2.0stdDevMultiplier
RSI Lengthint5rsiLength
RSI Oversold Levelint20rsiOversold
RSI Overbought Levelint80rsiOverbought
Profit Target (ticks)int21profitTicks
Stop Loss (ticks)int34stopTicks
Tick Value ($)float12.50tickValue
Initial Contractsint10initialContracts
Maximum Contractsint10maxContracts
Use Trading Hours FilterbooltrueuseTimeFilter
Start Hour (EST)int8startHour
Show all 30 settings
SettingTypeDefaultVariable
Start Minuteint30startMinute
End Hour (EST)int14endHour
End Minuteint0endMinute
Use Daily P&L LimitsbooltrueuseDailyLimits
Daily Profit Target ($)float999dailyProfitTarget
Daily Loss Limit ($)float500dailyLossLimit
Max Daily Tradesint2maxDailyTrades
MACD Fast Lengthint8macd_fast_length
MACD Slow Lengthint21macd_slow_length
MACD Signal Lengthint8macd_signal_length
MACD Sourcesourceclosemacd_src
MACD Oscillator MA TypestringEMAsma_source_macd
MACD Signal MA TypestringEMAsma_signal_macd
MACD ConfirmationstringNonemacdConfirm
Require RSI oversold/overbought AND MACD rising/fallingbooltruerequireRSIandMACD
Require Price Action ConfirmationboolfalserequirePriceAction
Price Action TypestringLower WickpriceActionType
Wick Factor (lower/upper wick vs body)float1.5wickFactor
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

RSI/BB 1minute Study

by SammyEnigma
18 stars

This strategy combines Relative Strength Index and Bollinger Bands for short-term signal generation. It enters long positions when the price crosses below the lower Bollinger Band while the RSI falls at or below the oversold threshold. Positions are scaled dow

Strategy v4 Oscillators & momentumVolatility & bands
Updated 6 years ago · None stated GitHub repository of RSI/BB 1minute Study
330 stars

Alert BB + RSI [Alorse] is a multi-symbol mean-reversion strategy designed for cryptocurrency trading. It evaluates Bollinger Bands and the Relative Strength Index (RSI) across up to 20 user-defined ticker symbols simultaneously. The strategy enters long posit

Strategy v4 Oscillators & momentumVolatility & bands
Updated 2 months ago · None stated GitHub repository of Alert BB + RSI [Alorse]
106 stars

A multi-timeframe Dollar Cost Averaging (DCA) trading strategy that combines signals from three RSI indicators, three CCI indicators, and Bollinger Bands. It places up to five weighted scale-in safety orders to lower the average entry price. The script offers

Strategy v5 Oscillators & momentumVolatility & bands
Updated 2 years ago · GPL-3.0 GitHub repository of 3RSI 3CCI BB 5orders DCA Strategy+
104 stars

This strategy combines Bollinger Bands with a short RSI to fade moves that leave the bands and then return. A long requires the prior bar below the lower band and oversold, then a close back inside the band while RSI is between 30 and 50. Shorts mirror that at

Strategy v5 Oscillators & momentumVolatility & bands
Updated 3 years ago · MIT GitHub repository of Bollinger Bands and RSI Strategy
27 stars

LuxAlgo Hybrid Gold Scalper is a price-chart strategy aimed at gold. It stacks a fast, slow, trend and 200-period bias EMA to mark trend direction, then filters strength with RSI, ADX and an intraday VWAP. Swing highs and lows are marked from pivot length. Set

Strategy v5 TrendOscillators & momentum
Updated 5 months ago · None stated GitHub repository of LuxAlgo Hybrid Gold Scalper
13 stars

This strategy overlays the price chart to trade DAX futures during European market hours. It calculates exponential and simple moving averages, RSI, MACD, Bollinger Bands, ATR, and realized volatility to simulate VIX levels. Trades execute when session time fi

Strategy v5 Sessions & timeOscillators & momentum
Updated 8 months ago · Custom licence GitHub repository of ClaudeHedge - DAX Session Strategy

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers