Most Smart Money Concepts overlays stop at drawing structure — order blocks, fair value gaps, a Break of Structure label — and leave the actual trade to you. ICT SMC Expert Signals, by Forex_Market_Insights, takes the opposite stance: it fires a concrete Buy/Sell on a liquidity sweep and immediately projects the whole plan — entry, stop-loss and three take-profit targets by risk-reward — with the risk and reward zones shaded on the chart. A stack of optional filters (EMA bias, an ATR volatility floor, a volume check and a cooldown) lets you go from raw sweeps to a heavily-confirmed setup, and a status panel keeps the current plan in a corner of the chart.
This ProBuilder port keeps the whole package: the sweep logic, the filters, the last-signal trade plan with its zones, and the panel.
The core idea is the classic stop-hunt. Over the last sweepLookback bars (default 10, excluding the current one) the indicator tracks the highest high and the lowest low — the pools of resting liquidity:
recentHigh = highest[sweepLookback](high[1])
recentLow = lowest[sweepLookback](low[1])
A bar that pushes above the prior high but closes back below it has swept buy-side liquidity and failed — a bearish signal:
buySideSweep = high > recentHigh and close < recentHigh // -> SELL
sellSideSweep = low < recentLow and close > recentLow // -> BUY
With requireReversal on (default), the signal bar must also be a reversal candle (a down candle for a Sell, an up candle for a Buy). That is the entire entry trigger — deliberately simple; the quality control lives in the filters.
Each filter can only block a signal, never create one:
(The original also carried a higher-timeframe bias via request.security; it was dropped in the port — see the rendering note below.)
On every accepted signal the indicator builds the plan from the entry close and an ATR-based stop:
entry = close
SL = buy ? low - ATR * stopMult : high + ATR * stopMult
risk = |entry - SL|
TPn = buy ? entry + risk * rrN : entry - risk * rrN (n = 1,2,3)
with default risk-reward ratios 1 / 2 / 3. It then draws entry, SL and the three TP lines, price labels, a risk zone (entry→SL) and a reward zone (entry→TP3) — for the last signal, extended to the right so it tracks the live market.
sweepLookback = 10: liquidity window; larger = only the more significant swings get swept.requireReversal = 1: demand a reversal candle on the signal bar. Set to 0 for more (rawer) signals.useEmaBias / emaLength (50): trend filter, off by default. Raise emaLength for a slower, higher-timeframe-like bias.useAtrVol / minAtrPercent (0.10): volatility floor, as % of price.useVolume / volumeMaLength (20) / volumeMult (1.0): volume confirmation.useCooldown = 1 / cooldownBars = 5: minimum spacing between signals.tradeAtrLength = 14 / stopAtrMult = 0.5: the ATR stop distance beyond the sweep wick.tp1RR / tp2RR / tp3RR = 1.0 / 2.0 / 3.0: the three targets, in R multiples.levelExtend = 50: how far the plan lines project to the right.showDashboard = 1, maxSignals = 100: panel toggle and how many historical BUY/SELL marks are redrawn.A note on rendering. The indicator uses defparam drawonlastbaronly = true so the trade-plan lines and labels — which extend to the right edge and follow price — stay crisp on low timeframes; without it ProBuilder repaints and overlaps them on every tick. Because that flag would otherwise hide inline drawings on past bars, the historical BUY/SELL marks are stored in arrays and redrawn in a loop on the last bar.
The higher-timeframe filter was dropped. The original reads a 4-hour EMA through request.security with a timeframe input — something ProBuilder’s TIMEFRAME can’t reproduce (it needs a literal), and an embedded TIMEFRAME(4 hours) throws an error whenever the chart is on a higher timeframe (e.g. daily) or one that isn’t an integer multiple. Since the filter was off by default, it was removed entirely. For a slower, trend-aligned bias, use useEmaBias with a larger emaLength on the chart timeframe.
What was adapted or dropped. The signal engine, the five filters and the last-signal trade plan are intact. Three things have no clean ProBuilder equivalent:
line/label/linefill objects it edits and deletes each bar; ProBuilder has no dynamic object handles, so the port keeps the last signal’s plan in persistent state and draws it on the last bar. The “TP1/TP2/TP3 HIT” markers and the historical plans are dropped; the live setup and its hit-tracking state are kept.table → an anchored text panel. Same information (direction, last signal, levels, ATR%) as fixed text in the top-right corner, without per-cell backgrounds or the progress bars.alertcondition has no indicator equivalent; alerts are configured from the ProRealTime UI. The longSignal / shortSignal conditions are left clean for ProScreener/ProOrder.//-----------------------------------------------------------//
//PRC_ICT SMC EXPERT SIGNALS (by Forex_Market_Insights)
//version = 1
//09.07.26
//Ivan Gonzalez @ www.prorealcode.com
//Sharing ProRealTime knowledge
//-----------------------------------------------------------//
defparam drawonlastbaronly = true
//-----Inputs (parametros configurables)---------------------//
showSignals = 1
sweepLookback = 10
requireReversal = 1
useEmaBias = 0
emaLength = 50
useAtrVol = 0
volAtrLength = 14
minAtrPercent = 0.10
useVolume = 0
volumeMaLength = 20
volumeMult = 1.0
useCooldown = 1
cooldownBars = 5
tradeAtrLength = 14
stopAtrMult = 0.5
tp1RR = 1.0
tp2RR = 2.0
tp3RR = 3.0
levelExtend = 50
showDashboard = 1
maxSignals = 100
//-----Colors (RGB)------------------------------------------//
buyR = 0
buyG = 190
buyB = 120
sellR = 230
sellG = 65
sellB = 85
entryR = 30
entryG = 140
entryB = 255
slR = 240
slG = 80
slB = 80
tpR = 30
tpG = 190
tpB = 160
//-----ATR and liquidity levels------------------------------//
atrVal = averagetruerange[tradeAtrLength]
volAtrVal = averagetruerange[volAtrLength]
recentHigh = highest[sweepLookback](high[1])
recentLow = lowest[sweepLookback](low[1])
//-----Liquidity sweep detection-----------------------------//
buySideSweep = high > recentHigh and close < recentHigh
sellSideSweep = low < recentLow and close > recentLow
bearRev = close < open
bullRev = close > open
if requireReversal = 1 then
validShort = buySideSweep and bearRev
validLong = sellSideSweep and bullRev
else
validShort = buySideSweep
validLong = sellSideSweep
endif
//-----Bias and confirmation filters-------------------------//
emaBias = average[emaLength,1](close)
if useEmaBias = 1 then
trendLongOk = close > emaBias
trendShortOk = close < emaBias
else
trendLongOk = 1
trendShortOk = 1
endif
atrPercent = volAtrVal / close * 100
if useAtrVol = 1 then
atrVolOk = atrPercent >= minAtrPercent
else
atrVolOk = 1
endif
volumeMa = average[volumeMaLength](volume)
if useVolume = 1 then
volumeOk = volume >= volumeMa * volumeMult
else
volumeOk = 1
endif
//-----Cooldown and final signal-----------------------------//
once hasSignal = 0
once lastSignalBar = 0
if useCooldown = 0 then
cooldownOk = 1
elsif hasSignal = 0 then
cooldownOk = 1
elsif barindex - lastSignalBar >= cooldownBars then
cooldownOk = 1
else
cooldownOk = 0
endif
longSignal = (showSignals = 1) and validLong and trendLongOk and atrVolOk and volumeOk and cooldownOk
shortSignal = (showSignals = 1) and validShort and trendShortOk and atrVolOk and volumeOk and cooldownOk
//-----Live trade state + signal recording-------------------//
once nSig = 0
once tradeDir = 0
once entryBar = 0
once entryVal = 0
once slVal = 0
once tp1Val = 0
once tp2Val = 0
once tp3Val = 0
once tp1Done = 0
once tp2Done = 0
once tp3Done = 0
once slDone = 0
if longSignal then
$sigX[nSig] = barindex
$sigY[nSig] = low
$sigType[nSig] = 1
nSig = nSig + 1
tradeDir = 1
entryBar = barindex
entryVal = close
slVal = low - atrVal * stopAtrMult
riskV = entryVal - slVal
tp1Val = entryVal + riskV * tp1RR
tp2Val = entryVal + riskV * tp2RR
tp3Val = entryVal + riskV * tp3RR
tp1Done = 0
tp2Done = 0
tp3Done = 0
slDone = 0
lastSignalBar = barindex
hasSignal = 1
elsif shortSignal then
$sigX[nSig] = barindex
$sigY[nSig] = high
$sigType[nSig] = 2
nSig = nSig + 1
tradeDir = 0 - 1
entryBar = barindex
entryVal = close
slVal = high + atrVal * stopAtrMult
riskV = slVal - entryVal
tp1Val = entryVal - riskV * tp1RR
tp2Val = entryVal - riskV * tp2RR
tp3Val = entryVal - riskV * tp3RR
tp1Done = 0
tp2Done = 0
tp3Done = 0
slDone = 0
lastSignalBar = barindex
hasSignal = 1
endif
//-----Hit tracking of the live trade------------------------//
if tradeDir = 1 then
if tp1Done = 0 and high >= tp1Val then
tp1Done = 1
endif
if tp2Done = 0 and high >= tp2Val then
tp2Done = 1
endif
if tp3Done = 0 and high >= tp3Val then
tp3Done = 1
endif
if slDone = 0 and low <= slVal then
slDone = 1
endif
elsif tradeDir = 0 - 1 then
if tp1Done = 0 and low <= tp1Val then
tp1Done = 1
endif
if tp2Done = 0 and low <= tp2Val then
tp2Done = 1
endif
if tp3Done = 0 and low <= tp3Val then
tp3Done = 1
endif
if slDone = 0 and high >= slVal then
slDone = 1
endif
endif
//-----Drawing (all on the last bar)-------------------------//
if islastbarupdate then
startI = 0
if nSig > maxSignals then
startI = nSig - maxSignals
endif
if nSig > 0 then
for i = startI to nSig - 1 do
if $sigType[i] = 1 then
drawtext("BUY", $sigX[i], $sigY[i] - atrVal * 0.6) coloured(buyR, buyG, buyB)
else
drawtext("SELL", $sigX[i], $sigY[i] + atrVal * 0.6) coloured(sellR, sellG, sellB)
endif
next
endif
if tradeDir <> 0 then
endBar = barindex + levelExtend
if tradeDir = 1 then
drawrectangle(entryBar, slVal, endBar, entryVal) coloured(slR, slG, slB, 0) fillcolor(slR, slG, slB, 10)
drawrectangle(entryBar, entryVal, endBar, tp3Val) coloured(tpR, tpG, tpB, 0) fillcolor(tpR, tpG, tpB, 8)
else
drawrectangle(entryBar, entryVal, endBar, slVal) coloured(slR, slG, slB, 0) fillcolor(slR, slG, slB, 10)
drawrectangle(entryBar, tp3Val, endBar, entryVal) coloured(tpR, tpG, tpB, 0) fillcolor(tpR, tpG, tpB, 8)
endif
drawsegment(entryBar, entryVal, endBar, entryVal) coloured(entryR, entryG, entryB) style(dottedline)
drawsegment(entryBar, slVal, endBar, slVal) coloured(slR, slG, slB) style(line, 2)
drawsegment(entryBar, tp1Val, endBar, tp1Val) coloured(tpR, tpG, tpB) style(dottedline)
drawsegment(entryBar, tp2Val, endBar, tp2Val) coloured(tpR, tpG, tpB) style(dottedline)
drawsegment(entryBar, tp3Val, endBar, tp3Val) coloured(tpR, tpG, tpB) style(dottedline)
drawtext("Entry #entryVal#", endBar, entryVal+0.20*atrVal) coloured(entryR, entryG, entryB)
drawtext("SL #slVal#", endBar, slVal+0.20*atrVal) coloured(slR, slG, slB)
drawtext("TP1 #tp1Val#", endBar, tp1Val+0.20*atrVal) coloured(tpR, tpG, tpB)
drawtext("TP2 #tp2Val#", endBar, tp2Val+0.20*atrVal) coloured(tpR, tpG, tpB)
drawtext("TP3 #tp3Val#", endBar, tp3Val+0.20*atrVal) coloured(tpR, tpG, tpB)
endif
if showDashboard = 1 then
panelX = 0 - 250
topY = 0 - 30
lineH = 20
drawtext("ICT SMC EXPERT SIGNALS", panelX, topY, sansserif, bold, 11) coloured(entryR, entryG, entryB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
if tradeDir = 1 then
drawtext("Direction: LONG", panelX, topY - lineH, sansserif, bold, 10) coloured(buyR, buyG, buyB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
elsif tradeDir = 0 - 1 then
drawtext("Direction: SHORT", panelX, topY - lineH, sansserif, bold, 10) coloured(sellR, sellG, sellB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
else
drawtext("Direction: --", panelX, topY - lineH, sansserif, standard, 10) coloured(150, 150, 150) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
endif
barsAgo = barindex - lastSignalBar
if hasSignal = 1 then
drawtext("Last signal: #barsAgo# bars", panelX, topY - lineH * 2, sansserif, standard, 10) coloured(200, 200, 200) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
drawtext("Entry #entryVal#", panelX, topY - lineH * 3, sansserif, standard, 10) coloured(entryR, entryG, entryB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
drawtext("SL #slVal#", panelX, topY - lineH * 4, sansserif, standard, 10) coloured(slR, slG, slB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
drawtext("TP1 #tp1Val#", panelX, topY - lineH * 5, sansserif, standard, 10) coloured(tpR, tpG, tpB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
drawtext("TP2 #tp2Val#", panelX, topY - lineH * 6, sansserif, standard, 10) coloured(tpR, tpG, tpB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
drawtext("TP3 #tp3Val#", panelX, topY - lineH * 7, sansserif, standard, 10) coloured(tpR, tpG, tpB) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
else
drawtext("no signal yet", panelX, topY - lineH * 2, sansserif, standard, 10) coloured(150, 150, 150) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
endif
drawtext("ATR%: #atrPercent#", panelX, topY - lineH * 8, sansserif, standard, 10) coloured(200, 200, 200) ANCHOR(TOPRIGHT, XSHIFT, YSHIFT)
endif
endif
//-----------------------------------------------------------//
return