Page 1 of 1

🏆 Master XAU/USD: The "Liquidity Sweep" Scalping Strategy (Expert Level)

Posted: Sun Jul 26, 2026 1:01 pm
by PTScalper
Gold is not a typical forex pair. It is a beast of volatility, and most scalpers fail because they treat it like EUR/USD. To master XAU/USD scalping, you must stop looking for simple crossovers and start identifying where the "Big Fish" are trapping retail traders.

Today, we’re diving into a high-probability setup I call: The Liquidity Sweep & Retest.

The Theory
Large institutions need liquidity to fill their massive orders. In Gold, this usually happens at obvious levels: previous day highs (PDH), previous day lows (PDL), and "equal highs/lows." Retail traders see a break of these levels and jump in for a "breakout," only to be stopped out when the price snaps back.

Our goal is to wait for them to get trapped first.

The Setup
Timeframes: 5-Minute (Entry), 15-Minute (Context).
Indicators: VWAP (Volume Weighted Average Price) and a 20-period EMA.
Target Pairs: XAU/USD (Primary focus).
The "Secret" Execution Rules:
To enter a trade, three components must align perfectly:

The Liquidity Grab: Look for a clear peak or valley on the M15 chart (e.g., yesterday's high). You are looking for a sudden "spike" that pierces that level but fails to stay above/below it immediately.
The Displacement: After the grab, look for an aggressive move in the opposite direction. This is institutional "rejection." We want to see a large candle (displacement) that moves away from the high/low and closes back inside the previous range.
The VWAP Confirmation: Only take the trade if the price is on the correct side of the VWAP.
Long: Price grabs a low, rejects it with volume, and sits above the VWAP.
Short: Price grabs a high, rejects it with volume, and sits below the VWAP.
Entry & Exit Protocol
Entry: Enter on the first 1-minute candle that closes in your direction following the "Rejection" of the liquidity zone.
Stop Loss (SL): Place your SL just above/below the "wick" of the Liquidity Grab.
Take Profit (TP): Target the next logical liquidity zone or a minimum 1:2 Risk-to-Reward ratio.
Why this works for Gold
Gold thrives on volatility. By waiting for the "Sweep," you are essentially letting the market "wash out" the weak hands before you enter your trade. You aren't trading the noise; you are trading the reaction to the noise.

Post a screenshot of your XAU/USD charts below—let’s analyze some liquidity zones together! 👇

#GoldTrading #XAUUSD #ForexScalping #PriceAction #LiquiditySweep #SmartMoneyConcepts #ForexStrategy

Re: 🏆 Master XAU/USD: The "Liquidity Sweep" Scalping Strategy (Expert Level)

Posted: Sun Jul 26, 2026 1:03 pm
by PTScalper
How to install:
1) Open your MT4 platform.
2) Go to File > Open Data Folder.
3) Navigate to MQL4 > Indicators.
4) Create a new file named Gold_Liquidity_Sweep.mq4 and paste the code below.
5) Compile it in the MetaEditor and attach it to your XAU/USD chart (M1 or M5).
//+------------------------------------------------------------------+
//| Gold_Liquidity_Sweep.mq4|
//| Copyright 2023, Your Forum Name|
//| Specialized for XAU/USD |
//+------------------------------------------------------------------+
#property copyright "YourForumName"
#property link "http://yourforumlink.com"
#property version "1.00"
#property strict

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2

// Plot Settings
#property indicator_type1 DRAW_ARROW
#property indicator_color1 clrLime
#property indicator_width1 2
#property indicator_label1 "Buy Sweep (Bullish)"

#property indicator_type2 DRAW_ARROW
#property indicator_color2 clrRed
#property indicator_width2 2
#property indicator_label2 "Sell Sweep (Bearish)"

//--- Inputs
input int EMA_Period = 20; // Filter EMA Period
input bool Alert_Enabled = true; // Enable Sound/Popup Alerts
input int LookbackDays = 1; // Look back days to find High/Low

//--- Buffers
double BuyBuffer[];
double SellBuffer[];

// Global Variables
double pdh, pdl; // Previous Day High and Low

//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
SetIndexBuffer(0, BuyBuffer);
SetIndexArrow(0, 233); // Up Arrow

SetIndexBuffer(1, SellBuffer);
SetIndexArrow(1, 234); // Down Arrow

// Set up levels on chart (optional visual)
ObjectCreate(0, "PDH_Line", OBJ_HLINE, 0, 0, 0);
ObjectSetInteger(0, "PDH_Line", OBJPROP_COLOR, clrGray);
ObjectSetInteger(0, "PDH_Line", OBJPROP_STYLE, STYLE_DOT);

ObjectCreate(0, "PDL_Line", OBJ_HLINE, 0, 0, 0);
ObjectSetInteger(0, "PDL_Line", OBJPROP_COLOR, clrGray);
ObjectSetInteger(0, "PDL_Line", OBJPROP_STYLE, STYLE_DOT);

return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration |
//+------------------------------------------------------------------+
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 limit = rates_total - prev_calculated;
if(limit > 1) limit = rates_total - 1;

// Update Previous Day High/Low automatically
pdh = iHigh(Symbol(), PERIOD_D1, 0); // Current day high (changes as it happens) or previous.
// To be precise for "Yesterday", we use index 1:
pdh = iHigh(_Symbol, PERIOD_D1, 1);
pdl = iLow(_Symbol, PERIOD_D1, 1);

// Update Hlines on chart visually
ObjectMove(0, "PDH_Line", 0, 0, pdh);
ObjectMove(0, "PDL_Line", 0, 0, pdl);

for(int i = limit; i >= 0; i--)
{
BuyBuffer = 0;
SellBuffer = 0;

double currentEMA = iMA(_Symbol, 0, EMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);

//--- BULLISH LIQUIDITY SWEEP ---
// Logic: Price dipped below yesterday's low (Liquidity Grab)
// but closed above it or higher than the previous candle.
if(low < pdl && close > pdl && close > close[i+1])
{
if(close > currentEMA) // Confirmation of momentum
{
BuyBuffer = low - (20 * _Point);
if(i == 0 && prev_calculated != 0) TriggerAlert("BULLISH SWEEP: XAU/USD");
}
}

//--- BEARISH LIQUIDITY SWEEP ---
// Logic: Price spiked above yesterday's high (Liquidity Grab)
// but closed below it.
if(high > pdh && close < pdh && close[i] < close[i+1])
{
if(close[i] < currentEMA) // Confirmation of momentum
{
SellBuffer[i] = high[i] + (20 * _Point);
if(i == 0 && prev_calculated != 0) TriggerAlert("BEARISH SWEEP: XAU/USD");
}
}
}

return(rates_total);
}

//+------------------------------------------------------------------+
//| Alert System |
//+------------------------------------------------------------------+
void TriggerAlert(string msg)
{
static datetime lastAlert = 0;
if(Time[0] != lastAlert)
{
Alert(msg);
SendNotification(msg); // Sends to mobile if configured in MT4 options
lastAlert = Time[0];
}
}


1) Automatic Level Detection: Instead of the user manually drawing lines, the indicator automatically finds yesterday's High and Low (the core of the strategy).
2) The "Rejection" Logic: It doesn't just signal a touch of a line; it checks if the price poked through the line but closed back inside. This is exactly what "Liquidity Sweep" means in pro trading.
3) Multi-Layer Filtering: It incorporates the EMA 20 check to ensure you aren't buying during a massive crash or selling into a moon mission—it only signals when the trend aligns with the sweep.
4) Visual & Audio Alerts: It places arrows on the chart and sends mobile notifications, making it highly valuable for your community members.

The indicator highlights the Liquidity Zone automatically. When you see a green arrow under a 'wick' that pierced the gray dashed line, that is your signal that institutional players have just washed out the retail traders.

Re: 🏆 Master XAU/USD: The "Liquidity Sweep" Scalping Strategy (Expert Level)

Posted: Thu Sep 03, 2026 8:07 am
by FTtrader
Here is a complete, "Pro Level" rewrite of your indicator.

What was wrong with the original code?

Critical Syntax Errors:

BuyBuffer = 0; and low < pdl were missing their array index . This would fail to compile.

Historical Repainting (The biggest issue):

In your for loop, you hardcoded PERIOD_D1, 1. This meant when the indicator scanned past data (e.g., a candle from 3 weeks ago), it was comparing it to yesterday's high/low, completely breaking historical backtesting and visual accuracy.

Hardcoded Offsets:

You used 20 * _Point. On some brokers, Gold has 2 decimal places, and on others it has 3. This causes the arrows to float randomly.

Repainting Alerts:

Triggering alerts on candle 0 (the active, open candle) for a "close above/below" strategy means the alert will trigger mid-candle, but if the price drops before the candle closes, the arrow will vanish.

Pro-Level Upgrades Added:

Time-Synched History:

The indicator now uses iBarShift to properly align the Daily High/Low with the exact historical candle it is evaluating.

ATR-Based Arrow Offsets:

Arrow distance dynamically scales based on volatility (ATR) so it looks perfect on any timeframe (M5, H1, etc.) and any asset.

Alert Confirmation:

Added an input to choose between alerting on the Active Tick (risky) or the Confirmed Candle Close (professional standard).

Multi-Alert System:

Integrated Toggles for Popups, Push Notifications to mobile, Emails, and Sounds.

Clean De-Initialization:

The code now cleans up its chart lines when you remove the indicator.

Re: 🏆 Master XAU/USD: The "Liquidity Sweep" Scalping Strategy (Expert Level)

Posted: Thu Sep 03, 2026 8:07 am
by FTtrader
The Pro Level Code:

Code: Select all

//+------------------------------------------------------------------+
//|                                        Gold_Liquidity_Sweep.mq4  |
//|                                   Copyright 2024, Your Forum Name|
//|                                         Specialized for XAU/USD  |
//+------------------------------------------------------------------+
#property copyright "YourForumName"
#property link      "http://yourforumlink.com"
#property version   "2.00"
#property strict

#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2

// Plot Settings - Buy
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrLime
#property indicator_width1  2
#property indicator_label1  "Bullish Sweep"

// Plot Settings - Sell
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrRed
#property indicator_width2  2
#property indicator_label2  "Bearish Sweep"

//--- Enums
enum ENUM_ALERT_MODE
  {
   ALERT_ON_CLOSE = 0, // Alert on Confirmed Candle Close (Recommended)
   ALERT_ON_TICK  = 1  // Alert on Live Tick (May Repaint)
  };

//--- Inputs
sinput string  s1 = "--- Core Parameters ---";
input int      EMA_Period        = 20;    // Filter EMA Period
input int      ATR_Period        = 14;    // ATR Period (For Arrow Spacing)
input double   Arrow_Offset      = 1.0;   // Arrow Distance (ATR Multiplier)

sinput string  s2 = "--- Visual Settings ---";
input bool     Show_PDH_PDL      = true;  // Show Current Day's PDH/PDL Lines
input color    Color_PDH         = clrGray; // PDH Line Color
input color    Color_PDL         = clrGray; // PDL Line Color

sinput string  s3 = "--- Alerts System ---";
input ENUM_ALERT_MODE Alert_Mode = ALERT_ON_CLOSE; 
input bool     Alert_Popup       = true;  // Popup Alert
input bool     Alert_Push        = false; // Mobile Push Notification
input bool     Alert_Email       = false; // Email Alert
input bool     Alert_Sound       = false; // Sound Alert

//--- Buffers
double         BuyBuffer[];
double         SellBuffer[];

//--- Global Variables
datetime       LastAlertTime     = 0;
string         Obj_PDH = "LiqSweep_PDH";
string         Obj_PDL = "LiqSweep_PDL";

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Configure Buy Buffer
   SetIndexBuffer(0, BuyBuffer);
   SetIndexArrow(0, 233);
   SetIndexEmptyValue(0, 0.0);

   // Configure Sell Buffer
   SetIndexBuffer(1, SellBuffer);
   SetIndexArrow(1, 234);
   SetIndexEmptyValue(1, 0.0);

   // Set short name for indicator subwindow/hover
   IndicatorShortName("LiqSweep EMA(" + IntegerToString(EMA_Period) + ")");

   // Create PDH/PDL lines if enabled
   if(Show_PDH_PDL)
     {
      if(ObjectFind(0, Obj_PDH) < 0) ObjectCreate(0, Obj_PDH, OBJ_HLINE, 0, 0, 0);
      ObjectSetInteger(0, Obj_PDH, OBJPROP_COLOR, Color_PDH);
      ObjectSetInteger(0, Obj_PDH, OBJPROP_STYLE, STYLE_DASHDOT);
      ObjectSetString(0, Obj_PDH, OBJPROP_TEXT, "Previous Day High");
      ObjectSetInteger(0, Obj_PDH, OBJPROP_BACK, true);

      if(ObjectFind(0, Obj_PDL) < 0) ObjectCreate(0, Obj_PDL, OBJ_HLINE, 0, 0, 0);
      ObjectSetInteger(0, Obj_PDL, OBJPROP_COLOR, Color_PDL);
      ObjectSetInteger(0, Obj_PDL, OBJPROP_STYLE, STYLE_DASHDOT);
      ObjectSetString(0, Obj_PDL, OBJPROP_TEXT, "Previous Day Low");
      ObjectSetInteger(0, Obj_PDL, OBJPROP_BACK, true);
     }

   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Clean up objects from chart to prevent clutter
   ObjectDelete(0, Obj_PDH);
   ObjectDelete(0, Obj_PDL);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration                                       |
//+------------------------------------------------------------------+
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[])
  {
   // Ensure we have enough data to calculate
   if(rates_total <= EMA_Period) return(0);

   int limit = rates_total - prev_calculated;
   
   // Initialization/Re-calculation
   if(limit > 1)
     {
      limit = rates_total - 2; // -2 ensures we can safely check i+1 (previous candle)
      ArrayInitialize(BuyBuffer, 0.0);
      ArrayInitialize(SellBuffer, 0.0);
     }

   // --- Update Visual Daily Lines (Active Day Only) ---
   if(Show_PDH_PDL)
     {
      double current_pdh = iHigh(_Symbol, PERIOD_D1, 1);
      double current_pdl = iLow(_Symbol, PERIOD_D1, 1);
      ObjectMove(0, Obj_PDH, 0, 0, current_pdh);
      ObjectMove(0, Obj_PDL, 0, 0, current_pdl);
     }

   // --- Main Calculation Loop ---
   for(int i = limit; i >= 0; i--)
     {
      // Clear current buffer step to prevent artifacting
      BuyBuffer[i]  = 0.0;
      SellBuffer[i] = 0.0;

      // 1. Get the corresponding Historical Previous Day High/Low for THIS specific bar
      int d1_shift    = iBarShift(_Symbol, PERIOD_D1, time[i]);
      double hist_pdh = iHigh(_Symbol, PERIOD_D1, d1_shift + 1);
      double hist_pdl = iLow(_Symbol, PERIOD_D1, d1_shift + 1);

      // 2. Indicators
      double currentEMA = iMA(_Symbol, 0, EMA_Period, 0, MODE_EMA, PRICE_CLOSE, i);
      double currentATR = iATR(_Symbol, 0, ATR_Period, i); // Used for clean visual offset

      // 3. Setup Alert Trigger Bar Check
      bool isAlertBar = (Alert_Mode == ALERT_ON_CLOSE && i == 1) || (Alert_Mode == ALERT_ON_TICK && i == 0);

      //--- BULLISH LIQUIDITY SWEEP ---
      // Logic: Price dipped below historical PDL, closed above it, and closed higher than the previous candle
      if(low[i] < hist_pdl && close[i] > hist_pdl && close[i] > close[i+1])
        {
         if(close[i] > currentEMA) // Confirmation of momentum
           {
            // Position arrow precisely using ATR instead of fixed points
            BuyBuffer[i] = low[i] - (currentATR * Arrow_Offset);

            // Handle Alerts
            if(isAlertBar && time[i] != LastAlertTime)
              {
               TriggerAlert("BULLISH Sweep: " + _Symbol + " (" + GetTimeframeString(Period()) + ")");
               LastAlertTime = time[i];
              }
           }
        }

      //--- BEARISH LIQUIDITY SWEEP ---
      // Logic: Price spiked above historical PDH, closed below it, and closed lower than the previous candle
      if(high[i] > hist_pdh && close[i] < hist_pdh && close[i] < close[i+1])
        {
         if(close[i] < currentEMA) // Confirmation of momentum
           {
            // Position arrow precisely using ATR
            SellBuffer[i] = high[i] + (currentATR * Arrow_Offset);

            // Handle Alerts
            if(isAlertBar && time[i] != LastAlertTime)
              {
               TriggerAlert("BEARISH Sweep: " + _Symbol + " (" + GetTimeframeString(Period()) + ")");
               LastAlertTime = time[i];
              }
           }
        }
     }

   return(rates_total);
  }

//+------------------------------------------------------------------+
//| Custom Alert Function                                            |
//+------------------------------------------------------------------+
void TriggerAlert(string msg)
  {
   if(Alert_Popup) Alert(msg);
   if(Alert_Push)  SendNotification(msg);
   if(Alert_Email) SendMail("Liquidity Sweep Alert", msg);
   if(Alert_Sound) PlaySound("alert.wav");
  }

//+------------------------------------------------------------------+
//| Helper Function: Get Timeframe String                            |
//+------------------------------------------------------------------+
string GetTimeframeString(int tf)
  {
   switch(tf)
     {
      case PERIOD_M1:  return "M1";
      case PERIOD_M5:  return "M5";
      case PERIOD_M15: return "M15";
      case PERIOD_M30: return "M30";
      case PERIOD_H1:  return "H1";
      case PERIOD_H4:  return "H4";
      case PERIOD_D1:  return "D1";
      case PERIOD_W1:  return "W1";
      case PERIOD_MN1: return "MN1";
      default:         return IntegerToString(tf);
     }
  }
//+------------------------------------------------------------------+
Important Usage Note:

Because this strategy revolves around the candle close, I highly recommend leaving the Alert Mode set to Alert on Confirmed Candle Close. If you set it to tick, MT4 will alert you the exact second the price crosses the criteria, but if the candle ends up closing in the opposite direction, you'll be stuck in a trade based on a false signal.

Re: 🏆 Master XAU/USD: The "Liquidity Sweep" Scalping Strategy (Expert Level)

Posted: Sun Sep 13, 2026 7:28 pm
by LondonScalper
PTScalper wrote:The Liquidity Sweep & Retest
Sweep-and-retest on gold is a real pattern — institutions do hunt obvious PDH/PDL and equal highs. The retail failure mode is labelling every wick a “liquidity grab” and forcing a ticket.

Desk rules that kept me honest: wait for the failed hold and a displacement that actually closes back through the level on your execution TF, then retest. VWAP/EMA as context is fine; they are not a substitute for that sequence. First fifteen minutes of London still get a wider berth — false sweeps are common while the book finds itself.

Stops belong beyond the sweep extreme, sized so the R still makes sense after gold’s spread. Tight “safe” stops under the wick are how this setup feels brilliant in screenshots and average in live.

FTtrader’s code hygiene points are worth taking seriously if anyone runs an alert version — a broken buffer helps nobody.

Do you require M15 context alignment, or will you take a clean M5 sweep against the higher-TF bias?