// 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.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
IB Start Hour (ET)
int
9
i_ibStartHour
IB Start Minute (ET)
int
30
i_ibStartMin
IB End Hour (ET)
int
10
i_ibEndHour
IB End Minute (ET)
int
30
i_ibEndMin
IB Avg Lookback (days)
int
20
i_ibAvgLen
Narrow IB Threshold (% of avg)
float
0.70
i_narrowPct
Wide IB Threshold (% of avg)
float
1.30
i_widePct
Skip Narrow IB Days
bool
true
i_skipNarrow
Skip Trend Day signals
bool
true
i_skipTrend
Extension Min (x IB Range)
float
0.5
i_extMin
Extension Max (x IB Range)
float
1.0
i_extMax
MA Type
string
EMA
i_maType
Show all 25 settings
Setting
Type
Default
Variable
MA Length
int
50
i_maLen
Volume Confirm Multiplier
float
1.2
i_volMult
Volume Avg Length
int
20
i_volLen
Take Profit Target
string
IB Midpoint
i_tpTarget
Stop Loss (x IB Range)
float
0.5
i_slMult
EOD Exit Hour (ET)
int
15
i_eodHour
EOD Exit Minute (ET)
int
45
i_eodMin
Max Daily Loss ($)
float
500.0
i_maxDailyLoss
Show IB Box
bool
true
i_showBox
Show Extension Lines
bool
true
i_showExtLines
Show Dashboard
bool
true
i_showDash
IB Box Color
color
color.new(color.blue, 80)
i_ibBoxColor
Extension Line Color
color
color.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.
This strategy plots on the price chart and calculates an initial balance (IB) range from specified IB start to end hours in ET. It computes VWAP using cumulative typical price and volume during the regular trading hours. Confluence is detected when price align
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,
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
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
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
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