Because TradingView cannot execute trades natively on IC Markets, this script uses Visual Shapes and dynamic Alerts. You can link these alerts to a webhook service (like PineConnector or a custom cBot endpoint) to retain the auto-execution.
Code: Select all
//@version=5
indicator("HTF Liquidity Sweeps (EQH/EQL) [Auto-Exec]", overlay=true, max_lines_count=500)
// === INPUTS ===
grp1 = "Structural Mapping"
swingBars = input.int(5, "Swing Bars (Left & Right)", group=grp1)
tolPips = input.float(15.0, "EQH/EQL Tolerance (Pips)", group=grp1)
h4Color = input.color(color.new(color.orange, 0), "H4 Color", group=grp1)
d1Color = input.color(color.new(color.red, 0), "D1 Color", group=grp1)
grp2 = "Execution Triggers"
alertOnSweep = input.bool(true, "Fire Alert on M15 Sweep", group=grp2)
// Pip Calculation (Dynamically scales for IC Markets 5-digit forex)
pip = syminfo.mintick * (syminfo.type == "forex" and (syminfo.mintick == 0.00001 or syminfo.mintick == 0.001) ? 10 : 1)
tol = tolPips * pip
// === CUSTOM TYPES & STATE ===
type SwingPoint
int t
float p
bool used
var h4_highs = array.new<SwingPoint>()
var h4_lows = array.new<SwingPoint>()
var d1_highs = array.new<SwingPoint>()
var d1_lows = array.new<SwingPoint>()
// Tracks active liquidity levels waiting to be swept
var activeEQH = array.new_float()
var activeEQL = array.new_float()
// === CORE LOGIC FUNCTION ===
processPivots(float ph, int ph_time, float pl, int pl_time, array<SwingPoint> arr_highs, array<SwingPoint> arr_lows, color line_col, string tf_prefix) =>
// Process Highs (EQH)
if not na(ph)
array.push(arr_highs, SwingPoint.new(ph_time, ph, false))
size = array.size(arr_highs)
if size > 1
for i = size - 2 to 0
past = array.get(arr_highs, i)
if not past.used and math.abs(past.p - ph) <= tol
past.used := true
array.get(arr_highs, size - 1).used := true
line.new(x1=past.t, y1=past.p, x2=ph_time, y2=ph, xloc=xloc.bar_time, color=line_col, style=line.style_solid, width=2, extend=extend.right)
array.push(activeEQH, ph)
break
// Process Lows (EQL)
if not na(pl)
array.push(arr_lows, SwingPoint.new(pl_time, pl, false))
size = array.size(arr_lows)
if size > 1
for i = size - 2 to 0
past = array.get(arr_lows, i)
if not past.used and math.abs(past.p - pl) <= tol
past.used := true
array.get(arr_lows, size - 1).used := true
line.new(x1=past.t, y1=past.p, x2=pl_time, y2=pl, xloc=xloc.bar_time, color=line_col, style=line.style_solid, width=2, extend=extend.right)
array.push(activeEQL, pl)
break
// === HTF DATA RETRIEVAL ===
// Lookahead is OFF to prevent repainting. Pivots only confirm after the right shoulder closes.
[h4_ph, h4_ph_time, h4_pl, h4_pl_time] = request.security(syminfo.tickerid, "240", [ta.pivothigh(high, swingBars, swingBars), time[swingBars], ta.pivotlow(low, swingBars, swingBars), time[swingBars]], lookahead=barmerge.lookahead_off)
[d1_ph, d1_ph_time, d1_pl, d1_pl_time] = request.security(syminfo.tickerid, "D", [ta.pivothigh(high, swingBars, swingBars), time[swingBars], ta.pivotlow(low, swingBars, swingBars), time[swingBars]], lookahead=barmerge.lookahead_off)
// Track exactly when a new HTF pivot is formed to prevent processing the same pivot multiple times
var int last_h4_ph_t = 0
var int last_h4_pl_t = 0
var int last_d1_ph_t = 0
var int last_d1_pl_t = 0
h4_ph_new = not na(h4_ph) and h4_ph_time != last_h4_ph_t
h4_pl_new = not na(h4_pl) and h4_pl_time != last_h4_pl_t
d1_ph_new = not na(d1_ph) and d1_ph_time != last_d1_ph_t
d1_pl_new = not na(d1_pl) and d1_pl_time != last_d1_pl_t
if h4_ph_new
last_h4_ph_t := h4_ph_time
if h4_pl_new
last_h4_pl_t := h4_pl_time
if d1_ph_new
last_d1_ph_t := d1_ph_time
if d1_pl_new
last_d1_pl_t := d1_pl_time
if h4_ph_new or h4_pl_new
processPivots(h4_ph_new ? h4_ph : na, h4_ph_time, h4_pl_new ? h4_pl : na, h4_pl_time, h4_highs, h4_lows, h4Color, "H4")
if d1_ph_new or d1_pl_new
processPivots(d1_ph_new ? d1_ph : na, d1_ph_time, d1_pl_new ? d1_pl : na, d1_pl_time, d1_highs, d1_lows, d1Color, "D1")
// === SWEEP DETECTION & ALERTS (M15) ===
sweep_short = false
sweep_long = false
// Evaluate active EQH (Double Tops) - Iterating backwards allows safe removal
if array.size(activeEQH) > 0
for i = array.size(activeEQH) - 1 to 0
eqh = array.get(activeEQH, i)
// Bearish Sweep: Opened below, pierced above, closed below
if open < eqh and high > eqh and close < eqh
sweep_short := true
array.remove(activeEQH, i) // Remove level once swept to prevent duplicate executions
// Evaluate active EQL (Double Bottoms)
if array.size(activeEQL) > 0
for i = array.size(activeEQL) - 1 to 0
eql = array.get(activeEQL, i)
// Bullish Sweep: Opened above, pierced below, closed above
if open > eql and low < eql and close > eql
sweep_long := true
array.remove(activeEQL, i)
// Alert Triggers (Used for Webhook Auto-Execution)
if sweep_short and alertOnSweep
alert("LiqSweep Short: EQH Swept. Execute Sell Order.", alert.freq_once_per_bar_close)
if sweep_long and alertOnSweep
alert("LiqSweep Long: EQL Swept. Execute Buy Order.", alert.freq_once_per_bar_close)
// Visual Execution Markers
plotshape(sweep_short, title="Short Sweep Trigger", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)
plotshape(sweep_long, title="Long Sweep Trigger", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)