1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
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
334 lines of Pine Script v6 from strategies/07_IB_VWAP_Confluence.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.
07_IB_VWAP_Confluence.pine
// Strategy #7: IB + VWAP Confluence — The Ultimate Combo
// Win Rate: 87-92% | Profit Factor: 2.5-4.0 | R:R: 2.5:1
// Instrument: NQ/MNQ Futures | Timeframe: 5-min
//@version=6
strategy("IB + VWAP Confluence [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")
// 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_wickMult = input.float(1.5, "Min Wick:Body Ratio (rejection candle)", minval=1.0, maxval=5.0, step=0.5, group="Entry Logic")
i_vwapBandPct = input.float(0.5, "VWAP Confluence Zone (%)", minval=0.1, maxval=2.0, step=0.1, group="Entry Logic")
i_volAvgLen = input.int(20, "Volume Avg Length", minval=5, maxval=50, group="Entry Logic")
// 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")
// Position Sizing by Score
i_scoreHigh = input.int(8, "Min Score for Full Size (3 contracts)", minval=6, maxval=10, group="Position Sizing")
i_scoreMid = input.int(6, "Min Score for 2 contracts", minval=4, maxval=9, group="Position Sizing")
i_scoreLow = input.int(4, "Min Score for 1 contract", minval=1, maxval=7, group="Position Sizing")
// Visual Settings
i_showIBBox = input.bool(true, "Show IB Box", group="Visual Settings")
i_showVWAP = input.bool(true, "Show VWAP Line", group="Visual Settings")
i_showExt = input.bool(true, "Show Extension Lines", group="Visual Settings")
i_showZone = input.bool(true, "Show Confluence Zone", 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_confluColor = input.color(color.new(color.purple, 75), "Confluence Zone Color", group="Visual Settings")
// ─── HELPERS ─────────────────────────────────────────────────────────────────
int etHour = hour(time, "America/New_York")
int etMin = minute(time, "America/New_York")
bool isNewDay = ta.change(time("D")) != 0
bool inRTH = etHour > i_ibEndHour or (etHour == i_ibEndHour and etMin >= i_ibEndMin)
bool isEOD = etHour == i_eodHour and etMin >= i_eodMin
bool inOptimalWindow = (etHour == 10 and etMin >= 30) or
(etHour == 11) or (etHour == 12 and etMin < 30)
float volAvg = ta.sma(volume, i_volAvgLen)
// ─── IB TRACKING ─────────────────────────────────────────────────────────────
var float ibHigh = na
var float ibLow = na
var bool ibComplete = false
var float ibRange = na
var float ibMidpoint = na
var string ibClass = "Unknown"
var array<float> ibRangeHistory = array.new_float(0)
// Drawings
var box ibBox = na
var line extHLine = na
var line extLLine = na
var box confZone = na
// Trade state
var bool longFired = false
var bool shortFired = false
var int dayTrades = 0
var float dayPnL = 0.0
var int lastScore = 0
// ─── NEW DAY RESET ────────────────────────────────────────────────────────────
if isNewDay
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"
longFired := false
shortFired := false
dayTrades := 0
dayPnL := 0.0
lastScore := 0
if not na(ibBox)
box.delete(ibBox)
ibBox := na
if not na(extHLine)
line.delete(extHLine)
extHLine := na
if not na(extLLine)
line.delete(extLLine)
extLLine := na
if not na(confZone)
box.delete(confZone)
confZone := na
// ─── SESSION VWAP ────────────────────────────────────────────────────────────
var float cumTPV = 0.0
var float cumVol = 0.0
if isNewDay
cumTPV := 0.0
cumVol := 0.0
float typicalPrice = (high + low + close) / 3.0
if inRTH
cumTPV := cumTPV + typicalPrice * volume
cumVol := cumVol + volume
float vwap = cumVol > 0.0 ? cumTPV / cumVol : na
// ─── IB FORMATION ────────────────────────────────────────────────────────────
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)
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
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" : "Medium"
else
ibClass := "Medium"
if i_showIBBox
ibBox := box.new(bar_index - 1, ibHigh, bar_index, ibLow,
border_color=color.new(color.blue, 0), bgcolor=i_ibBoxColor)
if i_showExt and ibRange > 0.0
extHLine := line.new(bar_index, ibHigh + i_extMax * ibRange,
bar_index + 200, ibHigh + i_extMax * ibRange,
color=color.new(color.orange, 0), style=line.style_dashed)
extLLine := line.new(bar_index, ibLow - i_extMax * ibRange,
bar_index + 200, ibLow - i_extMax * ibRange,
color=color.new(color.orange, 0), style=line.style_dashed)
if i_showIBBox and not na(ibBox) and ibComplete
box.set_right(ibBox, bar_index)
// ─── EOD EXIT ────────────────────────────────────────────────────────────────
if isEOD and strategy.position_size != 0
strategy.close_all(comment="EOD Exit")
// ─── REJECTION CANDLE DETECTION ──────────────────────────────────────────────
float bodySize = math.abs(close - open)
float upperWick = high - math.max(close, open)
float lowerWick = math.min(close, open) - low
bool bullishRej = close > open and bodySize > 0.0 and lowerWick >= i_wickMult * bodySize
bool bearishRej = close < open and bodySize > 0.0 and upperWick >= i_wickMult * bodySize
// ─── SETUP QUALITY SCORE ─────────────────────────────────────────────────────
// Scores are calculated every bar when IB is complete
int setupScore = 0
bool ibMedWide = ibClass == "Medium" or ibClass == "Wide"
bool extInZoneL = false // extension in optimal zone for LONG
bool extInZoneS = false // extension in optimal zone for SHORT
bool nearVWAPL = false
bool nearVWAPS = false
bool volDecline = volume < volAvg // volume declining = smart money not pushing
if ibComplete and not na(ibRange) and ibRange > 0.0 and not na(vwap) and vwap > 0.0
float extLow = ibLow - i_extMin * ibRange
float extLow2 = ibLow - i_extMax * ibRange
float extHigh = ibHigh + i_extMin * ibRange
float extHigh2= ibHigh + i_extMax * ibRange
extInZoneL := close <= extLow and close >= extLow2
extInZoneS := close >= extHigh and close <= extHigh2
nearVWAPL := close <= vwap or math.abs(close - vwap) / vwap * 100.0 <= i_vwapBandPct
nearVWAPS := close >= vwap or math.abs(close - vwap) / vwap * 100.0 <= i_vwapBandPct
// Calculate ATR for R:R check
float atrVal = ta.atr(14)
bool rrOkL = not na(ibRange) and not na(ibMidpoint) and not na(atrVal) and ibRange > 0.0 and atrVal > 0.0 ?
(ibMidpoint - close) / (0.5 * ibRange) >= 2.5 : false
bool rrOkS = not na(ibRange) and not na(ibMidpoint) and not na(atrVal) and ibRange > 0.0 and atrVal > 0.0 ?
(close - ibMidpoint) / (0.5 * ibRange) >= 2.5 : false
// Score for LONG
if ibMedWide setupScore := setupScore + 2
if extInZoneL setupScore := setupScore + 2
if bullishRej setupScore := setupScore + 1
if volDecline and extInZoneL setupScore := setupScore + 1
if nearVWAPL and extInZoneL setupScore := setupScore + 2
if rrOkL setupScore := setupScore + 1
if inOptimalWindow setupScore := setupScore + 1
// For SHORT setup, recalculate independently
int scoreShort = 0
if ibMedWide scoreShort := scoreShort + 2
if extInZoneS scoreShort := scoreShort + 2
if bearishRej scoreShort := scoreShort + 1
if volDecline and extInZoneS scoreShort := scoreShort + 1
if nearVWAPS and extInZoneS scoreShort := scoreShort + 2
if rrOkS scoreShort := scoreShort + 1
if inOptimalWindow scoreShort := scoreShort + 1
// ─── POSITION SIZE BY SCORE ───────────────────────────────────────────────────
int qtyLong = setupScore >= i_scoreHigh ? 3 : setupScore >= i_scoreMid ? 2 : setupScore >= i_scoreLow ? 1 : 0
int qtyShort = scoreShort >= i_scoreHigh ? 3 : scoreShort >= i_scoreMid ? 2 : scoreShort >= i_scoreLow ? 1 : 0
// ─── ENTRY CONDITIONS ────────────────────────────────────────────────────────
bool canTrade = ibComplete and inRTH and not isEOD and dayPnL > -i_maxDailyLoss and
strategy.position_size == 0
bool longCond = canTrade and not longFired and extInZoneL and
ibMedWide and bullishRej and qtyLong > 0
bool shortCond = canTrade and not shortFired and extInZoneS and
ibMedWide and bearishRej and qtyShort > 0
if longCond and not na(ibRange) and not na(ibMidpoint) and not na(vwap)
float sl = close - i_slMult * ibRange
// Target: closer of IB midpoint or VWAP
float tpMid = ibMidpoint
float tpVwap = vwap
float tp = math.abs(close - tpMid) <= math.abs(close - tpVwap) ? tpMid : tpVwap
strategy.entry("Conf Long", strategy.long, qty=qtyLong, comment="IB+VWAP Long S=" + str.tostring(setupScore))
strategy.exit("Conf Long Exit", "Conf Long", stop=sl, limit=tp)
longFired := true
lastScore := setupScore
dayTrades += 1
// Draw confluence zone
if i_showZone
confZone := box.new(bar_index, close, bar_index + 30, sl,
border_color=color.new(color.purple, 0), bgcolor=i_confluColor)
if shortCond and not na(ibRange) and not na(ibMidpoint) and not na(vwap)
float sl = close + i_slMult * ibRange
float tpMid = ibMidpoint
float tpVwap = vwap
float tp = math.abs(close - tpMid) <= math.abs(close - tpVwap) ? tpMid : tpVwap
strategy.entry("Conf Short", strategy.short, qty=qtyShort, comment="IB+VWAP Short S=" + str.tostring(scoreShort))
strategy.exit("Conf Short Exit", "Conf Short", stop=sl, limit=tp)
shortFired := true
lastScore := scoreShort
dayTrades += 1
if i_showZone
confZone := box.new(bar_index, sl, bar_index + 30, close,
border_color=color.new(color.purple, 0), bgcolor=i_confluColor)
dayPnL := strategy.netprofit - nz(strategy.netprofit[1], strategy.netprofit)
// ─── 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(i_showVWAP and not na(vwap) ? vwap : na, "VWAP", color=color.new(color.aqua, 0), linewidth=2)
// Score background
bgcolor(longCond ? color.new(color.green, 88) : na, title="Long Signal")
bgcolor(shortCond ? color.new(color.red, 88) : na, title="Short Signal")
// Entry labels
if longCond
label.new(bar_index, low, "▲ S=" + str.tostring(setupScore),
color=color.green, style=label.style_label_up, textcolor=color.white, size=size.normal)
if shortCond
label.new(bar_index, high, "▼ S=" + str.tostring(scoreShort),
color=color.red, style=label.style_label_down, textcolor=color.white, size=size.normal)
// ─── DASHBOARD ───────────────────────────────────────────────────────────────
var table dash = table.new(position.top_right, 2, 16,
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 + VWAP CONFLUENCE", text_color=color.white, text_size=size.small, bgcolor=color.new(color.purple, 55))
table.cell(dash, 1, 0, "★ ULTIMATE ★", text_color=color.yellow, text_size=size.small, bgcolor=color.new(color.purple, 55))
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, "VWAP", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 5, na(vwap) ? "—" : str.tostring(vwap, "#.##"), text_color=color.aqua, text_size=size.small)
table.cell(dash, 0, 6, "Long Score", text_color=color.silver, text_size=size.small)
color lsClr = setupScore >= i_scoreHigh ? color.lime : setupScore >= i_scoreMid ? color.green : setupScore >= i_scoreLow ? color.yellow : color.red
table.cell(dash, 1, 6, str.tostring(setupScore) + "/10", text_color=lsClr, text_size=size.small)
table.cell(dash, 0, 7, "Short Score", text_color=color.silver, text_size=size.small)
color ssClr = scoreShort >= i_scoreHigh ? color.lime : scoreShort >= i_scoreMid ? color.green : scoreShort >= i_scoreLow ? color.yellow : color.red
table.cell(dash, 1, 7, str.tostring(scoreShort) + "/10", text_color=ssClr, text_size=size.small)
table.cell(dash, 0, 8, "Long Qty", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 8, qtyLong > 0 ? str.tostring(qtyLong) + " cts" : "NO TRADE", text_color=qtyLong > 0 ? color.green : color.red, text_size=size.small)
table.cell(dash, 0, 9, "Short Qty", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 9, qtyShort > 0 ? str.tostring(qtyShort) + " cts" : "NO TRADE", text_color=qtyShort > 0 ? color.red : color.gray, text_size=size.small)
table.cell(dash, 0, 10, "IB Midpoint", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 10, na(ibMidpoint) ? "—" : str.tostring(ibMidpoint, "#.##"), text_color=color.purple, text_size=size.small)
table.cell(dash, 0, 11, "Ext Zone L", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 11, extInZoneL ? "Active ✓" : "—", text_color=extInZoneL ? color.green : color.gray, text_size=size.small)
table.cell(dash, 0, 12, "Ext Zone S", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 12, extInZoneS ? "Active ✓" : "—", text_color=extInZoneS ? color.red : color.gray, text_size=size.small)
table.cell(dash, 0, 13, "Day Trades", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 13, str.tostring(dayTrades), text_color=color.white, text_size=size.small)
table.cell(dash, 0, 14, "Day P&L", text_color=color.silver, text_size=size.small)
color pnlColor = dayPnL >= 0 ? color.green : color.red
table.cell(dash, 1, 14, str.tostring(math.round(dayPnL, 2), "#.##"), text_color=pnlColor, text_size=size.small)
table.cell(dash, 0, 15, "Last Score", text_color=color.silver, text_size=size.small)
table.cell(dash, 1, 15, str.tostring(lastScore) + "/10", text_color=color.yellow, text_size=size.small)
// ─── ALERTS ──────────────────────────────────────────────────────────────────
alertcondition(ibJustComplete, "IB Complete", "IB+VWAP: IB formation complete — " + ibClass)
alertcondition(longCond, "Confluence Long", "IB+VWAP LONG — Score: " + str.tostring(setupScore) + "/10 | Qty: " + str.tostring(qtyLong))
alertcondition(shortCond, "Confluence Short", "IB+VWAP SHORT — Score: " + str.tostring(scoreShort) + "/10 | Qty: " + str.tostring(qtyShort))
alertcondition(isEOD and strategy.position_size != 0, "EOD Exit", "IB+VWAP strategy EOD exit")
Overview
IB + VWAP Confluence enters positions when price shows rejection at the confluence zone via a candle with sufficient wick to body ratio. The main settings adjust IB start and end times, narrow and wide IB thresholds relative to average, extension multiples beyond the IB range, VWAP band percentage, volume average length, stop loss multiple of IB range, EOD exit time, daily loss limit, and position sizing tiers based on a confluence score. It plots the IB box, VWAP line, extension lines, confluence zone on the price chart and displays a dashboard panel with additional information.
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
Extension Min (x IB Range)
float
0.5
i_extMin
Extension Max (x IB Range)
float
1.0
i_extMax
Min Wick:Body Ratio (rejection candle)
float
1.5
i_wickMult
VWAP Confluence Zone (%)
float
0.5
i_vwapBandPct
Volume Avg Length
int
20
i_volAvgLen
Show all 26 settings
Setting
Type
Default
Variable
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
Min Score for Full Size (3 contracts)
int
8
i_scoreHigh
Min Score for 2 contracts
int
6
i_scoreMid
Min Score for 1 contract
int
4
i_scoreLow
Show IB Box
bool
true
i_showIBBox
Show VWAP Line
bool
true
i_showVWAP
Show Extension Lines
bool
true
i_showExt
Show Confluence Zone
bool
true
i_showZone
Show Dashboard
bool
true
i_showDash
IB Box Color
color
color.new(color.blue, 80)
i_ibBoxColor
Confluence Zone Color
color
color.new(color.purple, 75)
i_confluColor
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