Page 1 of 2

Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:14 pm
by PTScalper
Hi traders, scalpers,

i prepared for you another interesting trading strategy.

The highest-expectancy forex scalping approach combines Higher-Timeframe (H4/D1) Structural Liquidity Zones with M15/M5 Price-Action Displacement on a Raw ECN execution feed. Pure indicator-crossover systems on 1-minute charts break down once spread expansion, slippage, and round-turn commissions are factored in; fading false breakouts (liquidity sweeps) or trading confirmed micro-structure pullbacks in the direction of institutional order flow keeps stops tight (5 to 12 pips) while preserving asymmetric reward-to-risk ratios (1:1.5 to 1:4).

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:15 pm
by PTScalper
1. Strategy Architecture: Multi-Timeframe Liquidity & Micro-Structure

Step-by-Step Execution Protocol

Follow this sequence before placing any order during an active session:

1.Map Pre-Session H4/D1 Liquidity Pools:

Complete 15 minutes before London or New York open.

Mark the Previous Day High (PDH), Previous Day Low (PDL), Asian Session High/Low, and major H4 Support and Resistance zones. These levels act as liquidity magnets where clustered retail stop-losses and breakout orders rest.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:15 pm
by PTScalper
2.Wait for the Liquidity Sweep or Trend Impulse:

Filter out mid-range noise on M15.

Allow price to reach your pre-marked H4 or session level. Look for one of two institutional footprints on the M15 chart:Reversal Sweep (False Breakout): Price pierces the key support/resistance level by a few pips to sweep stops, then prints an impulsive engulfing candle that closes decisively back inside the level.Trend Pullback: In a strong directional trend where EMA 20 is separated from EMA 50, wait for price to pull back into the EMA 20 and horizontal micro-support/resistance zone.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:16 pm
by PTScalper
3.Confirm Micro Break of Structure (BoS) & Enter:

Execute on M5/M15 candle close or 50% retest.

Drop to the M5 or M15 chart and verify that price breaks the minor swing high (for longs) or swing low (for shorts) that initiated the sweep or pullback.Entry: Enter on the confirmation candle close or place a limit order at the 50% retracement of the displacement candle.Hard Stop-Loss: Place a server-side stop-loss 1x M5 ATR (typically 6 to 12 pips on FX majors, or $0.80 to $1.50 on XAU/USD) beyond the extreme tip of the liquidity sweep wick. If price violates that wick, exit immediately without widening the stop.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:16 pm
by PTScalper
4.Manage Trade & Scale Out Asymmetrically:

Protect capital first, let runners capture H4 range.

At +1.2R to +1.5R: Close 50% of the position (or move your hard stop to breakeven plus commission) to eliminate downside risk on the trade.At +2R: Trail the remaining stop-loss behind each new M15 higher low (for longs) or lower high (for shorts).Final Target (+2.5R to +4R) or Time Stop: Target the opposing intraday liquidity pool or session high/low. If price stalls and fails to move in your favor within 3 to 4 M15 candles, close the trade manually via a time stop.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:17 pm
by PTScalper
Position Sizing, Spread Friction & Profit-Locked Scaling

In high-frequency scalping, transaction costs represent a major percentage of gross edge. On a $10,000 account, position sizing must explicitly account for both the structural stop distance and the round-turn ECN commission:

$$\text{Position Size (Lots)} = \frac{\text{Account Equity} \times \text{Risk \%}}{\left(\text{Stop-Loss in Pips} + \text{Effective Spread/Commission in Pips}\right) \times \text{Pip Value}}$$

Worked Calculation ($10,000 Account on EUR/USD)

Baseline Risk per Trade: 0.50% of account equity = $50.00 maximum loss.Trade Parameters:
8.0-pip structural stop-loss + 0.1-pip raw spread + 0.7-pip equivalent commission ($7.00 round-turn per standard lot) = 8.8 pips total risk distance.Exact

Lot Size: $$\text{Position Size} = \frac{\$50.00}{8.8 \text{ pips} \times \$10.00/\text{pip}} = 0.568 \approx \mathbf{0.57 \text{ Standard Lots}}$$

Reward Profile: At a 1.5R initial target (13.2 pips net, or ~14 pips gross), the trade nets $75.00 after commissions; at a 3R runner target (26.4 pips net), it nets $150.00.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:18 pm
by PTScalper
Exponential "Profit-Lock" Risk Protocol

Rather than risking a high static percentage on every trade, separate Core Capital from Accumulated Session Profit:

Phase 1 (Baseline Defense): Risk strictly 0.25% to 0.50% ($25 to $50 on a $10,000 account) until your account builds a realized profit cushion of +2.0% ($200). Enforce a hard daily drawdown cap of 1.5% ($150) or 3 consecutive losses—if hit, shut down the terminal for the session.

Phase 2 (Asymmetric Scaling from Gains): Once you are up +2.0% ($200) on the week, permanently lock 50% ($100) into your protected equity floor and use up to 50% of the unlocked profit buffer ($100) to scale position size on your next A+ London/NY overlap setup. Your core deposit remains insulated while winning streaks compound geometrically.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:19 pm
by PTScalper
Action Plan to Deploy This Strategy

Configure a Raw ECN Execution Workspace: Allocate your baseline trading capital (e.g., $10,000 or a dedicated sub-account) on an ECN account with raw spreads (0.0 to 0.2 pips on EUR/USD) and set a live spread-filter alert so you never execute when spreads widen past 0.5 pips on majors or $0.25 on XAU/USD before your next London session.

Enforce Fixed Fractional & Daily Drawdown Limits: Lock your default order-ticket risk at 0.25% to 0.50% ($25 to $50 per trade) with a hard daily loss limit of 1.5% ($150), and commit to executing 50 consecutive sample trades exclusively during the London Open and London–NY Overlap over the next 30 trading days.

Audit Expectancy & Activate Profit-Locked Scaling: After completing your 50-trade sample block, verify a minimum Profit Factor of 1.4+ and net expectancy greater than 0.3R per trade in your trade journal before activating the 50% profit-lock scaling rule for live lot expansion.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:20 pm
by PTScalper
This complete, production-ready MQL5 Expert Advisor (XAUUSD_LiquidityScalper.mq5) automates the multi-timeframe liquidity sweep and micro-structure pullback strategy specifically calibrated for XAU/USD (Gold) on a Raw ECN execution feed.

Key Architectural Highlights for XAU/USD

Broker-Agnostic USD Price Math: Gold is quoted with either 2 decimals (0.01) or 3 decimals (0.001) depending on the broker. All spread filters, stop-loss bounds, and sweep tolerances in this EA are defined in exact USD price delta (e.g., $0.25 max spread, $1.20 to $3.50 stop-loss bounds) and converted dynamically to broker ticks.

ECN Commission-Adjusted Sizing: Lot size is calculated using SYMBOL_TRADE_TICK_VALUE, SYMBOL_TRADE_TICK_SIZE, and your exact round-turn ECN commission per lot (default $7.00), ensuring a $50 risk target includes commission drag.

Exponential Profit-Lock Scaling Engine: Tracks your baseline equity floor. Once profit reaches your trigger threshold (default +2.0%), the EA locks 50% of the gain into a protected floor and optionally scales position risk using a fraction of the unlocked profit cushion—while enforcing a hard daily drawdown circuit breaker (1.5% or 3 consecutive losses).

State-Tracked Partial Close & M15 Structural Trail: Automatically banks 50% of the position at +1.5R, moves the hard server-side stop-loss to Breakeven + Commission, trails the runner behind M15 structural swing highs/lows past +2.0R, and enforces a time stop on stalled trades.

Re: Forex scalping trading strategy for Gold (XAU/USD)

Posted: Mon Oct 19, 2026 6:20 pm
by PTScalper
Complete MQL5 Source Code (XAUUSD_LiquidityScalper.mq5)

Save the code below in MetaEditor 5 under MQL5/Experts/XAUUSD_LiquidityScalper.mq5 and compile (F7):

Code: Select all

//+------------------------------------------------------------------+
//|                                      XAUUSD_LiquidityScalper.mq5 |
//|          Multi-Timeframe Liquidity Sweep & Pullback Scalping EA  |
//|                                  Calibrated for XAU/USD Raw ECN  |
//+------------------------------------------------------------------+
#property copyright "XAUUSD Liquidity Scalper"
#property version   "1.00"
#property strict

#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\SymbolInfo.mqh>

//+------------------------------------------------------------------+
//| Input Parameters                                                 |
//+------------------------------------------------------------------+
input group "=== 1. Strategy & Setup Filters ==="
input bool           InpEnableSweepSetup      = true;       // Enable Liquidity Sweep (False Breakout)
input bool           InpEnablePullbackSetup   = true;       // Enable M15 EMA 20/50 Trend Pullback
input ENUM_TIMEFRAMES InpTriggerTF            = PERIOD_M5;  // Entry Trigger Timeframe (M5 or M15)
input int            InpEmaFast               = 20;         // M15 Fast EMA Period
input int            InpEmaSlow               = 50;         // M15 Slow EMA Period
input int            InpAtrPeriod             = 14;         // M5 ATR Period for Stop Sizing
input int            InpH4SwingLookback       = 10;         // H4 Bars Lookback for Structural High/Low
input double         InpMaxSweepOvershootUSD  = 2.50;       // Max Liquidity Sweep Piercing ($ USD)
input double         InpTouchToleranceUSD     = 0.35;       // Level / EMA Touch Tolerance ($ USD)

input group "=== 2. XAU/USD Stop-Loss & Target Calibration ==="
input double         InpAtrStopMultiplier     = 1.0;        // ATR Multiplier Beyond Sweep/Pullback Wick
input double         InpMinStopUSD            = 1.20;       // Minimum Structural Stop Distance ($ USD)
input double         InpMaxStopUSD            = 3.50;       // Maximum Structural Stop Distance ($ USD)
input double         InpPartialCloseRR        = 1.5;        // Partial Close & BE Trigger (R-Multiple)
input double         InpPartialCloseRatio     = 0.50;       // Partial Close Volume Ratio (0.50 = 50%)
input double         InpTrailStartRR          = 2.0;        // Start M15 Structural Trail (R-Multiple)
input double         InpFinalTargetRR         = 3.5;        // Hard Take-Profit Target (R-Multiple)
input int            InpTimeStopMinutes       = 45;         // Time Stop if Profit < 0.5R (Minutes, 0=Off)

input group "=== 3. Risk, ECN Commission & Profit-Lock Scaling ==="
input double         InpBaseRiskPct           = 0.50;       // Baseline Risk Per Trade (% of Equity)
input double         InpCommissionPerLotRT    = 7.00;       // Round-Turn ECN Commission Per 1.0 Lot ($)
input bool           InpUseProfitLockScaling  = true;       // Enable Exponential Profit-Lock Scaling
input double         InpProfitLockTriggerPct  = 2.00;       // Profit Gain % to Trigger 50% Equity Lock
input double         InpUnlockedBufferRiskPct = 25.0;       // % of Unlocked Profit Buffer Added to Risk
input double         InpMaxScaledRiskPct      = 1.25;       // Hard Cap on Scaled Risk Per Trade (%)
input double         InpMaxDailyDrawdownPct   = 1.50;       // Daily Loss Circuit Breaker (% of Day Start)
input int            InpMaxDailyConsecLosses  = 3;          // Max Consecutive Losses Per Day

input group "=== 4. Raw ECN Spread & Session Windows (UTC/Server) ==="
input double         InpMaxSpreadUSD          = 0.25;       // Max Allowed Live Spread ($ USD, e.g. $0.25)
input int            InpAsianStartHour        = 0;          // Asian Session Start Hour (Server Time)
input int            InpAsianEndHour          = 7;          // Asian Session End Hour (Server Time)
input bool           InpTradeLondonSession    = true;       // Trade London Open Window
input int            InpLondonStartHour       = 7;          // London Window Start Hour
input int            InpLondonEndHour         = 10;         // London Window End Hour
input bool           InpTradeNYOverlap        = true;       // Trade London-NY Overlap Window
input int            InpNYStartHour           = 12;         // NY Overlap Start Hour
input int            InpNYEndHour             = 16;         // NY Overlap End Hour
input ulong          InpMagicNumber           = 20260888;   // EA Magic Number
input int            InpSlippagePoints        = 15;         // Max Deviation in Points

//+------------------------------------------------------------------+
//| Global Objects & State Variables                                 |
//+------------------------------------------------------------------+
CTrade         g_trade;
CPositionInfo  g_posInfo;
CSymbolInfo    g_symInfo;

int            g_hEmaFastM15 = INVALID_HANDLE;
int            g_hEmaSlowM15 = INVALID_HANDLE;
int            g_hAtrM5      = INVALID_HANDLE;

datetime       g_lastTriggerBarTime = 0;
int            g_currentDayOfYear   = -1;

// Risk & Profit-Lock State
double         g_dayStartEquity     = 0.0;
double         g_baseReferenceEq    = 0.0;
double         g_lockedEquityFloor  = 0.0;
int            g_dailyConsecLosses  = 0;
bool           g_dailyHalted        = false;

// Liquidity Pool Cache
double         g_pdh                = 0.0;
double         g_pdl                = 0.0;
double         g_asianHigh          = 0.0;
double         g_asianLow           = 0.0;
double         g_h4SwingHigh        = 0.0;
double         g_h4SwingLow         = 0.0;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   if(!g_symInfo.Name(_Symbol))
      return(INIT_FAILED);
   g_symInfo.RefreshRates();

   g_trade.SetExpertMagicNumber(InpMagicNumber);
   g_trade.SetDeviationInPoints(InpSlippagePoints);
   g_trade.SetTypeFillingBySymbol(_Symbol);
   g_trade.SetAsyncMode(false);

   g_hEmaFastM15 = iMA(_Symbol, PERIOD_M15, InpEmaFast, 0, MODE_EMA, PRICE_CLOSE);
   g_hEmaSlowM15 = iMA(_Symbol, PERIOD_M15, InpEmaSlow, 0, MODE_EMA, PRICE_CLOSE);
   g_hAtrM5      = iATR(_Symbol, PERIOD_M5, InpAtrPeriod);

   if(g_hEmaFastM15 == INVALID_HANDLE || g_hEmaSlowM15 == INVALID_HANDLE || g_hAtrM5 == INVALID_HANDLE)
   {
      Print("Error creating indicator handles: ", GetLastError());
      return(INIT_FAILED);
   }

   double eq = AccountInfoDouble(ACCOUNT_EQUITY);
   g_dayStartEquity    = eq;
   g_baseReferenceEq   = eq;
   g_lockedEquityFloor = eq * (1.0 - InpMaxDailyDrawdownPct / 100.0);

   MqlDateTime dt;
   TimeCurrent(dt);
   g_currentDayOfYear = dt.day_of_year;

   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   if(g_hEmaFastM15 != INVALID_HANDLE) IndicatorRelease(g_hEmaFastM15);
   if(g_hEmaSlowM15 != INVALID_HANDLE) IndicatorRelease(g_hEmaSlowM15);
   if(g_hAtrM5      != INVALID_HANDLE) IndicatorRelease(g_hAtrM5);
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   if(!g_symInfo.RefreshRates())
      return;

   // 1. Daily Reset & Circuit Breaker Audit
   CheckDailyResetAndDrawdown();

   // 2. Manage Any Open Position (Partial Close, BE, Structural Trail, Time Stop)
   if(HasOpenPosition())
   {
      ManageOpenPositions();
      return; // One active position at a time on XAU/USD
   }

   if(g_dailyHalted)
      return;

   // 3. Evaluate Entry Signals Strictly on New Trigger Bar Close
   datetime currentBarTime = iTime(_Symbol, InpTriggerTF, 0);
   if(currentBarTime == g_lastTriggerBarTime)
      return;

   // Check Session Filter
   if(!IsWithinActiveSession())
      return;

   // Check Live Spread Filter ($ USD)
   double liveSpreadUSD = g_symInfo.Ask() - g_symInfo.Bid();
   if(liveSpreadUSD > InpMaxSpreadUSD)
      return;

   g_lastTriggerBarTime = currentBarTime;

   // 4. Refresh H4/D1 & Asian Session Liquidity Pools
   UpdateLiquidityPools();

   // 5. Fetch Indicator Values
   double emaFast[2], emaSlow[2], atrM5[2];
   if(CopyBuffer(g_hEmaFastM15, 0, 1, 2, emaFast) < 2) return;
   if(CopyBuffer(g_hEmaSlowM15, 0, 1, 2, emaSlow) < 2) return;
   if(CopyBuffer(g_hAtrM5,      0, 1, 1, atrM5)   < 1) return;

   double currentAtr = atrM5[0];
   double slPrice    = 0.0;

   // 6. Check Setup 1: Liquidity Sweep (False Breakout of Key Level)
   if(InpEnableSweepSetup)
   {
      if(CheckBullishSweep(currentAtr, slPrice))
      {
         ExecuteTrade(ORDER_TYPE_BUY, slPrice, "XAU_Sweep_Buy");
         return;
      }
      if(CheckBearishSweep(currentAtr, slPrice))
      {
         ExecuteTrade(ORDER_TYPE_SELL, slPrice, "XAU_Sweep_Sell");
         return;
      }
   }

   // 7. Check Setup 2: M15 EMA 20/50 Trend Pullback + Micro BoS
   if(InpEnablePullbackSetup)
   {
      // Note: CopyBuffer index 1 is bar [1] (most recently closed M15 bar)
      double m15Fast = emaFast[1];
      double m15Slow = emaSlow[1];

      if(CheckBullishPullback(m15Fast, m15Slow, currentAtr, slPrice))
      {
         ExecuteTrade(ORDER_TYPE_BUY, slPrice, "XAU_Pullback_Buy");
         return;
      }
      if(CheckBearishPullback(m15Fast, m15Slow, currentAtr, slPrice))
      {
         ExecuteTrade(ORDER_TYPE_SELL, slPrice, "XAU_Pullback_Sell");
         return;
      }
   }
}

//+------------------------------------------------------------------+
//| Track Closed Deals for Consecutive Losses & Profit-Lock Scaling  |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
{
   if(trans.type != TRADE_TRANSACTION_DEAL_ADD)
      return;

   if(!HistoryDealSelect(trans.deal))
      return;

   ulong  magic = (ulong)HistoryDealGetInteger(trans.deal, DEAL_MAGIC);
   string sym   = HistoryDealGetString(trans.deal, DEAL_SYMBOL);
   long   entry = HistoryDealGetInteger(trans.deal, DEAL_ENTRY);

   if(magic != InpMagicNumber || sym != _Symbol || entry != DEAL_ENTRY_OUT)
      return;

   double netProfit = HistoryDealGetDouble(trans.deal, DEAL_PROFIT)
                    + HistoryDealGetDouble(trans.deal, DEAL_COMMISSION)
                    + HistoryDealGetDouble(trans.deal, DEAL_SWAP);

   // Ignore partial closes when counting full-trade consecutive losses
   if(netProfit < -1.0)
      g_dailyConsecLosses++;
   else if(netProfit > 1.0)
      g_dailyConsecLosses = 0;

   // Update Profit-Lock Exponential Floor if threshold reached
   double eq = AccountInfoDouble(ACCOUNT_EQUITY);
   double gainPct = ((eq - g_baseReferenceEq) / g_baseReferenceEq) * 100.0;
   if(InpUseProfitLockScaling && gainPct >= InpProfitLockTriggerPct)
   {
      double gainedUSD    = eq - g_baseReferenceEq;
      g_lockedEquityFloor = g_baseReferenceEq + (gainedUSD * 0.50);
      g_baseReferenceEq   = eq;
      PrintFormat("Profit-Lock Triggered! New Locked Equity Floor: $%.2f | New Reference: $%.2f",
                  g_lockedEquityFloor, g_baseReferenceEq);
   }
}

//+------------------------------------------------------------------+
//| Daily Reset & Circuit Breaker Audit                              |
//+------------------------------------------------------------------+
void CheckDailyResetAndDrawdown()
{
   MqlDateTime dt;
   TimeCurrent(dt);
   double eq = AccountInfoDouble(ACCOUNT_EQUITY);

   if(dt.day_of_year != g_currentDayOfYear)
   {
      g_currentDayOfYear  = dt.day_of_year;
      g_dayStartEquity    = eq;
      g_dailyConsecLosses = 0;
      g_dailyHalted       = false;
   }

   if(g_dailyHalted)
      return;

   double dailyDDPct = ((g_dayStartEquity - eq) / g_dayStartEquity) * 100.0;
   if(dailyDDPct >= InpMaxDailyDrawdownPct)
   {
      g_dailyHalted = true;
      PrintFormat("Circuit Breaker: Max Daily Drawdown (%.2f%%) reached. Trading halted for today.", dailyDDPct);
   }
   else if(g_dailyConsecLosses >= InpMaxDailyConsecLosses)
   {
      g_dailyHalted = true;
      PrintFormat("Circuit Breaker: %d Consecutive Losses reached. Trading halted for today.", g_dailyConsecLosses);
   }
}

//+------------------------------------------------------------------+
//| Update PDH/PDL, Asian Session High/Low, and H4 Structural Swings |
//+------------------------------------------------------------------+
void UpdateLiquidityPools()
{
   // 1. Previous Day High & Low (D1 Bar 1)
   g_pdh = iHigh(_Symbol, PERIOD_D1, 1);
   g_pdl = iLow(_Symbol,  PERIOD_D1, 1);

   // 2. H4 Structural Swing High & Low (Last N closed H4 bars)
   int h4HighIdx = iHighest(_Symbol, PERIOD_H4, MODE_HIGH, InpH4SwingLookback, 1);
   int h4LowIdx  = iLowest(_Symbol,  PERIOD_H4, MODE_LOW,  InpH4SwingLookback, 1);
   if(h4HighIdx != -1) g_h4SwingHigh = iHigh(_Symbol, PERIOD_H4, h4HighIdx);
   if(h4LowIdx  != -1) g_h4SwingLow  = iLow(_Symbol,  PERIOD_H4, h4LowIdx);

   // 3. Asian Session High & Low (Calculated from M15 bars today)
   MqlDateTime dt;
   TimeCurrent(dt);
   dt.hour = InpAsianStartHour;
   dt.min  = 0;
   dt.sec  = 0;
   datetime asianStart = StructToTime(dt);

   dt.hour = InpAsianEndHour;
   datetime asianEnd   = StructToTime(dt);

   g_asianHigh = 0.0;
   g_asianLow  = DBL_MAX;

   for(int i = 1; i < 100; i++)
   {
      datetime barTime = iTime(_Symbol, PERIOD_M15, i);
      if(barTime < asianStart)
         break;
      if(barTime >= asianStart && barTime < asianEnd)
      {
         double h = iHigh(_Symbol, PERIOD_M15, i);
         double l = iLow(_Symbol,  PERIOD_M15, i);
         if(h > g_asianHigh) g_asianHigh = h;
         if(l < g_asianLow)  g_asianLow  = l;
      }
   }
   if(g_asianLow == DBL_MAX) g_asianLow = 0.0;
}

//+------------------------------------------------------------------+
//| Check Bullish Liquidity Sweep (False Breakout of Support)        |
//+------------------------------------------------------------------+
bool CheckBullishSweep(double atr, double &outSlPrice)
{
   double open1  = iOpen(_Symbol,  InpTriggerTF, 1);
   double close1 = iClose(_Symbol, InpTriggerTF, 1);
   double high1  = iHigh(_Symbol,  InpTriggerTF, 1);
   double low1   = iLow(_Symbol,   InpTriggerTF, 1);
   double low2   = iLow(_Symbol,   InpTriggerTF, 2);
   double high2  = iHigh(_Symbol,  InpTriggerTF, 2);

   // Require bullish displacement body on bar [1] and micro break above high[2] or strong engulfing
   double range1 = high1 - low1;
   double body1  = close1 - open1;
   if(range1 <= 0.0 || body1 <= 0.45 * range1)
      return(false);

   double sweepLow = MathMin(low1, low2);
   double levels[3] = { g_pdl, g_asianLow, g_h4SwingLow };

   for(int i = 0; i < 3; i++)
   {
      double lvl = levels[i];
      if(lvl <= 0.0) continue;

      // Price pierced below support level by up to InpMaxSweepOvershootUSD and closed back above it
      double overshoot = lvl - sweepLow;
      if(overshoot > 0.0 && overshoot <= InpMaxSweepOvershootUSD && close1 > lvl && (close1 > high2 || body1 > 0.60 * range1))
      {
         outSlPrice = sweepLow - (atr * InpAtrStopMultiplier);
         return(true);
      }
   }
   return(false);
}

//+------------------------------------------------------------------+
//| Check Bearish Liquidity Sweep (False Breakout of Resistance)     |
//+------------------------------------------------------------------+
bool CheckBearishSweep(double atr, double &outSlPrice)
{
   double open1  = iOpen(_Symbol,  InpTriggerTF, 1);
   double close1 = iClose(_Symbol, InpTriggerTF, 1);
   double high1  = iHigh(_Symbol,  InpTriggerTF, 1);
   double low1   = iLow(_Symbol,   InpTriggerTF, 1);
   double high2  = iHigh(_Symbol,  InpTriggerTF, 2);
   double low2   = iLow(_Symbol,   InpTriggerTF, 2);

   double range1 = high1 - low1;
   double body1  = open1 - close1;
   if(range1 <= 0.0 || body1 <= 0.45 * range1)
      return(false);

   double sweepHigh = MathMax(high1, high2);
   double levels[3] = { g_pdh, g_asianHigh, g_h4SwingHigh };

   for(int i = 0; i < 3; i++)
   {
      double lvl = levels[i];
      if(lvl <= 0.0) continue;

      // Price pierced above resistance level and closed decisively back below it
      double overshoot = sweepHigh - lvl;
      if(overshoot > 0.0 && overshoot <= InpMaxSweepOvershootUSD && close1 < lvl && (close1 < low2 || body1 > 0.60 * range1))
      {
         outSlPrice = sweepHigh + (atr * InpAtrStopMultiplier);
         return(true);
      }
   }
   return(false);
}

//+------------------------------------------------------------------+
//| Check Bullish Trend Pullback into M15 EMA 20/50 Zone             |
//+------------------------------------------------------------------+
bool CheckBullishPullback(double emaFast, double emaSlow, double atr, double &outSlPrice)
{
   if(emaFast <= emaSlow)
      return(false);

   double open1  = iOpen(_Symbol,  InpTriggerTF, 1);
   double close1 = iClose(_Symbol, InpTriggerTF, 1);
   double high1  = iHigh(_Symbol,  InpTriggerTF, 1);
   double low1   = iLow(_Symbol,   InpTriggerTF, 1);
   double high2  = iHigh(_Symbol,  InpTriggerTF, 2);
   double low2   = iLow(_Symbol,   InpTriggerTF, 2);

   double pullbackLow = MathMin(low1, low2);

   // Pullback touched or dipped into EMA 20 zone while holding above EMA 50, then broke above bar [2] high
   bool touchedValueZone = (pullbackLow <= emaFast + InpTouchToleranceUSD) && (pullbackLow >= emaSlow - InpTouchToleranceUSD);
   bool bullishBoS       = (close1 > open1) && (close1 > emaFast) && (close1 > high2);

   if(touchedValueZone && bullishBoS)
   {
      outSlPrice = pullbackLow - (atr * InpAtrStopMultiplier);
      return(true);
   }
   return(false);
}

//+------------------------------------------------------------------+
//| Check Bearish Trend Pullback into M15 EMA 20/50 Zone             |
//+------------------------------------------------------------------+
bool CheckBearishPullback(double emaFast, double emaSlow, double atr, double &outSlPrice)
{
   if(emaFast >= emaSlow)
      return(false);

   double open1  = iOpen(_Symbol,  InpTriggerTF, 1);
   double close1 = iClose(_Symbol, InpTriggerTF, 1);
   double high1  = iHigh(_Symbol,  InpTriggerTF, 1);
   double low1   = iLow(_Symbol,   InpTriggerTF, 1);
   double high2  = iHigh(_Symbol,  InpTriggerTF, 2);
   double low2   = iLow(_Symbol,   InpTriggerTF, 2);

   double pullbackHigh = MathMax(high1, high2);

   bool touchedValueZone = (pullbackHigh >= emaFast - InpTouchToleranceUSD) && (pullbackHigh <= emaSlow + InpTouchToleranceUSD);
   bool bearishBoS       = (close1 < open1) && (close1 < emaFast) && (close1 < low2);

   if(touchedValueZone && bearishBoS)
   {
      outSlPrice = pullbackHigh + (atr * InpAtrStopMultiplier);
      return(true);
   }
   return(false);
}

//+------------------------------------------------------------------+
//| Execute Order with Commission-Adjusted & Profit-Lock Lot Sizing  |
//+------------------------------------------------------------------+
void ExecuteTrade(ENUM_ORDER_TYPE orderType, double rawSlPrice, string comment)
{
   g_symInfo.RefreshRates();
   double entryPrice = (orderType == ORDER_TYPE_BUY) ? g_symInfo.Ask() : g_symInfo.Bid();
   double slDistUSD  = MathAbs(entryPrice - rawSlPrice);

   // Clamp Stop-Loss distance to XAU/USD structural bounds ($1.20 to $3.50)
   if(slDistUSD < InpMinStopUSD)
      slDistUSD = InpMinStopUSD;
   else if(slDistUSD > InpMaxStopUSD)
      return; // Skip trade if structural stop is too wide for a scalp

   double slPrice = (orderType == ORDER_TYPE_BUY)
                    ? NormalizeDouble(entryPrice - slDistUSD, _Digits)
                    : NormalizeDouble(entryPrice + slDistUSD, _Digits);

   double tpDistUSD = slDistUSD * InpFinalTargetRR;
   double tpPrice   = (orderType == ORDER_TYPE_BUY)
                    ? NormalizeDouble(entryPrice + tpDistUSD, _Digits)
                    : NormalizeDouble(entryPrice - tpDistUSD, _Digits);

   double lots = CalculatePositionLots(slDistUSD);
   if(lots <= 0.0)
      return;

   if(orderType == ORDER_TYPE_BUY)
      g_trade.Buy(lots, _Symbol, entryPrice, slPrice, tpPrice, comment);
   else
      g_trade.Sell(lots, _Symbol, entryPrice, slPrice, tpPrice, comment);
}

//+------------------------------------------------------------------+
//| Calculate Exact Lots Factoring ECN Commission & Profit-Lock      |
//+------------------------------------------------------------------+
double CalculatePositionLots(double slDistUSD)
{
   double eq      = AccountInfoDouble(ACCOUNT_EQUITY);
   double riskUSD = eq * (InpBaseRiskPct / 100.0);

   // Apply Exponential Profit-Lock Scaling if active and above locked floor
   if(InpUseProfitLockScaling && eq > g_lockedEquityFloor)
   {
      double unlockedProfit = MathMax(0.0, eq - g_baseReferenceEq);
      if(unlockedProfit > 0.0)
      {
         double bonusRiskUSD = unlockedProfit * (InpUnlockedBufferRiskPct / 100.0);
         double maxRiskUSD   = eq * (InpMaxScaledRiskPct / 100.0);
         riskUSD = MathMin(riskUSD + bonusRiskUSD, maxRiskUSD);
      }
   }

   double tickSize  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   if(tickSize <= 0.0 || tickValue <= 0.0)
      return(0.0);

   // Price loss per 1.0 standard lot + Round-Turn ECN Commission per 1.0 lot
   double priceLossPerLot = (slDistUSD / tickSize) * tickValue;
   double totalLossPerLot = priceLossPerLot + InpCommissionPerLotRT;
   if(totalLossPerLot <= 0.0)
      return(0.0);

   double rawLots  = riskUSD / totalLossPerLot;
   double stepLots = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double minLots  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLots  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);

   double lots = MathFloor(rawLots / stepLots) * stepLots;
   if(lots < minLots) return(0.0);
   if(lots > maxLots) lots = maxLots;

   // Verify Free Margin
   double marginRequired = 0.0;
   if(!OrderCalcMargin(ORDER_TYPE_BUY, _Symbol, lots, g_symInfo.Ask(), marginRequired) ||
      marginRequired > AccountInfoDouble(ACCOUNT_MARGIN_FREE))
   {
      Print("Insufficient free margin for calculated lot size: ", lots);
      return(0.0);
   }

   return(NormalizeDouble(lots, 2));
}

//+------------------------------------------------------------------+
//| Manage Open Positions: Partial Close, BE+Comm, Trail & Time Stop |
//+------------------------------------------------------------------+
void ManageOpenPositions()
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(!g_posInfo.SelectByIndex(i)) continue;
      if(g_posInfo.Symbol() != _Symbol || g_posInfo.Magic() != InpMagicNumber) continue;

      ulong  ticket     = g_posInfo.Ticket();
      double openPrice  = g_posInfo.PriceOpen();
      double currentSL  = g_posInfo.StopLoss();
      double currentTP  = g_posInfo.TakeProfit();
      double volume     = g_posInfo.Volume();
      ENUM_POSITION_TYPE posType = g_posInfo.PositionType();

      double currentPrice = (posType == POSITION_TYPE_BUY) ? g_symInfo.Bid() : g_symInfo.Ask();
      double profitDist   = (posType == POSITION_TYPE_BUY) ? (currentPrice - openPrice) : (openPrice - currentPrice);

      // Recover initial 1R distance from TakeProfit distance
      double initialRiskDist = (currentTP > 0.0) ? (MathAbs(currentTP - openPrice) / InpFinalTargetRR) : InpMinStopUSD;
      if(initialRiskDist <= 0.0) initialRiskDist = InpMinStopUSD;

      double currentR = profitDist / initialRiskDist;

      // 1. Time Stop Check: Close if open > InpTimeStopMinutes and profit < 0.5R
      if(InpTimeStopMinutes > 0)
      {
         int elapsedSec = (int)(TimeCurrent() - g_posInfo.Time());
         if(elapsedSec >= InpTimeStopMinutes * 60 && currentR < 0.5)
         {
            g_trade.PositionClose(ticket);
            PrintFormat("Time Stop executed on Ticket #%I64u after %d mins (R = %.2f)", ticket, InpTimeStopMinutes, currentR);
            continue;
         }
      }

      // 2. Partial Close at +1.5R & Move Stop-Loss to Breakeven + Commission Buffer
      string gvKey = "XAU_PARTIAL_" + IntegerToString(ticket);
      if(currentR >= InpPartialCloseRR && !GlobalVariableCheck(gvKey))
      {
         double stepLots  = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
         double minLots   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
         double closeLots = MathFloor((volume * InpPartialCloseRatio) / stepLots) * stepLots;

         if(closeLots >= minLots && (volume - closeLots) >= minLots)
            g_trade.PositionClosePartial(ticket, NormalizeDouble(closeLots, 2));

         // Move SL to Breakeven + $0.15 Commission/Spread Offset
         double commOffsetUSD = 0.15;
         double newSL = (posType == POSITION_TYPE_BUY)
                        ? NormalizeDouble(openPrice + commOffsetUSD, _Digits)
                        : NormalizeDouble(openPrice - commOffsetUSD, _Digits);

         if((posType == POSITION_TYPE_BUY && newSL > currentSL) ||
            (posType == POSITION_TYPE_SELL && (currentSL == 0.0 || newSL < currentSL)))
         {
            g_trade.PositionModify(ticket, newSL, currentTP);
         }

         GlobalVariableSet(gvKey, 1.0);
      }

      // 3. M15 Structural Trailing Stop once trade reaches +2.0R
      if(currentR >= InpTrailStartRR)
      {
         double trailBuffer = 0.20; // $0.20 buffer beyond last closed M15 candle
         if(posType == POSITION_TYPE_BUY)
         {
            double m15Low = iLow(_Symbol, PERIOD_M15, 1) - trailBuffer;
            double newSL  = NormalizeDouble(m15Low, _Digits);
            if(newSL > currentSL && newSL < currentPrice)
               g_trade.PositionModify(ticket, newSL, currentTP);
         }
         else
         {
            double m15High = iHigh(_Symbol, PERIOD_M15, 1) + trailBuffer;
            double newSL   = NormalizeDouble(m15High, _Digits);
            if((currentSL == 0.0 || newSL < currentSL) && newSL > currentPrice)
               g_trade.PositionModify(ticket, newSL, currentTP);
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Helper: Check if EA Has an Active Open Position on Symbol        |
//+------------------------------------------------------------------+
bool HasOpenPosition()
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(g_posInfo.SelectByIndex(i))
         if(g_posInfo.Symbol() == _Symbol && g_posInfo.Magic() == InpMagicNumber)
            return(true);
   }
   return(false);
}

//+------------------------------------------------------------------+
//| Helper: Verify Active London or NY Overlap Window                |
//+------------------------------------------------------------------+
bool IsWithinActiveSession()
{
   MqlDateTime dt;
   TimeCurrent(dt);

   bool inLondon = InpTradeLondonSession && (dt.hour >= InpLondonStartHour && dt.hour < InpLondonEndHour);
   bool inNY     = InpTradeNYOverlap     && (dt.hour >= InpNYStartHour     && dt.hour < InpNYEndHour);

   return(inLondon || inNY);
}
//+------------------------------------------------------------------+