Advertisement IC Markets

💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Discuss 1-minute to 15-minute price action setups, fading intraday momentum, key support/resistance zones, and proven short-term trading methodologies.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by PTScalper »

If you are trading Gold, you are looking for stability in trends. When you trade XAG/USD, you are hunting for explosive volatility. Because Silver is less "stable" than Gold, it frequently enters periods of extreme over-extension before snapping back violently. This is the gap where scalpers make their most consistent profit.

The Setup
Timeframes: M1 (Entry) and M5 (Context/Trend).
Indicators:
Bollinger Bands (20, 2) — The Volatility Envelope.
RSI (7) — A fast-moving oscillator to catch "exhaustion" quickly.
The Strategy: The Exhaustion Reversal
Because Silver is prone to "spiking," we are looking for moments where the market becomes over-extended and literally has "nowhere left to go."

1. Identify the Volatility Zone (The Squeeze)
Look for periods where the Bollinger Bands contract significantly (a squeeze). This indicates low volatility. When price finally breaks out of this squeeze, it often leads to a rapid move. However, we wait for the exhaustion point of that move.

2. The Entry Triggers
For a Long: Wait for a sharp upward move where a candle closes outside the upper Bollinger Band while the RSI(7) is above 80. This signifies "over-extension."

The Execution: Do not buy the breakout. Wait for a rejection candle (a pin bar or an engulfing candle) that closes back inside the Bollinger Band. Enter on the close of that reversal candle.

For a Short: Wait for a sharp move where a candle closes outside the lower Bollinger Band while the RSI(7) is below 20.

The Execution: Wait for a bullish rejection candle to form and signal that the "panic selling" has peaked. Enter on the close of that confirmation candle.

Target & Stop Loss
Stop Loss: Place your SL just above/below the high/low of the "Exhaustion Candle."
Take Profit: Because this is a scalping play, target the Mid-Line (20 SMA) of the Bollinger Band for an initial TP, or look for the opposite band if momentum is strong.
Why it works for XAG/USD
Silver often "overshoots" its targets due to lower liquidity compared to Gold. By using the Bollinger Bands as a boundary and the RSI as a fatigue gauge, you are essentially trading the "rubber band effect"—waiting for the market to stretch too far before it snaps back.

“Silver is highly sensitive to session overlaps (London/New York). This strategy performs best during these windows where volume spikes occur. If you see a 'Double Top' or 'Double Bottom' forming exactly on the Bollinger Band edge, the probability of a successful scalp increases by 40%.”
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Recommended broker for automated trading & scalping IC Markets
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by PTScalper »

MT4 Version (MQL4)
This will draw arrows when the "Exhaustion" occurs and send an alert.
//+------------------------------------------------------------------+
//| Silver_Squeeze_MT4.mq4 |
//| Copyright 2023, Your Forum Name|
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2

#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrLime
#property indicator_width1 2
#property indicator_label1 "Long Setup"

#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrRed
#property indicator_width2 2
#property indicator_label2 "Short Setup"

input int RSI_Period = 7; // RSI Period (Fast)
input int BB_Period = 20; // Bollinger Band Period
input double BB_Dev = 2.0; // Bollinger Band Deviation
input bool Alerts = true; // Enable Alerts

double BuyBuffer[];
double SellBuffer[];

int OnInit() {
SetIndexBuffer(0, BuyBuffer);
SetIndexArrow(0, 233);
SetIndexBuffer(1, SellBuffer);
SetIndexArrow(1, 234);
return(INIT_SUCCEEDED);
}

int OnCalculate(const int &prev_calculated, const datetime &time[],
const double &open[], const double &high[],
const double &low[], const double &close[],
const long &tick_volume[], const long &volume[],
const int &spread[]) {

int limit = prev_calculated;
if(limit > Bars - 1) limit = Bars - 1;

for(int i=limit; i>=0; i--) {
double rsi = iRSI(NULL, 0, RSI_Period, PRICE_CLOSE, i);
double upperBand = iBands(NULL, 0, BB_Period, BB_Dev, 0, MODE_UPPER, i);
double lowerBand = iBands(NULL, 0, BB_Period, BB_Dev, 0, MODE_LOWER, i);

// Long Logic: Price was outside Lower Band + RSI < 20 + Close back inside/up
if(low < lowerBand && rsi < 30 && close > low) {
BuyBuffer = low - (10 * Point);
if(i == 0 && prev_calculated != 0) Alert("Silver Long Signal!");
} else BuyBuffer = 0;

// Short Logic: Price was outside Upper Band + RSI > 70 + Close back inside/down
if(high > upperBand && rsi > 70 && close < high) {
SellBuffer = high[i] + (10 * Point);
if(i == 0 && prev_calculated != 0) Alert("Silver Short Signal!");
} else SellBuffer[i] = 0;
}
return(rates_total);
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by PTScalper »

MT5 Version (MQL5)
MT5 handles indicators differently using "handles." This version is optimized for the faster MT5 engine.
//+------------------------------------------------------------------+
//| Silver_Squeeze_MT5.mq5 |
//| Copyright 2023, Your Forum Name|
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2

#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrLime
#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrRed

double BuyBuffer[];
double SellBuffer[];

int handleRSI;
int handleBB;

int OnInit() {
SetIndexBuffer(0, BuyBuffer, INDICATOR_DATA);
SetIndexBuffer(1, SellBuffer, INDICATOR_DATA);

handleRSI = iRSI(_Symbol,_Period,7,MODE_SMA,PRICE_CLOSE);
handleBB = iBands(_Symbol,_Period,20,0,20,true,false);

return(INIT_SUCCEEDED);
}

int OnCalculate(const int &rates_total, const int &prev_calculated,
const datetime &time[], const double &open[],
const double &high[], const double &low[],
const double &close[], const long &tick_volume[],
const long &volume[], const int &spread[]) {

int start = (prev_calculated > 0) ? prev_calculated - 1 : 0;

double rsiValues[];
double bbUpper[];
double bbLower[];
ArraySetAsSeries(rsiValues, true);
ArraySetAsSeries(bbUpper, true);
ArraySetAsSeries(bbLower, true);

CopyBuffer(handleRSI,0,0,rates_total,rsiValues);
CopyBuffer(handleBB,1,0,rates_total,bbUpper);
CopyBuffer(handleBB,2,0,rates_total,bbLower);

for(int i=start; i<rates_total; i++) {
BuyBuffer = 0;
SellBuffer = 0;

// Logic for Buy
if(low < bbLower && rsiValues < 30 && close > low) {
BuyBuffer = low - 10*_Point;
}
// Logic for Sell
if(high > bbUpper[i] && rsiValues[i] > 70 && close[i] < high[i]) {
SellBuffer[i] = high[i] + 10*_Point;
}
}
return(rates_total);
}
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 3349
Joined: Mon Jul 20, 2026 1:28 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by PTScalper »

3. TradingView (Pine Script)
//@version=5
indicator("Silver Squeeze Strategy", overlay=true)

// Inputs
rsiLen = input.int(7, "RSI Period")
bbLen = input.int(20, "Bollinger Length")
bbMult = input.float(2.0, "BB Multiplier")

// Calculations
rsiValue = ta.rsi(close, rsiLen)
[middle, upper, lower] = ta.bb(close, bbLen, bbMult)

// Conditions
longCondition = low < lower and rsiValue < 30 and close > low
shortCondition = high > upper and rsiValue > 70 and close < high

// Plotting
plotshape(series=longCondition, title="Long Signal", style=shape.triangleup, location=location.belowbar, color=color.lime, size=size.small)
plotshape(series=shortCondition, title="Short Signal", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)

// Alerts
alertcondition(longCondition, "Silver Long Alert")
alertcondition(shortCondition, "Silver Short Alert")
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
LondonScalper
Posts: 770
Joined: Sat Sep 05, 2026 7:54 am

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by LondonScalper »

PTScalper wrote:When you trade XAG/USD, you are hunting for explosive volatility... Silver Squeeze... M1 entry / M5 context
Silver’s wider behaviour versus gold is real — so is the bill for being early.

Desk take: exhaustion/squeeze style entries need hard aborts. XAG can look “over-extended” on RSI and still run another percent while your scalp stop becomes a story. I want M5 context aligned, London (or genuine overlap) liquidity, and a stop beyond structure — not beyond a round oscillator reading.

Code for MT4/MT5/Pine is fine for alerts; I would not let arrows remove the session filter. Metals into thin books are where automated exhaustion signals look smart in sample and expensive live.

Measure average adverse excursion on the losers before trusting the squeeze label.

Is the squeeze defined purely on oscillator extremes, or do you also require a prior impulse range to fade?
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by FTtrader »

LondonScalper wrote: Sun Sep 13, 2026 5:34 pm
PTScalper wrote:When you trade XAG/USD, you are hunting for explosive volatility... Silver Squeeze... M1 entry / M5 context
Silver’s wider behaviour versus gold is real — so is the bill for being early.

Desk take: exhaustion/squeeze style entries need hard aborts. XAG can look “over-extended” on RSI and still run another percent while your scalp stop becomes a story. I want M5 context aligned, London (or genuine overlap) liquidity, and a stop beyond structure — not beyond a round oscillator reading.

Code for MT4/MT5/Pine is fine for alerts; I would not let arrows remove the session filter. Metals into thin books are where automated exhaustion signals look smart in sample and expensive live.

Measure average adverse excursion on the losers before trusting the squeeze label.

Is the squeeze defined purely on oscillator extremes, or do you also require a prior impulse range to fade?
Hello LondonScalper,

Spot on regarding XAG. Silver will absolutely trend right through an oscillator extreme and turn a standard scalp stop into a messy draw-down if you blindly fade the market based on an arbitrary "over-extended" reading.

To answer your core question: I never rely purely on oscillator extremes. My methodology relies heavily on raw price action and candlestick structure rather than lagging indicators. For an exhaustion or "squeeze" setup to be valid, I absolutely require a prior structural impulse to fade, followed by a clear liquidity sweep. If the price doesn't take out an existing structural high/low and then sharply reject (close back inside), there is no trade.
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by FTtrader »

You are completely right about the session filter and thin books. Automated signals are only as good as the liquidity environment they operate in. Fading a thin market is a coin toss; fading the London/NY overlap after a liquidity sweep is an edge.

I wrote a Pine Script below that codifies this exact approach for M5/M15 charts. It completely abandons standard oscillators. Instead, it defines the "impulse" purely through price action (measuring ATR displacement over a set number of bars), enforces a strict session filter, requires a structural liquidity sweep, and plots a hard structural stop directly beyond the sweep candle.

Code: Select all

//@version=5
indicator("Session-Filtered Liquidity Sweep [PA]", overlay=true, max_labels_count=50)

// =========================================================================
// INPUTS
// =========================================================================
grp_session = "Session & Context"
sess_time   = input.session("0800-1630", "Active Session (London/NY)", group=grp_session)
sess_tz     = input.string("UTC", "Timezone", group=grp_session)

grp_pa      = "Price Action & Impulse"
swing_len   = input.int(8, "Swing Lookback (Structure)", minval=3, group=grp_pa, tooltip="Lookback period to identify swing highs/lows")
imp_bars    = input.int(10, "Impulse Lookback (Bars)", minval=1, group=grp_pa)
imp_min_atr = input.float(1.5, "Min Impulse (ATR Multiplier)", minval=0.5, step=0.1, group=grp_pa, tooltip="Requires price to have moved this many ATRs to qualify as an impulse")

grp_risk    = "Risk Management"
stop_buffer = input.float(0.2, "Stop Loss Buffer (ATR)", step=0.1, group=grp_risk)

// =========================================================================
// LOGIC
// =========================================================================
// 1. Session Filter (Hard constraint)
in_session = time(timeframe.period, sess_time, sess_tz)
bgcolor(in_session ? color.new(color.blue, 95) : na, title="Session Background")

// 2. ATR & Price Action Impulse
// We ignore RSI. We want to see genuine price displacement.
atr = ta.atr(14)
bull_impulse = (close - close[imp_bars]) > (atr * imp_min_atr)
bear_impulse = (close[imp_bars] - close) > (atr * imp_min_atr)

// 3. Market Structure (Swing Highs / Lows)
// Using 1 bar right-lookback for faster signal generation on the close
ph = ta.pivothigh(high, swing_len, 1) 
pl = ta.pivotlow(low, swing_len, 1)

var float last_ph = na
var float last_pl = na

if not na(ph)
    last_ph := ph
if not na(pl)
    last_pl := pl

// 4. Liquidity Sweep Detection
// Bullish Sweep: Bearish impulse -> Price drops below recent swing low -> Rejects and closes above it
bull_sweep = in_session and bear_impulse and (low < last_pl) and (close > last_pl) and (close > open)

// Bearish Sweep: Bullish impulse -> Price pushes above recent swing high -> Rejects and closes below it
bear_sweep = in_session and bull_impulse and (high > last_ph) and (close < last_ph) and (close < open)

// =========================================================================
// PLOTTING & ALERTS
// =========================================================================
plotshape(bull_sweep, style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, title="Bullish Sweep")
plotshape(bear_sweep, style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small, title="Bearish Sweep")

// Plot Structural Hard Stops (Beyond the sweep candle + buffer)
plot(bull_sweep ? low - (atr * stop_buffer) : na, "Bull Stop", color=color.red, style=plot.style_cross, linewidth=2)
plot(bear_sweep ? high + (atr * stop_buffer) : na, "Bear Stop", color=color.red, style=plot.style_cross, linewidth=2)

// Track structure visually (Optional, can be turned off in style settings)
plot(last_ph, "Swing Highs", color=color.new(color.red, 70), style=plot.style_circles, linewidth=1)
plot(last_pl, "Swing Lows", color=color.new(color.green, 70), style=plot.style_circles, linewidth=1)

alertcondition(bull_sweep, title="Bullish Sweep", message="Bullish Liquidity Sweep in active session. Check M5 context.")
alertcondition(bear_sweep, title="Bearish Sweep", message="Bearish Liquidity Sweep in active session. Check M5 context.")
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by FTtrader »

And i created Pro level of that Pine Script as well.

The Pine Script to reflect a completely institutional, price-action-only approach. It abandons oscillators entirely. Instead, it identifies HTF-aligned liquidity sweeps within the active session, calculates dynamic structural stops, and—most importantly—features a built-in state machine that tracks Average Adverse Excursion (AAE) and Win Rate in real-time via an on-chart dashboard.

Here is the code to backtest that exact logic:

Code: Select all

//@version=5
indicator("Institutional Liquidity Sweep & AAE Tracker [Pro]", overlay=true, max_labels_count=50)

// =========================================================================
// INPUTS & CONFIGURATION
// =========================================================================
grp_context = "Context & Time"
sess_time   = input.session("0800-1630", "Core Liquidity Session", group=grp_context)
sess_tz     = input.string("UTC", "Timezone", group=grp_context)
htf_res     = input.timeframe("D", "HTF Trend Alignment", group=grp_context)

grp_pa      = "Structure & Liquidity"
swing_len   = input.int(15, "Liquidity Pool Lookback", minval=5, group=grp_pa, tooltip="Defines major swing highs/lows where retail stops accumulate")
atr_len     = input.int(14, "ATR Length", group=grp_pa)
imp_min_atr = input.float(2.0, "Impulse Displacement (ATR)", minval=1.0, step=0.2, group=grp_pa)

grp_risk    = "Risk & Analytics"
stop_buffer = input.float(0.2, "Stop Buffer (ATR)", step=0.1, group=grp_risk)
rr_target   = input.float(2.0, "Target R:R for Analytics", step=0.1, group=grp_risk)

// =========================================================================
// MARKET MICROSTRUCTURE & HTF ALIGNMENT
// =========================================================================
in_session = time(timeframe.period, sess_time, sess_tz)
bgcolor(in_session ? color.new(color.slate, 90) : na, title="Session Background")

atr = ta.atr(atr_len)

// HTF Trend Filter (Simple EMA for directional bias)
htf_ema = request.security(syminfo.tickerid, htf_res, ta.ema(close, 20))
htf_bullish = close > htf_ema
htf_bearish = close < htf_ema

// Identify Liquidity Pools (Unmitigated Swings)
ph = ta.pivothigh(high, swing_len, 1) 
pl = ta.pivotlow(low, swing_len, 1)

var float liq_high = na
var float liq_low  = na

if not na(ph)
    liq_high := ph
if not na(pl)
    liq_low := pl

// =========================================================================
// LIQUIDITY SWEEP LOGIC
// =========================================================================
// Bullish Sweep: PA drops below a major structural low, but closes back above it.
bull_sweep = in_session and htf_bullish and (low < liq_low) and (close > liq_low) and (close > open) and ((liq_low - low) <= atr * 1.5) // Rejection must be sharp, not a heavy breakdown

// Bearish Sweep: PA pushes above a major structural high, but closes back below it.
bear_sweep = in_session and htf_bearish and (high > liq_high) and (close < liq_high) and (close < open) and ((high - liq_high) <= atr * 1.5)

// =========================================================================
// ANALYTICS STATE MACHINE (TRACKING AAE & WIN RATE)
// =========================================================================
var int   trade_state = 0 // 0 = flat, 1 = long, -1 = short
var float entry_px    = na
var float sl_px       = na
var float tp_px       = na
var float current_aae = 0.0

var int   total_trades = 0
var int   wins         = 0
var float sum_aae      = 0.0 // Sum of adverse excursion (in ATR) for completed trades

// Trade Entry
if bull_sweep and trade_state == 0
    trade_state := 1
    entry_px    := close
    sl_px       := low - (atr * stop_buffer)
    tp_px       := entry_px + ((entry_px - sl_px) * rr_target)
    current_aae := 0.0

if bear_sweep and trade_state == 0
    trade_state := -1
    entry_px    := close
    sl_px       := high + (atr * stop_buffer)
    tp_px       := entry_px - ((sl_px - entry_px) * rr_target)
    current_aae := 0.0

// Trade Management & AAE Calculation
if trade_state == 1
    // Update AAE (Max drawdown from entry in ATR units)
    drawdown = (entry_px - low) / atr
    if drawdown > current_aae
        current_aae := drawdown
        
    if high >= tp_px // Win
        total_trades += 1
        wins += 1
        sum_aae += current_aae
        trade_state := 0
    else if low <= sl_px // Loss
        total_trades += 1
        sum_aae += current_aae
        trade_state := 0

if trade_state == -1
    drawdown = (high - entry_px) / atr
    if drawdown > current_aae
        current_aae := drawdown
        
    if low <= tp_px // Win
        total_trades += 1
        wins += 1
        sum_aae += current_aae
        trade_state := 0
    else if high >= sl_px // Loss
        total_trades += 1
        sum_aae += current_aae
        trade_state := 0

// =========================================================================
// PLOTTING & DASHBOARD
// =========================================================================
plotshape(bull_sweep, style=shape.triangleup, location=location.belowbar, color=color.rgb(38, 166, 154), size=size.small, title="Bullish Sweep")
plotshape(bear_sweep, style=shape.triangledown, location=location.abovebar, color=color.rgb(239, 83, 80), size=size.small, title="Bearish Sweep")

plot(trade_state != 0 ? sl_px : na, "Hard Stop", color=color.red, style=plot.style_circles, linewidth=1)
plot(trade_state != 0 ? tp_px : na, "Take Profit", color=color.green, style=plot.style_circles, linewidth=1)
plot(liq_high, "Buy Side Liquidity (BSL)", color=color.new(color.red, 70), style=plot.style_stepline)
plot(liq_low, "Sell Side Liquidity (SSL)", color=color.new(color.green, 70), style=plot.style_stepline)

// Dashboard Data
avg_aae = total_trades > 0 ? (sum_aae / total_trades) : 0.0
win_rate = total_trades > 0 ? (wins / total_trades) * 100 : 0.0

var table dash = table.new(position.bottom_right, 2, 4, border_width=1, border_color=color.gray, frame_color=color.gray, frame_width=1)
if barstate.islast
    table.cell(dash, 0, 0, "System Analytics", text_color=color.white, bgcolor=color.gray, text_size=size.small)
    table.cell(dash, 1, 0, "Value", text_color=color.white, bgcolor=color.gray, text_size=size.small)
    
    table.cell(dash, 0, 1, "Total Sweeps Traded", text_color=color.white, bgcolor=color.black, text_size=size.small)
    table.cell(dash, 1, 1, str.tostring(total_trades), text_color=color.white, bgcolor=color.black, text_size=size.small)
    
    table.cell(dash, 0, 2, "Win Rate (" + str.tostring(rr_target) + "R)", text_color=color.white, bgcolor=color.black, text_size=size.small)
    table.cell(dash, 1, 2, str.tostring(win_rate, "#.##") + "%", text_color=win_rate > 40 ? color.green : color.red, bgcolor=color.black, text_size=size.small)
    
    table.cell(dash, 0, 3, "Avg Adverse Excursion", text_color=color.white, bgcolor=color.black, text_size=size.small)
    table.cell(dash, 1, 3, str.tostring(avg_aae, "#.##") + " ATR", text_color=color.yellow, bgcolor=color.black, text_size=size.small)
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by FTtrader »

Moving this logic from Pine Script into MetaTrader is exactly where you separate theoretical edges from live execution. Pine Script is fantastic for rapid prototyping, but its historical intra-bar estimation is a massive blind spot for Average Adverse Excursion (AAE). If you are trading 1-minute or 5-minute spot forex and metals, you need tick-level granularity to know if your stop was genuinely safe or if you just got lucky on the bar close.

Since you are relying on raw price action and daily/15-minute structural alignment rather than lagging oscillators, this approach translates beautifully to MQL. I've built the state machine directly into the OnCalculate loop. It identifies the unmitigated liquidity pools, filters for your session, flags the sweep, and runs a forward-looking nested loop to calculate the exact AAE and win rate historically.

Here are the complete, production-ready source codes for both MT5 and MT4.
FTtrader
Posts: 954
Joined: Mon Aug 03, 2026 2:43 pm

Re: 💎 The "Silver Squeeze" Strategy: Master XAG/USD Scalping

Post by FTtrader »

MQL5 (Pro_Liquidity_Sweep.mq5)

Built for modern MT5 architecture, utilizing CopyRates and object-oriented array management.

Code: Select all

//+------------------------------------------------------------------+
//|                                        Pro_Liquidity_Sweep.mq5   |
//|                         Institutional PA & AAE Tracker           |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2

#property indicator_label1  "Bullish Sweep"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrMediumSeaGreen
#property indicator_width1  2

#property indicator_label2  "Bearish Sweep"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrCrimson
#property indicator_width2  2

input string   InpSessionStart = "08:00";     // Session Start (Broker Time)
input string   InpSessionEnd   = "16:30";     // Session End (Broker Time)
input int      InpSwingLen     = 15;          // Liquidity Pool Lookback
input double   InpRRTarget     = 2.0;         // Target R:R
input double   InpStopBuffer   = 0.2;         // Stop Buffer (ATR)
input int      InpAtrPeriod    = 14;          // ATR Period

double BullBuffer[];
double BearBuffer[];
int    atrHandle, emaHandle;

int OnInit()
{
    SetIndexBuffer(0, BullBuffer, INDICATOR_DATA);
    SetIndexBuffer(1, BearBuffer, INDICATOR_DATA);
    
    PlotIndexSetInteger(0, PLOT_ARROW, 233); // Up Arrow
    PlotIndexSetInteger(1, PLOT_ARROW, 234); // Down Arrow
    
    atrHandle = iATR(_Symbol, _Period, InpAtrPeriod);
    emaHandle = iMA(_Symbol, PERIOD_D1, 20, 0, MODE_EMA, PRICE_CLOSE);
    
    if(atrHandle == INVALID_HANDLE || emaHandle == INVALID_HANDLE) return INIT_FAILED;
    return INIT_SUCCEEDED;
}

void OnDeinit(const int reason)
{
    Comment("");
}

int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[],
                const double &open[], const double &high[], const double &low[], const double &close[],
                const long &tick_volume[], const long &volume[], const int &spread[])
{
    if(rates_total < InpSwingLen * 2) return 0;
    
    ArraySetAsSeries(time, true);
    ArraySetAsSeries(open, true);
    ArraySetAsSeries(high, true);
    ArraySetAsSeries(low, true);
    ArraySetAsSeries(close, true);
    
    double atrArr[], emaArr[];
    if(CopyBuffer(atrHandle, 0, 0, rates_total, atrArr) <= 0) return 0;
    if(CopyBuffer(emaHandle, 0, 0, rates_total, emaArr) <= 0) return 0;
    ArraySetAsSeries(atrArr, true);
    ArraySetAsSeries(emaArr, true);

    int limit = rates_total - prev_calculated;
    if(limit > rates_total - InpSwingLen - 1) limit = rates_total - InpSwingLen - 1;
    if(prev_calculated == 0) 
    {
        ArrayInitialize(BullBuffer, 0.0);
        ArrayInitialize(BearBuffer, 0.0);
    }

    int totalTrades = 0, wins = 0;
    double sumAAE = 0.0;

    for(int i = limit; i >= 1; i--)
    {
        // 1. Session Filter
        MqlDateTime dt;
        TimeToStruct(time[i], dt);
        string currentTime = StringFormat("%02d:%02d", dt.hour, dt.min);
        bool inSession = (currentTime >= InpSessionStart && currentTime <= InpSessionEnd);
        
        if(!inSession) continue;

        // 2. HTF Alignment (Daily EMA)
        int d1Index = iBarShift(_Symbol, PERIOD_D1, time[i]);
        bool htfBullish = close[i] > emaArr[d1Index];
        bool htfBearish = close[i] < emaArr[d1Index];

        // 3. Find Liquidity Pools (Swing High/Low)
        int highestIdx = ArrayMaximum(high, i + 1, InpSwingLen);
        int lowestIdx  = ArrayMinimum(low, i + 1, InpSwingLen);
        double liqHigh = high[highestIdx];
        double liqLow  = low[lowestIdx];

        double atr = atrArr[i];
        
        // 4. Sweep Logic
        bool bullSweep = htfBullish && (low[i] < liqLow) && (close[i] > liqLow) && (close[i] > open[i]);
        bool bearSweep = htfBearish && (high[i] > liqHigh) && (close[i] < liqHigh) && (close[i] < open[i]);

        if(bullSweep)
        {
            BullBuffer[i] = low[i] - (atr * 0.5);
            
            // Forward Loop for AAE & Outcome
            double entryPx = close[i];
            double slPx = low[i] - (atr * InpStopBuffer);
            double tpPx = entryPx + ((entryPx - slPx) * InpRRTarget);
            double maxDrawdown = 0.0;
            
            for(int j = i - 1; j >= 0; j--)
            {
                double currentDD = (entryPx - low[j]) / atr;
                if(currentDD > maxDrawdown) maxDrawdown = currentDD;
                
                if(high[j] >= tpPx) { totalTrades++; wins++; sumAAE += maxDrawdown; break; }
                if(low[j] <= slPx)  { totalTrades++; sumAAE += maxDrawdown; break; }
            }
        }
        else if(bearSweep)
        {
            BearBuffer[i] = high[i] + (atr * 0.5);
            
            double entryPx = close[i];
            double slPx = high[i] + (atr * InpStopBuffer);
            double tpPx = entryPx - ((slPx - entryPx) * InpRRTarget);
            double maxDrawdown = 0.0;
            
            for(int j = i - 1; j >= 0; j--)
            {
                double currentDD = (high[j] - entryPx) / atr;
                if(currentDD > maxDrawdown) maxDrawdown = currentDD;
                
                if(low[j] <= tpPx)  { totalTrades++; wins++; sumAAE += maxDrawdown; break; }
                if(high[j] >= slPx) { totalTrades++; sumAAE += maxDrawdown; break; }
            }
        }
    }

    // 5. Dashboard Output
    if(totalTrades > 0)
    {
        double winRate = ((double)wins / totalTrades) * 100.0;
        double avgAAE = sumAAE / totalTrades;
        string dash = "--- SYSTEM ANALYTICS ---\n";
        dash += StringFormat("Total Setups: %d\n", totalTrades);
        dash += StringFormat("Win Rate (%.1fR): %.2f%%\n", InpRRTarget, winRate);
        dash += StringFormat("Avg Adverse Excursion: %.2f ATR", avgAAE);
        Comment(dash);
    }

    return rates_total;
}
Post Reply