Strategy · Pine Script v6 · On the chart

IB Mean Reversion Fade

by Prat617

This strategy identifies Initial Balance periods on NQ and ES futures charts using user-defined start and end hours in Eastern Time.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code244
Settings25inputs
LicenceMIT
Last update7 months ago6 Mar 2026

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

244 lines of Pine Script v6 from strategies/01_IB_Mean_Reversion_Fade.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

01_IB_Mean_Reversion_Fade.pine
// Strategy #1: IB Mean Reversion Fade
// Win Rate: 85-90% | Profit Factor: 2.0-3.0 | R:R: 2:1
// Instrument: NQ/MNQ/ES Futures | Timeframe: 5-min (entries), uses 60-min IB
//@version=6
strategy("IB Mean Reversion Fade [v6]", overlay=true, calc_on_every_tick=false,
     process_orders_on_close=false, max_bars_back=5000,
     initial_capital=100000, commission_type=strategy.commission.cash_per_contract,
     commission_value=2.50, slippage=1)

// ─── INPUTS ──────────────────────────────────────────────────────────────────
// IB Settings
i_ibStartHour   = input.int(9,  "IB Start Hour (ET)",  minval=0, maxval=23, group="IB Settings")
i_ibStartMin    = input.int(30, "IB Start Minute (ET)", minval=0, maxval=59, group="IB Settings")
i_ibEndHour     = input.int(10, "IB End Hour (ET)",    minval=0, maxval=23, group="IB Settings")
i_ibEndMin      = input.int(30, "IB End Minute (ET)",  minval=0, maxval=59, group="IB Settings")
i_ibAvgLen      = input.int(20, "IB Avg Lookback (days)", minval=5, maxval=50, group="IB Settings")
i_narrowPct     = input.float(0.70, "Narrow IB Threshold (% of avg)", minval=0.3, maxval=1.0, step=0.05, group="IB Settings")
i_widePct       = input.float(1.30, "Wide IB Threshold (% of avg)",   minval=1.0, maxval=3.0, step=0.05, group="IB Settings")

// Day-Type Filters
i_skipNarrow    = input.bool(true, "Skip Narrow IB Days", group="Day-Type Filters")
i_skipTrend     = input.bool(true, "Skip Trend Day signals", group="Day-Type Filters")

// Entry Logic
i_extMin        = input.float(0.5, "Extension Min (x IB Range)",  minval=0.1, maxval=2.0, step=0.1, group="Entry Logic")
i_extMax        = input.float(1.0, "Extension Max (x IB Range)",  minval=0.1, maxval=3.0, step=0.1, group="Entry Logic")
i_maType        = input.string("EMA", "MA Type", options=["EMA","SMA","VWMA"], group="Entry Logic")
i_maLen         = input.int(50, "MA Length", minval=5, maxval=200, group="Entry Logic")
i_volMult       = input.float(1.2, "Volume Confirm Multiplier", minval=1.0, maxval=3.0, step=0.1, group="Entry Logic")
i_volLen        = input.int(20, "Volume Avg Length", minval=5, maxval=50, group="Entry Logic")

// Exit / Risk Management
i_tpTarget      = input.string("IB Midpoint", "Take Profit Target", options=["IB Midpoint","IB Opposite"], group="Exit/Risk Management")
i_slMult        = input.float(0.5, "Stop Loss (x IB Range)", minval=0.1, maxval=2.0, step=0.1, group="Exit/Risk Management")
i_eodHour       = input.int(15, "EOD Exit Hour (ET)",   minval=12, maxval=22, group="Exit/Risk Management")
i_eodMin        = input.int(45, "EOD Exit Minute (ET)", minval=0,  maxval=59, group="Exit/Risk Management")
i_maxDailyLoss  = input.float(500.0, "Max Daily Loss ($)", minval=0, group="Exit/Risk Management")

// Visual Settings
i_showBox       = input.bool(true,  "Show IB Box",       group="Visual Settings")
i_showExtLines  = input.bool(true,  "Show Extension Lines", group="Visual Settings")
i_showDash      = input.bool(true,  "Show Dashboard",    group="Visual Settings")
i_ibBoxColor    = input.color(color.new(color.blue,  80), "IB Box Color",       group="Visual Settings")
i_extLineColor  = input.color(color.new(color.orange, 0), "Extension Line Color", group="Visual Settings")

// ─── MA CALCULATION ───────────────────────────────────────────────────────────
float maValue = switch i_maType
    "SMA"  => ta.sma(close, i_maLen)
    "VWMA" => ta.vwma(close, i_maLen)
    =>         ta.ema(close, i_maLen)

float volAvg = ta.sma(volume, i_volLen)

// ─── TIMEZONE HELPERS ─────────────────────────────────────────────────────────
int   etHour  = hour(time, "America/New_York")
int   etMin   = minute(time, "America/New_York")
bool  isNewDay = ta.change(time("D")) != 0

// ─── IB TRACKING (var = persistent) ──────────────────────────────────────────
var float ibHigh      = na
var float ibLow       = na
var bool  ibComplete  = false
var float ibRange     = na
var float ibMidpoint  = na
var string ibClass    = "Unknown"

// IB range history array (stores one value per completed day)
var array<float> ibRangeHistory = array.new_float(0)

// Drawing handles
var box   ibBox       = na
var line  extHighLine = na
var line  extLowLine  = na

// Trade tracking
var int   dayTrades   = 0
var float dayPnL      = 0.0
var bool  longFired   = false
var bool  shortFired  = false

// ─── NEW DAY RESET ────────────────────────────────────────────────────────────
if isNewDay
    // Save completed IB range to history
    if not na(ibRange) and ibRange > 0.0
        array.push(ibRangeHistory, ibRange)
        if array.size(ibRangeHistory) > i_ibAvgLen
            array.shift(ibRangeHistory)
    ibHigh     := na
    ibLow      := na
    ibComplete := false
    ibRange    := na
    ibMidpoint := na
    ibClass    := "Unknown"
    dayTrades  := 0
    dayPnL     := 0.0
    longFired  := false
    shortFired := false
    // Delete old drawings
    if not na(ibBox)
        box.delete(ibBox)
        ibBox := na
    if not na(extHighLine)
        line.delete(extHighLine)
        extHighLine := na
    if not na(extLowLine)
        line.delete(extLowLine)
        extLowLine := na

// ─── IB FORMATION (9:30–10:30 ET) ────────────────────────────────────────────
bool inIBWindow = (etHour == i_ibStartHour and etMin >= i_ibStartMin) or
     (etHour > i_ibStartHour and etHour < i_ibEndHour) or
     (etHour == i_ibEndHour and etMin < i_ibEndMin)

if inIBWindow and not ibComplete
    ibHigh := na(ibHigh) ? high : math.max(ibHigh, high)
    ibLow  := na(ibLow)  ? low  : math.min(ibLow,  low)

// Detect IB completion (first bar after IB window)
bool ibJustComplete = not ibComplete and
     (etHour > i_ibEndHour or (etHour == i_ibEndHour and etMin >= i_ibEndMin)) and
     not na(ibHigh) and not na(ibLow)

if ibJustComplete
    ibComplete := true
    ibRange    := ibHigh - ibLow
    ibMidpoint := (ibHigh + ibLow) / 2.0
    // Classify IB
    float avgRange = array.size(ibRangeHistory) > 0 ? array.avg(ibRangeHistory) : na
    if not na(avgRange) and avgRange > 0.0
        float pct = ibRange / avgRange
        ibClass := pct < i_narrowPct ? "Narrow" : pct > i_widePct ? "Wide" : "Normal"
    else
        ibClass := "Normal"
    // Draw IB box
    if i_showBox
        ibBox := box.new(bar_index - 1, ibHigh, bar_index, ibLow,
             border_color=color.new(color.blue, 0), bgcolor=i_ibBoxColor)
    // Draw extension lines
    if i_showExtLines and ibRange > 0.0
        float extH = ibHigh + i_extMax * ibRange
        float extL = ibLow  - i_extMax * ibRange
        extHighLine := line.new(bar_index, extH, bar_index + 100, extH,
             color=i_extLineColor, style=line.style_dashed, width=1)
        extLowLine  := line.new(bar_index, extL, bar_index + 100, extL,
             color=i_extLineColor, style=line.style_dashed, width=1)

// Extend IB box right edge each bar
if i_showBox and not na(ibBox) and ibComplete
    box.set_right(ibBox, bar_index)

// ─── SESSION FILTER ───────────────────────────────────────────────────────────
bool inRTH    = (etHour > i_ibEndHour or (etHour == i_ibEndHour and etMin >= i_ibEndMin)) and
     (etHour < i_eodHour or (etHour == i_eodHour and etMin < i_eodMin))
bool isEOD    = etHour == i_eodHour and etMin >= i_eodMin

// ─── EOD EXIT ─────────────────────────────────────────────────────────────────
if isEOD and strategy.position_size != 0
    strategy.close_all(comment="EOD Exit")

// ─── ENTRY LOGIC ─────────────────────────────────────────────────────────────
bool skipDay = (i_skipNarrow and ibClass == "Narrow") or
               (i_skipTrend  and ibClass == "Wide")

if ibComplete and inRTH and not skipDay and not na(ibRange) and ibRange > 0.0
    float extHigh = ibHigh + i_extMin * ibRange
    float extLow  = ibLow  - i_extMin * ibRange

    // Volume confirmation
    bool volOk = volume > (i_volMult * volAvg)

    // LONG: price extended below IB, now crossing back through ibLow
    bool longCond = close[1] < extLow and close > extLow and
                    close > maValue and volOk and not longFired and
                    dayPnL > -i_maxDailyLoss

    // SHORT: price extended above IB, now crossing back through ibHigh
    bool shortCond = close[1] > extHigh and close < extHigh and
                     close < maValue and volOk and not shortFired and
                     dayPnL > -i_maxDailyLoss

    float sl = i_slMult * ibRange
    float tp = na(ibMidpoint) ? na : math.abs(close - ibMidpoint)

    if longCond and not na(ibMidpoint)
        float stopPrice   = close - sl
        float targetPrice = i_tpTarget == "IB Midpoint" ? ibMidpoint : ibHigh
        strategy.entry("IB Long", strategy.long)
        strategy.exit("IB Long Exit", "IB Long",
             stop=stopPrice, limit=targetPrice, comment="IB Long TP/SL")
        longFired  := true
        dayTrades  += 1

    if shortCond and not na(ibMidpoint)
        float stopPrice   = close + sl
        float targetPrice = i_tpTarget == "IB Midpoint" ? ibMidpoint : ibLow
        strategy.entry("IB Short", strategy.short)
        strategy.exit("IB Short Exit", "IB Short",
             stop=stopPrice, limit=targetPrice, comment="IB Short TP/SL")
        shortFired := true
        dayTrades  += 1

// ─── TRACK DAILY P&L ─────────────────────────────────────────────────────────
dayPnL := strategy.netprofit - nz(strategy.netprofit[1], strategy.netprofit)

// ─── DASHBOARD ────────────────────────────────────────────────────────────────
var table dash = table.new(position.top_right, 2, 10,
     border_color=color.gray, border_width=1,
     bgcolor=color.new(color.black, 85))

if i_showDash and barstate.islast
    table.cell(dash, 0, 0, "IB MEAN REVERSION", text_color=color.white, text_size=size.small, bgcolor=color.new(color.blue, 60))
    table.cell(dash, 1, 0, "", bgcolor=color.new(color.blue, 60))
    table.cell(dash, 0, 1, "IB High",   text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 1, na(ibHigh) ? "—" : str.tostring(ibHigh, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 0, 2, "IB Low",    text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 2, na(ibLow) ? "—" : str.tostring(ibLow, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 0, 3, "IB Range",  text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 3, na(ibRange) ? "—" : str.tostring(ibRange, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 0, 4, "IB Class",  text_color=color.silver, text_size=size.small)
    color classColor = ibClass == "Narrow" ? color.red : ibClass == "Wide" ? color.orange : color.green
    table.cell(dash, 1, 4, ibClass, text_color=classColor, text_size=size.small)
    table.cell(dash, 0, 5, "IB Status", text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 5, ibComplete ? "Complete" : "Forming", text_color=ibComplete ? color.green : color.yellow, text_size=size.small)
    table.cell(dash, 0, 6, "Day Trades", text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 6, str.tostring(dayTrades), text_color=color.white, text_size=size.small)
    table.cell(dash, 0, 7, "Day P&L",   text_color=color.silver, text_size=size.small)
    color pnlColor = dayPnL >= 0 ? color.green : color.red
    table.cell(dash, 1, 7, str.tostring(math.round(dayPnL, 2), "#.##"), text_color=pnlColor, text_size=size.small)
    table.cell(dash, 0, 8, "MA Filter",  text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 8, na(maValue) ? "—" : str.tostring(maValue, "#.##"), text_color=color.white, text_size=size.small)
    table.cell(dash, 0, 9, "Skip Day",   text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 9, skipDay ? "YES" : "No", text_color=skipDay ? color.red : color.green, text_size=size.small)

// ─── PLOTS ────────────────────────────────────────────────────────────────────
plot(ibComplete and not na(ibHigh) ? ibHigh : na,      "IB High",     color=color.new(color.blue, 0),   linewidth=2, style=plot.style_linebr)
plot(ibComplete and not na(ibLow)  ? ibLow  : na,      "IB Low",      color=color.new(color.blue, 0),   linewidth=2, style=plot.style_linebr)
plot(ibComplete and not na(ibMidpoint) ? ibMidpoint : na, "IB Mid",   color=color.new(color.purple, 0), linewidth=1, style=plot.style_linebr)
plot(maValue, "MA Filter", color=color.new(color.yellow, 0), linewidth=1)

// ─── ALERTS ───────────────────────────────────────────────────────────────────
alertcondition(ibJustComplete,                         "IB Complete",   "IB formation complete. IB High: {{plot_0}} IB Low: {{plot_1}}")
alertcondition(strategy.position_size > 0 and strategy.position_size[1] <= 0, "IB Long Entry",  "IB Mean Reversion LONG entry fired")
alertcondition(strategy.position_size < 0 and strategy.position_size[1] >= 0, "IB Short Entry", "IB Mean Reversion SHORT entry fired")
alertcondition(isEOD and strategy.position_size != 0,  "EOD Exit",      "EOD exit triggered — flattening position")

Overview

IB Mean Reversion Fade classifies days as narrow or wide based on average range lookback and skips narrow or trending days per settings. Entries trigger on extension beyond the Initial Balance range with volume confirmation and a moving average filter. Positions exit at a stop loss multiple of the IB range, take profit target at the IB midpoint or opposite side, or at end of day. A daily loss limit closes open positions. The strategy plots an IB box, extension lines, and a dashboard on the price chart.

Details

Published by

Prat617 on GitHub

Draws

On the price chart

Markets

Indices

Timeframes

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
IB Start Hour (ET)int9i_ibStartHour
IB Start Minute (ET)int30i_ibStartMin
IB End Hour (ET)int10i_ibEndHour
IB End Minute (ET)int30i_ibEndMin
IB Avg Lookback (days)int20i_ibAvgLen
Narrow IB Threshold (% of avg)float0.70i_narrowPct
Wide IB Threshold (% of avg)float1.30i_widePct
Skip Narrow IB Daysbooltruei_skipNarrow
Skip Trend Day signalsbooltruei_skipTrend
Extension Min (x IB Range)float0.5i_extMin
Extension Max (x IB Range)float1.0i_extMax
MA TypestringEMAi_maType
Show all 25 settings
SettingTypeDefaultVariable
MA Lengthint50i_maLen
Volume Confirm Multiplierfloat1.2i_volMult
Volume Avg Lengthint20i_volLen
Take Profit TargetstringIB Midpointi_tpTarget
Stop Loss (x IB Range)float0.5i_slMult
EOD Exit Hour (ET)int15i_eodHour
EOD Exit Minute (ET)int45i_eodMin
Max Daily Loss ($)float500.0i_maxDailyLoss
Show IB Boxbooltruei_showBox
Show Extension Linesbooltruei_showExtLines
Show Dashboardbooltruei_showDash
IB Box Colorcolorcolor.new(color.blue, 80)i_ibBoxColor
Extension Line Colorcolorcolor.new(color.orange, 0)i_extLineColor
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

3C QFL Mean Reversal

by hasnocool
106 stars

3C QFL Mean Reversal is a strategy based on the Quickfinger Luc (QFL) trading methodology. It identifies breakdown buying opportunities below established price base levels and enters mean-reversion trades. The strategy includes multi-safety order DCA scaling,

Strategy v5 Mean reversionSupport & resistance Repaints
Updated 2 years ago · GPL-3.0 GitHub repository of 3C QFL Mean Reversal

Wyckoff Phase

by muammeryldrm42
7 stars

This strategy identifies Wyckoff consolidation ranges directly on the price chart to trade potential spring and upthrust events. It calculates highest highs and lowest lows over a customizable lookback period, filtering setups by average volume spikes and ATR

Strategy v5 SMC / ICT / price actionSupport & resistance
Updated 3 months ago · MIT GitHub repository of Wyckoff Phase
5 stars

This strategy enters one long trade when the bar low comes within a set point tolerance of the prior day's low and the close finishes above that level. Entries are allowed only inside a UTC session and are blocked after a Friday cutoff hour. It stays flat unti

Strategy v5 Support & resistanceMean reversion Repaints
Updated 5 months ago · MIT GitHub repository of PDL — Prior Day Level Retest (Bull)
4 stars

This strategy draws on the price chart and identifies mean-reversion opportunities around daily volume-weighted average price (VWAP) bands. It enters long positions when the price crosses above the lower band while the Relative Strength Index indicates oversol

Strategy v6 Mean reversionSessions & time
Updated 2 months ago · MIT GitHub repository of NQ VWAP Reversion [trugurpala]

Gap Filling Strategy

by regalouisei
2 stars

This strategy detects daily opening gaps and trades them on the price chart. It marks an up or down gap from the current open and close versus the previous bar, then stores the prior extreme as the fill level. By default it buys down gaps and shorts up gaps, e

Strategy v4 Mean reversionSessions & time Repaints
Updated 8 months ago · None stated GitHub repository of Gap Filling Strategy

More Mean reversion scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

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

Compare brokers