Advertisement IC Markets

Forex scalping trading strategy for Gold (XAU/USD)

Share, develop, and backtest custom MQL4/MQL5 Expert Advisors, Python data-scraping scripts, trading bots, and automated market alert systems.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

Forex scalping trading strategy for Gold (XAU/USD)

Post 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).
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: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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.
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
PTScalper
Site Admin
Posts: 7643
Joined: Mon Jul 20, 2026 1:28 pm

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

Post 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);
}
//+------------------------------------------------------------------+
Preserve your own money. Scale with the market's money. Exponential growth is the ultimate key.
Post Reply