Re: Pro level forex strategy: scalping breakout levels
Posted: Mon Oct 26, 2026 9:15 pm
Complete Pine Script v5 Code
Copy and paste the script below directly into the Pine Editor in TradingView and click Add to chart on an M1 timeframe.
Copy and paste the script below directly into the Pine Editor in TradingView and click Add to chart on an M1 timeframe.
Code: Select all
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Institutional Breakout Scalper [M15/M5/M1]
//@version=5
indicator("Institutional Breakout Scalper [M15/M5/M1]", shorttitle="IBS [M1/M5]", overlay=true, max_lines_count=500, max_boxes_count=200, max_labels_count=200)
// ============================================================================
// 1. USER INPUTS & STRATEGY PARAMETERS
// ============================================================================
grp_sess = "1. Session Windows & Liquidity Ranges (UTC)"
asianSess = input.session("0000-0630", "Asian Range (Liquidity Pool)", group=grp_sess)
preNySess = input.session("1030-1215", "Pre-NY Consolidation Range", group=grp_sess)
lonExecSess = input.session("0700-1000", "London Execution Window", group=grp_sess)
nyExecSess = input.session("1230-1530", "NY Open Execution Window", group=grp_sess)
useSessionGate = input.bool(true, "Restrict Signals to Execution Windows", group=grp_sess)
usePreNyRange = input.bool(true, "Trade Pre-NY Range Breakouts", group=grp_sess)
usePdhPdl = input.bool(true, "Trade Previous Day High/Low (PDH/PDL)", group=grp_sess)
grp_mtf = "2. M5 Compression & Trend Filters (Non-Repainting)"
m5EmaLen = input.int(20, "M5 EMA Length", minval=5, group=grp_mtf)
m5AtrLen = input.int(14, "M5 ATR Length", minval=5, group=grp_mtf)
minM5AtrPips = input.float(3.5, "Minimum M5 ATR Threshold (Pips)", minval=0.5, step=0.5, group=grp_mtf, tooltip="Use 3.5 for EURUSD, 4.5 for GBPUSD/USDJPY.")
requireM5Filter = input.bool(true, "Enforce M5 EMA & ATR Alignment", group=grp_mtf)
grp_disp = "3. M1 Displacement Candle Rules"
minBodyPct = input.float(65.0, "Min Body-to-Range Ratio (%)", minval=30.0, maxval=95.0, step=5.0, group=grp_disp)
minClearancePct = input.float(50.0, "Min Body Clearance Beyond Level (%)", minval=10.0, maxval=90.0, step=5.0, group=grp_disp)
volSmaLen = input.int(20, "Tick Volume SMA Length", minval=5, group=grp_disp)
minVolMult = input.float(1.5, "Min Volume Expansion Multiplier", minval=1.0, step=0.1, group=grp_disp)
m1AtrLen = input.int(14, "M1 ATR Length", minval=5, group=grp_disp)
minM1AtrMult = input.float(1.2, "Min Candle Length (x M1 ATR)", minval=0.5, step=0.1, group=grp_disp)
maxM1AtrMult = input.float(2.5, "Anti-Exhaustion Cap (x M1 ATR)", minval=1.5, step=0.1, group=grp_disp)
grp_risk = "4. Execution, Risk & Position Sizing"
acctBalance = input.float(50000.0, "Account Balance ($)", minval=100.0, step=1000.0, group=grp_risk)
riskPct = input.float(0.5, "Risk Per Trade (%)", minval=0.1, maxval=5.0, step=0.1, group=grp_risk)
pipValuePerLot = input.float(10.0, "Pip Value per Standard Lot ($)", minval=1.0, step=0.5, group=grp_risk, tooltip="$10 for USD-quoted majors (EURUSD, GBPUSD).")
entryBufferPips = input.float(0.4, "Model A Limit Entry Buffer (Pips)", minval=0.0, step=0.1, group=grp_risk)
slBufferPips = input.float(1.2, "Stop-Loss Buffer Beyond Candle (Pips)", minval=0.5, step=0.1, group=grp_risk)
maxDecayBars = input.int(4, "Model A Time Decay Limit (M1 Bars)", minval=1, maxval=15, group=grp_risk)
showHud = input.bool(true, "Show Institutional Telemetry HUD", group=grp_risk)
// ============================================================================
// 2. PIP CONVERSION & NON-REPAINTING MTF DATA
// ============================================================================
pipSize = syminfo.mintick * (syminfo.mintick == 0.00001 or syminfo.mintick == 0.001 ? 10 : 1)
// Local M1 Indicators
m1Ema = ta.ema(close, 20)
m1Atr = ta.atr(m1AtrLen)
volSma = ta.sma(volume, volSmaLen)
// Non-Repainting M5 Data (Confirmed closed M5 bar values)
m5EmaExpr = ta.ema(close, m5EmaLen)
m5AtrExpr = ta.atr(m5AtrLen)
[m5Close, m5Ema, m5EmaPrev, m5Atr] = request.security(syminfo.tickerid, "5", [close[1], m5EmaExpr[1], m5EmaExpr[2], m5AtrExpr[1]], barmerge.gaps_off, barmerge.lookahead_on)
// Non-Repainting Previous Day High & Low (PDH / PDL)
[pdh, pdl] = request.security(syminfo.tickerid, "D", [high[1], low[1]], barmerge.gaps_off, barmerge.lookahead_on)
// Evaluate M5 Institutional Filters
m5AtrPips = m5Atr / pipSize
isM5AtrOk = m5AtrPips >= minM5AtrPips
isM5Bull = m5Close > m5Ema and m5Ema > m5EmaPrev
isM5Bear = m5Close < m5Ema and m5Ema < m5EmaPrev
// ============================================================================
// 3. SESSION & LIQUIDITY POOL TRACKING (ASIAN, PRE-NY, PDH/PDL)
// ============================================================================
inAsian = not na(time(timeframe.period, asianSess + ":1234567", "UTC"))
inPreNy = not na(time(timeframe.period, preNySess + ":1234567", "UTC"))
inLonExe = not na(time(timeframe.period, lonExecSess + ":1234567", "UTC"))
inNyExe = not na(time(timeframe.period, nyExecSess + ":1234567", "UTC"))
inExecWindow = not useSessionGate or inLonExe or inNyExe
// Asian Range Variables
var float asianHigh = na
var float asianLow = na
var bool asianHighBroken = false
var bool asianLowBroken = false
if inAsian and not inAsian[1]
asianHigh := high
asianLow := low
asianHighBroken := false
asianLowBroken := false
else if inAsian
asianHigh := math.max(nz(asianHigh, high), high)
asianLow := math.min(nz(asianLow, low), low)
// Pre-NY Range Variables
var float preNyHigh = na
var float preNyLow = na
var bool preNyHighBroken = false
var bool preNyLowBroken = false
if inPreNy and not inPreNy[1]
preNyHigh := high
preNyLow := low
preNyHighBroken := false
preNyLowBroken := false
else if inPreNy
preNyHigh := math.max(nz(preNyHigh, high), high)
preNyLow := math.min(nz(preNyLow, low), low)
// Reset PDH/PDL break flags on new trading day
var bool pdhBroken = false
var bool pdlBroken = false
if ta.change(time("D"))
pdhBroken := false
pdlBroken := false
preNyHigh := na
preNyLow := na
// ============================================================================
// 4. M1 DISPLACEMENT CANDLE ENGINE
// ============================================================================
candleRange = high - low
candleBody = math.abs(close - open)
bodyRatio = candleRange > 0 ? (candleBody / candleRange) * 100.0 : 0.0
isBodyValid = bodyRatio >= minBodyPct
isVolValid = volume >= (volSma * minVolMult)
isAtrValid = candleRange >= (m1Atr * minM1AtrMult) and candleRange <= (m1Atr * maxM1AtrMult)
isBaseDisp = isBodyValid and isVolValid and isAtrValid
// Helper function to validate clearance across a specific horizontal liquidity level
f_checkBullBreak(float lvl, bool alreadyBroken) =>
if na(lvl) or alreadyBroken or close <= open
false
else
clearance = close - lvl
open < lvl and close > lvl and (clearance / candleBody) * 100.0 >= minClearancePct
f_checkBearBreak(float lvl, bool alreadyBroken) =>
if na(lvl) or alreadyBroken or close >= open
false
else
clearance = lvl - close
open > lvl and close < lvl and (clearance / candleBody) * 100.0 >= minClearancePct
// Check individual liquidity pools once their formation window is complete
asianReady = not inAsian and not na(asianHigh)
preNyReady = usePreNyRange and not inPreNy and not na(preNyHigh)
pdhReady = usePdhPdl and not na(pdh)
bullAsian = asianReady and f_checkBullBreak(asianHigh, asianHighBroken)
bearAsian = asianReady and f_checkBearBreak(asianLow, asianLowBroken)
bullPreNy = preNyReady and f_checkBullBreak(preNyHigh, preNyHighBroken)
bearPreNy = preNyReady and f_checkBearBreak(preNyLow, preNyLowBroken)
bullPdh = pdhReady and f_checkBullBreak(pdh, pdhBroken)
bearPdl = pdhReady and f_checkBearBreak(pdl, pdlBroken)
// Combine with M5 filter and Execution Window
m5BullGate = not requireM5Filter or (isM5AtrOk and isM5Bull)
m5BearGate = not requireM5Filter or (isM5AtrOk and isM5Bear)
validBullDisp = inExecWindow and isBaseDisp and m5BullGate and (bullAsian or bullPreNy or bullPdh)
validBearDisp = inExecWindow and isBaseDisp and m5BearGate and (bearAsian or bearPreNy or bearPdl)
// Identify the exact broken level and mark it as consumed for the session
float brokenLvl = na
string lvlName = ""
if validBullDisp
if bullAsian
brokenLvl := asianHigh
lvlName := "Asian High"
asianHighBroken := true
else if bullPreNy
brokenLvl := preNyHigh
lvlName := "Pre-NY High"
preNyHighBroken := true
else if bullPdh
brokenLvl := pdh
lvlName := "PDH"
pdhBroken := true
if validBearDisp
if bearAsian
brokenLvl := asianLow
lvlName := "Asian Low"
asianLowBroken := true
else if bearPreNy
brokenLvl := preNyLow
lvlName := "Pre-NY Low"
preNyLowBroken := true
else if bearPdl
brokenLvl := pdl
lvlName := "PDL"
pdlBroken := true
// Cancel out untouched levels if price breaks through without valid displacement criteria
if asianReady and close > asianHigh and not validBullDisp
asianHighBroken := true
if asianReady and close < asianLow and not validBearDisp
asianLowBroken := true
if preNyReady and close > preNyHigh and not validBullDisp
preNyHighBroken := true
if preNyReady and close < preNyLow and not validBearDisp
preNyLowBroken := true
if pdhReady and close > pdh and not validBullDisp
pdhBroken := true
if pdhReady and close < pdl and not validBearDisp
pdlBroken := true
// ============================================================================
// 5. STATE MACHINE: MODEL A LIMIT RETEST, 4-MIN DECAY & 2-BAR TRAP FILTER
// ============================================================================
// States: 0 = Flat, 1 = Pending Limit Order, 2 = Active Position
var int tradeState = 0
var int tradeDir = 0 // 1 = Long, -1 = Short
var int signalBarIndex = na
var float activeLevel = na
var float entryPrice = na
var float slPrice = na
var float tp1Price = na
var float tp2Price = na
var float activeLots = na
var int insideRangeCnt = 0
bool evtLimitFilled = false
bool evtOrderExpired = false
bool evtTrapScratch = false
bool evtTp2Hit = false
bool evtSlHit = false
// Manage Pending Order (State 1)
if tradeState == 1
barsElapsed = bar_index - signalBarIndex
if tradeDir == 1
// Check if limit filled
if low <= entryPrice
tradeState := 2
insideRangeCnt := 0
evtLimitFilled := true
// Check 4-minute time decay or runaway 1.5R move before fill
else if barsElapsed > maxDecayBars or high >= tp1Price
tradeState := 0
evtOrderExpired := true
else if tradeDir == -1
if high >= entryPrice
tradeState := 2
insideRangeCnt := 0
evtLimitFilled := true
else if barsElapsed > maxDecayBars or low <= tp1Price
tradeState := 0
evtOrderExpired := true
// Manage Active Trade (State 2)
else if tradeState == 2
if tradeDir == 1
// Check SL or TP2 first
if low <= slPrice
tradeState := 0
evtSlHit := true
else if high >= tp2Price
tradeState := 0
evtTp2Hit := true
else
// Two-Candle Acceptance Failure Rule (Bull Trap Filter)
insideRangeCnt := close < activeLevel ? insideRangeCnt + 1 : 0
if insideRangeCnt >= 2
tradeState := 0
evtTrapScratch := true
else if tradeDir == -1
if high >= slPrice
tradeState := 0
evtSlHit := true
else if low <= tp2Price
tradeState := 0
evtTp2Hit := true
else
// Two-Candle Acceptance Failure Rule (Bear Trap Filter)
insideRangeCnt := close > activeLevel ? insideRangeCnt + 1 : 0
if insideRangeCnt >= 2
tradeState := 0
evtTrapScratch := true
// Trigger New Setup on Valid M1 Displacement Candle
if (validBullDisp or validBearDisp) and tradeState == 0
tradeState := 1
tradeDir := validBullDisp ? 1 : -1
signalBarIndex := bar_index
activeLevel := brokenLvl
insideRangeCnt := 0
entryPrice := validBullDisp ? activeLevel + (entryBufferPips * pipSize) : activeLevel - (entryBufferPips * pipSize)
slPrice := validBullDisp ? low - (slBufferPips * pipSize) : high + (slBufferPips * pipSize)
// Enforce minimum 3.5-pip structural stop distance
minSlDist = 3.5 * pipSize
if math.abs(entryPrice - slPrice) < minSlDist
slPrice := validBullDisp ? entryPrice - minSlDist : entryPrice + minSlDist
riskDist = math.abs(entryPrice - slPrice)
slPips = riskDist / pipSize
tp1Price := validBullDisp ? entryPrice + (riskDist * 1.5) : entryPrice - (riskDist * 1.5)
tp2Price := validBullDisp ? entryPrice + (riskDist * 2.5) : entryPrice - (riskDist * 2.5)
// Dynamic Position Size Calculation (Standard Lots)
riskDollars = acctBalance * (riskPct / 100.0)
activeLots := slPips > 0 ? riskDollars / (slPips * pipValuePerLot) : 0.0
// Draw Setup Visuals (Boxes & Labels)
boxRight = bar_index + 12
box.new(bar_index, tp2Price, boxRight, entryPrice, border_color=color.new(color.teal, 40), bgcolor=color.new(color.teal, 85), text="TP2 (+2.5R)\nTP1 (+1.5R): " + str.tostring(tp1Price, format.mintick), text_color=color.white, text_size=size.small)
box.new(bar_index, entryPrice, boxRight, slPrice, border_color=color.new(color.maroon, 40), bgcolor=color.new(color.maroon, 85), text="SL (" + str.tostring(slPips, "#.#") + "p)", text_color=color.white, text_size=size.small)
lblText = (validBullDisp ? "LONG " : "SHORT ") + lvlName + "\nLimit: " + str.tostring(entryPrice, format.mintick) + "\nSize: " + str.tostring(activeLots, "#.##") + " Lots"
label.new(bar_index, validBullDisp ? low : high, lblText, style=validBullDisp ? label.style_label_up : label.style_label_down, color=validBullDisp ? color.teal : color.maroon, textcolor=color.white, size=size.small)
// ============================================================================
// 6. CHART PLOTS, BAR COLORING & HUD TABLE
// ============================================================================
plot(m1Ema, "M1 20 EMA", color=color.new(color.aqua, 20), linewidth=1)
plot(m5Ema, "M5 20 EMA (MTF)", color=color.new(color.orange, 10), linewidth=2)
plot(not inAsian ? asianHigh : na, "Asian High", color=color.new(color.yellow, 15), style=plot.style_linebr, linewidth=2)
plot(not inAsian ? asianLow : na, "Asian Low", color=color.new(color.yellow, 15), style=plot.style_linebr, linewidth=2)
plot(usePreNyRange and not inPreNy ? preNyHigh : na, "Pre-NY High", color=color.new(color.fuchsia, 25), style=plot.style_linebr, linewidth=1)
plot(usePreNyRange and not inPreNy ? preNyLow : na, "Pre-NY Low", color=color.new(color.fuchsia, 25), style=plot.style_linebr, linewidth=1)
plot(usePdhPdl ? pdh : na, "PDH", color=color.new(color.gray, 30), style=plot.style_circles, linewidth=1)
plot(usePdhPdl ? pdl : na, "PDL", color=color.new(color.gray, 30), style=plot.style_circles, linewidth=1)
// Highlight Active Execution Sessions & Displacement Candles
bgcolor(inLonExe or inNyExe ? color.new(color.blue, 94) : na, title="Execution Window Highlight")
barcolor(validBullDisp ? color.lime : validBearDisp ? color.red : na, title="Displacement Candle Highlight")
// Plot State Transition Markers
plotshape(evtLimitFilled, title="Limit Order Filled", style=shape.circle, location=location.abovebar, color=color.aqua, size=size.tiny, text="FILL")
plotshape(evtOrderExpired, title="4-Min Decay Cancelled", style=shape.xcross, location=location.abovebar, color=color.gray, size=size.tiny, text="4m EXP")
plotshape(evtTrapScratch, title="2-Bar Trap Scratch", style=shape.Warning, location=location.abovebar, color=color.orange, size=size.small, text="TRAP SCRATCH")
// Institutional Telemetry HUD
var table hud = table.new(position.top_right, 2, 7, bgcolor=color.new(color.black, 20), border_color=color.new(color.gray, 60), border_width=1)
if barstate.islast and showHud
sessStr = inLonExe ? "LONDON OPEN (ACTIVE)" : inNyExe ? "NY OPEN (ACTIVE)" : inAsian ? "ASIAN (BUILDING)" : "OFF-PEAK (STANDBY)"
sessCol = (inLonExe or inNyExe) ? color.lime : color.gray
biasStr = isM5Bull ? "BULLISH (Above 20 EMA)" : isM5Bear ? "BEARISH (Below 20 EMA)" : "NEUTRAL / CHOP"
biasCol = isM5Bull ? color.lime : isM5Bear ? color.red : color.orange
stateStr = tradeState == 1 ? "PENDING LIMIT (4m Timer)" : tradeState == 2 ? "IN POSITION (Monitoring)" : "SCANNING LEVELS"
stateCol = tradeState == 1 ? color.yellow : tradeState == 2 ? color.aqua : color.white
table.cell(hud, 0, 0, "INSTITUTIONAL SCALPER", text_color=color.white, bgcolor=color.new(color.blue, 40), text_size=size.small)
table.cell(hud, 1, 0, syminfo.ticker, text_color=color.white, bgcolor=color.new(color.blue, 40), text_size=size.small)
table.cell(hud, 0, 1, "Session Window", text_color=color.silver, text_size=size.small)
table.cell(hud, 1, 1, sessStr, text_color=sessCol, text_size=size.small)
table.cell(hud, 0, 2, "M5 Volatility (ATR)", text_color=color.silver, text_size=size.small)
table.cell(hud, 1, 2, str.tostring(m5AtrPips, "#.##") + " Pips " + (isM5AtrOk ? "[OK]" : "[LOW]"), text_color=isM5AtrOk ? color.lime : color.red, text_size=size.small)
table.cell(hud, 0, 3, "M5 20 EMA Pressure", text_color=color.silver, text_size=size.small)
table.cell(hud, 1, 3, biasStr, text_color=biasCol, text_size=size.small)
table.cell(hud, 0, 4, "M1 Volume Spike", text_color=color.silver, text_size=size.small)
table.cell(hud, 1, 4, str.tostring(volume / volSma, "#.##") + "x Avg", text_color=isVolValid ? color.lime : color.silver, text_size=size.small)
table.cell(hud, 0, 5, "Engine Status", text_color=color.silver, text_size=size.small)
table.cell(hud, 1, 5, stateStr, text_color=stateCol, text_size=size.small)
table.cell(hud, 0, 6, "Last Calc Lot Size", text_color=color.silver, text_size=size.small)
table.cell(hud, 1, 6, na(activeLots) ? "N/A" : str.tostring(activeLots, "#.##") + " Lots (" + str.tostring(riskPct) + "%)", text_color=color.aqua, text_size=size.small)
// ============================================================================
// 7. REAL-TIME EXECUTION ALERTS
// ============================================================================
alertcondition(validBullDisp, title="1. Bullish Displacement Setup", message="BULLISH M1 Displacement Breakout on {{ticker}}! Place Limit Retest Order.")
alertcondition(validBearDisp, title="2. Bearish Displacement Setup", message="BEARISH M1 Displacement Breakout on {{ticker}}! Place Limit Retest Order.")
alertcondition(evtLimitFilled, title="3. Model A Limit Order Filled", message="Model A Limit Order FILLED on {{ticker}}.")
alertcondition(evtOrderExpired, title="4. Limit Cancelled (4-Min Rule)", message="CANCEL PENDING LIMIT on {{ticker}}: 4-Minute Time Decay or 1.5R reached unfilled.")
alertcondition(evtTrapScratch, title="5. EMERGENCY: 2-Bar Trap Scratch", message="TRAP DETECTED on {{ticker}}: 2 consecutive M1 closes back inside range. SCRATCH TRADE AT MARKET!")