Open MetaEditor 5 (F4), create a new Expert Advisor named XAUUSD_AutonomousEngine.mq5, and paste the complete source code below:
Code: Select all
//+------------------------------------------------------------------+
//| XAUUSD_AutonomousEngine.mq5 |
//| 100% Autonomous D1/H4/M15 Liquidity Sweep & Scaling Engine |
//+------------------------------------------------------------------+
#property copyright "Autonomous Institutional XAUUSD Engine v3.0"
#property version "3.00"
#property strict
#include <Trade\Trade.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\SymbolInfo.mqh>
//--- 1. Autonomous GMT Session & Friday Flat Controls
input group "=== 1. Autonomous GMT Clock & Session Windows ==="
input ulong InpMagicNumber = 20261099; // Autonomous EA Magic Number
input bool InpUseLondonSession = true; // Trade London Window (07:00 - 10:30 GMT)
input int InpLondonStartHourGMT = 7; // London Start Hour (GMT)
input int InpLondonEndHourGMT = 11; // London End Hour (GMT)
input bool InpUseNYOverlapSession = true; // Trade NY Overlap Window (12:00 - 16:30 GMT)
input int InpNYStartHourGMT = 12; // NY Start Hour (GMT)
input int InpNYEndHourGMT = 17; // NY End Hour (GMT)
input bool InpFridayAutoFlat = true; // Auto-Close All Trades & Orders Friday Evening
input int InpFridayFlatHourGMT = 20; // Friday Flat Hour (GMT)
input int InpFridayFlatMinuteGMT = 30; // Friday Flat Minute (GMT)
input double InpMaxSpreadUSD = 0.35; // Max Allowed ECN Spread in USD ($0.35 = 3.5 pips)
//--- 2. Native MQL5 Economic Calendar News Filter
input group "=== 2. Built-In High-Impact USD News Shield ==="
input bool InpUseNewsFilter = true; // Enable Native MT5 Calendar USD News Filter
input int InpNewsBlockBeforeMin = 15; // Minutes Before High-Impact USD News to Block/Cancel
input int InpNewsBlockAfterMin = 15; // Minutes After High-Impact USD News to Resume
input bool InpLockBEBeforeNews = true; // Auto-Lock Profitable Trades (>= 0.5R) to BE Before News
//--- 3. Multi-Timeframe D1 / H4 / M15 Institutional Structure
input group "=== 3. D1 / H4 / M15 Structural & Sweep Parameters ==="
input bool InpUseD1TrendFilter = true; // Require D1 EMA(20) Bias (Overridden on PDH/PDL Sweep)
input int InpH4LookbackBars = 45; // H4 Lookback Bars for S/R Pivots & Unmitigated FVGs
input int InpM15SwingLookback = 12; // M15 Lookback Bars for Liquidity High/Low
input double InpH4ZoneToleranceUSD = 3.50; // Proximity Tolerance to H4 Zone / PDH / PDL ($ USD)
input double InpMinSweepUSD = 0.40; // Min M15 Liquidity Sweep Depth ($ USD)
input double InpMaxSweepUSD = 4.80; // Max M15 Liquidity Sweep Depth ($ USD)
input double InpMinWickRatio = 0.40; // Min Rejection Wick Ratio for 1-Bar Sweep (0.0 - 1.0)
//--- 4. Pullback Limit Execution & Asymmetric Trade Management
input group "=== 4. Pullback Limit Order & +1R/+2R Management ==="
input bool InpUsePullbackLimit = true; // Place BuyLimit/SellLimit at Retracement (False = Market)
input double InpRetraceEntryRatio = 0.50; // Displacement Candle Retracement Entry Ratio (0.50 = 50%)
input int InpLimitExpiryM15Bars = 3; // Auto-Expire Unfilled Limit Orders After N M15 Bars
input double InpCancelLimitAtR = 1.50; // Auto-Cancel Unfilled Limit If Price Runs to +R
input double InpSLBufferUSD = 0.85; // Hard SL Buffer Beyond Sweep Wick ($ USD)
input double InpMinSLDistanceUSD = 1.80; // Min Allowed Stop-Loss Distance ($ USD)
input double InpMaxSLDistanceUSD = 6.50; // Max Allowed Stop-Loss Distance ($ USD)
input double InpTargetRMultiple = 3.00; // Final Take-Profit Target (R-Multiple)
input double InpPartialCloseAtR = 1.00; // Trigger Partial Close & Breakeven Lock at +R
input double InpPartialCloseRatio = 0.50; // Fraction of Volume to Bank at +1R (0.50 = 50%)
input double InpBECommissionUSD = 0.25; // Breakeven Plus ECN Commission Buffer ($ USD)
input double InpTrailTriggerR = 2.00; // Activate 3-Bar M15 Structural Trailing Stop at +R
//--- 5. House-Money Scaling & Equity Circuit Breakers
input group "=== 5. House-Money Scaling & Circuit Breakers ==="
input double InpBaseRiskPct = 0.50; // Base Risk Per Trade (% of Daily Starting Balance)
input double InpReinvestProfitPct = 50.0; // % of Today's Realized Net Profit Added to Next Risk
input double InpMaxTotalRiskPct = 2.50; // Max Cap on Risk Per Trade (% of Account Equity)
input double InpMaxDailyDrawdownPct = 2.00; // Hard Daily Equity Drawdown Breaker (%)
input int InpMaxConsecutiveLosses = 2; // Max Consecutive Losses Per Day Before Shutdown
input bool InpShowChartHUD = true; // Render Real-Time Autonomous Telemetry HUD on Chart
//--- Global Engine State
CTrade ExtTrade;
CPositionInfo ExtPosition;
COrderInfo ExtOrder;
CSymbolInfo ExtSymbol;
int ExtHandleD1Ema = INVALID_HANDLE;
datetime ExtLastM15BarTime = 0;
datetime ExtCurrentDayStart = 0;
double ExtDayStartBalance = 0.0;
bool ExtDailyBreakerTripped= false;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
if(!ExtSymbol.Name(_Symbol))
return(INIT_FAILED);
ExtSymbol.RefreshRates();
ExtTrade.SetExpertMagicNumber(InpMagicNumber);
ExtTrade.SetMarginMode();
ExtTrade.SetTypeFillingBySymbol(_Symbol);
ExtTrade.SetDeviationInPoints(25);
ExtHandleD1Ema = iMA(_Symbol, PERIOD_D1, 20, 0, MODE_EMA, PRICE_CLOSE);
if(ExtHandleD1Ema == INVALID_HANDLE)
{
Print("Failed to initialize D1 EMA(20) handle. Error: ", GetLastError());
return(INIT_FAILED);
}
ExtCurrentDayStart = iTime(_Symbol, PERIOD_D1, 0);
ExtDayStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
ExtDailyBreakerTripped = false;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
if(ExtHandleD1Ema != INVALID_HANDLE)
IndicatorRelease(ExtHandleD1Ema);
Comment("");
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
if(!ExtSymbol.RefreshRates())
return;
// 1. Check Daily Rollover Reset & Hard Equity Drawdown Circuit Breaker
UpdateDailyBaselineAndCheckDrawdown();
if(ExtDailyBreakerTripped)
{
if(InpShowChartHUD)
RenderTelemetryHUD("DAILY DRAWDOWN BREAKER TRIPPED - LOCKED UNTIL D1 ROLLOVER", false, 0.0, 0);
return;
}
// 2. Check Friday Evening Autonomous Flat Protection
if(IsFridayCutoffReached())
{
CloseAllPositionsAndDeleteOrders("Friday GMT Cutoff");
if(InpShowChartHUD)
RenderTelemetryHUD("FRIDAY EVENING GMT CUTOFF - FLAT FOR WEEKEND", false, 0.0, 0);
return;
}
// 3. Tick-Level Management of Open Positions (+1R Partial, BE Lock, +2R Trail)
ManageOpenPositions();
// 4. Tick-Level Management of Pending Pullback Limit Orders
ManagePendingLimitOrders();
// 5. Evaluate Built-In High-Impact USD News Filter
string activeNewsName = "";
bool isNewsBlackout = IsHighImpactUSDNewsWindow(activeNewsName);
if(isNewsBlackout)
{
DeleteAllPendingOrders();
if(InpLockBEBeforeNews)
HardenStopsBeforeNews();
int losses = 0;
double pnl = GetTodayRealizedStats(losses);
if(InpShowChartHUD)
RenderTelemetryHUD("USD HIGH-IMPACT NEWS SHIELD: " + activeNewsName, true, pnl, losses);
return;
}
// 6. Verify Active GMT Session Window (London or NY Overlap)
string sessionStatus = "";
bool inSession = IsInsideGMTSession(sessionStatus);
int consecutiveLosses = 0;
double realizedPnLToday = GetTodayRealizedStats(consecutiveLosses);
if(InpShowChartHUD)
RenderTelemetryHUD(sessionStatus, false, realizedPnLToday, consecutiveLosses);
if(!inSession)
return;
if(consecutiveLosses >= InpMaxConsecutiveLosses)
return;
// 7. New M15 Closed Bar Evaluation for Autonomous Entries
datetime currentM15Bar = iTime(_Symbol, PERIOD_M15, 0);
if(currentM15Bar == ExtLastM15BarTime)
return;
// Check ECN Spread Filter before marking bar as evaluated
double currentSpreadUSD = ExtSymbol.Ask() - ExtSymbol.Bid();
if(currentSpreadUSD > InpMaxSpreadUSD)
return;
ExtLastM15BarTime = currentM15Bar;
// Only allow a new setup (or House-Money Pyramid) when no unprotected trade or pending order exists
if(HasUnprotectedPositionOrPendingOrder())
return;
// 8. Run 2-Stage M15 Liquidity Sweep + Break of Structure Engine
EvaluateM15InstitutionalTrap(realizedPnLToday);
}
//+------------------------------------------------------------------+
//| Track New Trading Day & Enforce Hard Daily Drawdown Breaker |
//+------------------------------------------------------------------+
void UpdateDailyBaselineAndCheckDrawdown()
{
datetime todayStart = iTime(_Symbol, PERIOD_D1, 0);
if(todayStart != ExtCurrentDayStart)
{
ExtCurrentDayStart = todayStart;
ExtDayStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
ExtDailyBreakerTripped = false;
}
if(ExtDayStartBalance <= 0.0)
return;
double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
double ddPct = ((ExtDayStartBalance - currentEquity) / ExtDayStartBalance) * 100.0;
if(ddPct >= InpMaxDailyDrawdownPct)
{
CloseAllPositionsAndDeleteOrders("Max Daily Drawdown Breaker");
ExtDailyBreakerTripped = true;
}
}
//+------------------------------------------------------------------+
//| Check if Friday GMT Flat Window is Reached |
//+------------------------------------------------------------------+
bool IsFridayCutoffReached()
{
if(!InpFridayAutoFlat)
return(false);
MqlDateTime gmt;
TimeGMT(gmt);
if(gmt.day_of_week == 5)
{
if(gmt.hour > InpFridayFlatHourGMT ||
(gmt.hour == InpFridayFlatHourGMT && gmt.min >= InpFridayFlatMinuteGMT))
return(true);
}
return(false);
}
//+------------------------------------------------------------------+
//| Check if Current GMT Time is Inside London or NY Overlap |
//+------------------------------------------------------------------+
bool IsInsideGMTSession(string &outStatus)
{
MqlDateTime gmt;
TimeGMT(gmt);
// Block late NY rollover (21:00 - 23:59 GMT) and Weekend
if(gmt.day_of_week == 0 || gmt.day_of_week == 6)
{
outStatus = "WEEKEND STANDBY";
return(false);
}
bool inLondon = (InpUseLondonSession && gmt.hour >= InpLondonStartHourGMT && gmt.hour < InpLondonEndHourGMT);
bool inNY = (InpUseNYOverlapSession && gmt.hour >= InpNYStartHourGMT && gmt.hour < InpNYEndHourGMT);
if(inLondon && inNY)
{
outStatus = "ACTIVE: LONDON + NY OVERLAP (GMT)";
return(true);
}
if(inLondon)
{
outStatus = "ACTIVE: LONDON SESSION (GMT)";
return(true);
}
if(inNY)
{
outStatus = "ACTIVE: NEW YORK SESSION (GMT)";
return(true);
}
outStatus = "STANDBY: OUTSIDE PEAK LIQUIDITY WINDOWS (GMT)";
return(false);
}
//+------------------------------------------------------------------+
//| Built-In MQL5 Economic Calendar High-Impact USD News Filter |
//+------------------------------------------------------------------+
bool IsHighImpactUSDNewsWindow(string &outEventName)
{
outEventName = "";
if(!InpUseNewsFilter)
return(false);
// Strategy Tester does not always populate live CalendarValueHistory on all brokers
if(MQLInfoInteger(MQL_TESTER))
return(false);
datetime nowServer = TimeCurrent();
datetime fromWindow = nowServer - (InpNewsBlockAfterMin * 60);
datetime toWindow = nowServer + (InpNewsBlockBeforeMin * 60);
MqlCalendarValue values[];
int count = CalendarValueHistory(values, fromWindow, toWindow, NULL, "USD");
if(count <= 0)
return(false);
for(int i = 0; i < count; i++)
{
MqlCalendarEvent eventInfo;
if(CalendarEventById(values[i].event_id, eventInfo))
{
if(eventInfo.importance == CALENDAR_IMPORTANCE_HIGH)
{
outEventName = eventInfo.name;
return(true);
}
}
}
return(false);
}
//+------------------------------------------------------------------+
//| Protect Open Profitable Positions (>= 0.5R) Ahead of Tier-1 News |
//+------------------------------------------------------------------+
void HardenStopsBeforeNews()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(!ExtPosition.SelectByIndex(i))
continue;
if(ExtPosition.Symbol() != _Symbol || ExtPosition.Magic() != InpMagicNumber)
continue;
double openPrice = ExtPosition.PriceOpen();
double currentSL = ExtPosition.StopLoss();
double currentTP = ExtPosition.TakeProfit();
bool isBuy = (ExtPosition.PositionType() == POSITION_TYPE_BUY);
bool isLockedAtBE = isBuy ? (currentSL >= openPrice) : (currentSL <= openPrice && currentSL > 0.0);
if(isLockedAtBE)
continue;
double oneR = ExtractInitialOneR(openPrice, currentSL, currentTP, ExtPosition.Comment());
double gainUSD = isBuy ? (ExtSymbol.Bid() - openPrice) : (openPrice - ExtSymbol.Ask());
if(oneR > 0.0 && gainUSD >= (oneR * 0.50))
{
double safeSL = isBuy ? NormalizeDouble(openPrice + InpBECommissionUSD, _Digits)
: NormalizeDouble(openPrice - InpBECommissionUSD, _Digits);
ExtTrade.PositionModify(ExtPosition.Ticket(), safeSL, currentTP);
}
}
}
//+------------------------------------------------------------------+
//| Check for Unprotected Open Position or Active Pending Order |
//+------------------------------------------------------------------+
bool HasUnprotectedPositionOrPendingOrder()
{
// 1. Check active pending orders
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!ExtOrder.SelectByIndex(i))
continue;
if(ExtOrder.Symbol() == _Symbol && ExtOrder.Magic() == InpMagicNumber)
return(true);
}
// 2. Check open positions whose SL is not yet locked at Breakeven+
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(!ExtPosition.SelectByIndex(i))
continue;
if(ExtPosition.Symbol() != _Symbol || ExtPosition.Magic() != InpMagicNumber)
continue;
double openPrice = ExtPosition.PriceOpen();
double sl = ExtPosition.StopLoss();
if(ExtPosition.PositionType() == POSITION_TYPE_BUY && (sl < openPrice || sl == 0.0))
return(true);
if(ExtPosition.PositionType() == POSITION_TYPE_SELL && (sl > openPrice || sl == 0.0))
return(true);
}
return(false);
}
//+------------------------------------------------------------------+
//| Close All EA Positions & Delete Pending Orders |
//+------------------------------------------------------------------+
void CloseAllPositionsAndDeleteOrders(string reason)
{
DeleteAllPendingOrders();
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(!ExtPosition.SelectByIndex(i))
continue;
if(ExtPosition.Symbol() == _Symbol && ExtPosition.Magic() == InpMagicNumber)
ExtTrade.PositionClose(ExtPosition.Ticket());
}
}
//+------------------------------------------------------------------+
//| Delete All Active Pending Limit Orders for This EA |
//+------------------------------------------------------------------+
void DeleteAllPendingOrders()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!ExtOrder.SelectByIndex(i))
continue;
if(ExtOrder.Symbol() == _Symbol && ExtOrder.Magic() == InpMagicNumber)
ExtTrade.OrderDelete(ExtOrder.Ticket());
}
}
//+------------------------------------------------------------------+
//| Manage Pending Limit Orders (Auto-Cancel If Target Reached Early)|
//+------------------------------------------------------------------+
void ManagePendingLimitOrders()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(!ExtOrder.SelectByIndex(i))
continue;
if(ExtOrder.Symbol() != _Symbol || ExtOrder.Magic() != InpMagicNumber)
continue;
double orderPrice = ExtOrder.PriceOpen();
double orderSL = ExtOrder.StopLoss();
if(orderSL <= 0.0)
continue;
double oneR = MathAbs(orderPrice - orderSL);
ENUM_ORDER_TYPE type = ExtOrder.OrderType();
// If price runs +1.5R away from limit price before filling, thesis is front-run -> cancel
if(type == ORDER_TYPE_BUY_LIMIT)
{
if(ExtSymbol.Bid() >= orderPrice + (oneR * InpCancelLimitAtR))
ExtTrade.OrderDelete(ExtOrder.Ticket());
}
else if(type == ORDER_TYPE_SELL_LIMIT)
{
if(ExtSymbol.Ask() <= orderPrice - (oneR * InpCancelLimitAtR))
ExtTrade.OrderDelete(ExtOrder.Ticket());
}
}
}
//+------------------------------------------------------------------+
//| Scan H4 Swing S/R, H4 Unmitigated FVG, and D1 PDH/PDL |
//+------------------------------------------------------------------+
bool IsNearH4OrDailyStructure(double testPrice, bool isBullish, bool &outSweptDailyExtreme)
{
outSweptDailyExtreme = false;
double pdh = iHigh(_Symbol, PERIOD_D1, 1);
double pdl = iLow(_Symbol, PERIOD_D1, 1);
// 1. Check Previous Day High / Low Liquidity Pool
if(isBullish && MathAbs(testPrice - pdl) <= InpH4ZoneToleranceUSD)
{
outSweptDailyExtreme = true;
return(true);
}
if(!isBullish && MathAbs(testPrice - pdh) <= InpH4ZoneToleranceUSD)
{
outSweptDailyExtreme = true;
return(true);
}
// 2. Scan H4 Fractal Swing Pivots and H4 3-Candle Fair Value Gaps (FVG)
for(int i = 2; i <= InpH4LookbackBars; i++)
{
double h4HighPrev = iHigh(_Symbol, PERIOD_H4, i + 1);
double h4LowPrev = iLow(_Symbol, PERIOD_H4, i + 1);
double h4HighCurr = iHigh(_Symbol, PERIOD_H4, i);
double h4LowCurr = iLow(_Symbol, PERIOD_H4, i);
double h4HighNext = iHigh(_Symbol, PERIOD_H4, i - 1);
double h4LowNext = iLow(_Symbol, PERIOD_H4, i - 1);
if(isBullish)
{
// A. H4 Swing Low Pivot
if(h4LowCurr <= h4LowPrev && h4LowCurr <= h4LowNext)
{
if(MathAbs(testPrice - h4LowCurr) <= InpH4ZoneToleranceUSD)
return(true);
}
// B. Bullish H4 Fair Value Gap (Imbalance between Bar i+1 High and Bar i-1 Low)
if(h4LowNext > h4HighPrev)
{
if(testPrice >= (h4HighPrev - InpH4ZoneToleranceUSD) &&
testPrice <= (h4LowNext + InpH4ZoneToleranceUSD))
return(true);
}
}
else
{
// A. H4 Swing High Pivot
if(h4HighCurr >= h4HighPrev && h4HighCurr >= h4HighNext)
{
if(MathAbs(testPrice - h4HighCurr) <= InpH4ZoneToleranceUSD)
return(true);
}
// B. Bearish H4 Fair Value Gap (Imbalance between Bar i+1 Low and Bar i-1 High)
if(h4HighNext < h4LowPrev)
{
if(testPrice <= (h4LowPrev + InpH4ZoneToleranceUSD) &&
testPrice >= (h4HighNext - InpH4ZoneToleranceUSD))
return(true);
}
}
}
return(false);
}
//+------------------------------------------------------------------+
//| 2-Stage M15 Sweep + Displacement / Micro-BoS Detection Engine |
//+------------------------------------------------------------------+
void EvaluateM15InstitutionalTrap(double realizedPnLToday)
{
// Inspect M15 Bar 1 (just closed) and Bar 2 (prior closed bar)
double open1 = iOpen(_Symbol, PERIOD_M15, 1);
double high1 = iHigh(_Symbol, PERIOD_M15, 1);
double low1 = iLow(_Symbol, PERIOD_M15, 1);
double close1 = iClose(_Symbol, PERIOD_M15, 1);
double range1 = high1 - low1;
double open2 = iOpen(_Symbol, PERIOD_M15, 2);
double high2 = iHigh(_Symbol, PERIOD_M15, 2);
double low2 = iLow(_Symbol, PERIOD_M15, 2);
double close2 = iClose(_Symbol, PERIOD_M15, 2);
if(range1 < 0.45)
return;
// Identify prior M15 Liquidity Pool (Bars 3 to InpM15SwingLookback + 2)
double priorLiquidityLow = DBL_MAX;
double priorLiquidityHigh = 0.0;
for(int i = 3; i <= InpM15SwingLookback + 2; i++)
{
double l = iLow(_Symbol, PERIOD_M15, i);
double h = iHigh(_Symbol, PERIOD_M15, i);
if(l < priorLiquidityLow) priorLiquidityLow = l;
if(h > priorLiquidityHigh) priorLiquidityHigh = h;
}
// D1 Trend Filter via 20-day EMA
double d1Ema[];
ArraySetAsSeries(d1Ema, true);
bool d1Bullish = true;
bool d1Bearish = true;
if(InpUseD1TrendFilter && CopyBuffer(ExtHandleD1Ema, 0, 0, 1, d1Ema) == 1)
{
d1Bullish = (close1 >= d1Ema[0]);
d1Bearish = (close1 <= d1Ema[0]);
}
// =================================================================
// 1. BULLISH INSTITUTIONAL SWEEP + DISPLACEMENT / MICRO-BOS
// =================================================================
double bullTrapLow = MathMin(low1, low2);
double bullSweepSize = priorLiquidityLow - bullTrapLow;
// Pattern A: 1-Bar Sweep & Engulfing Rejection on Bar 1
double lowerWick1 = MathMin(open1, close1) - low1;
bool bullPattern1 = (low1 < priorLiquidityLow &&
close1 > priorLiquidityLow &&
close1 > open1 &&
(lowerWick1 / range1) >= InpMinWickRatio);
// Pattern B: 2-Bar Sweep (Bar 2 sweeps, Bar 1 confirms Micro-BoS & Engulfs Bar 2)
bool bullPattern2 = (low2 < priorLiquidityLow &&
close1 > priorLiquidityLow &&
close1 > high2 &&
close1 > open1);
if((bullPattern1 || bullPattern2) &&
bullSweepSize >= InpMinSweepUSD && bullSweepSize <= InpMaxSweepUSD)
{
bool sweptDaily = false;
if(IsNearH4OrDailyStructure(bullTrapLow, true, sweptDaily))
{
if(d1Bullish || sweptDaily)
{
ExecuteAutonomousSetup(true, bullTrapLow, low1, high1, realizedPnLToday);
return;
}
}
}
// =================================================================
// 2. BEARISH INSTITUTIONAL SWEEP + DISPLACEMENT / MICRO-BOS
// =================================================================
double bearTrapHigh = MathMax(high1, high2);
double bearSweepSize = bearTrapHigh - priorLiquidityHigh;
// Pattern A: 1-Bar Sweep & Engulfing Rejection on Bar 1
double upperWick1 = high1 - MathMax(open1, close1);
bool bearPattern1 = (high1 > priorLiquidityHigh &&
close1 < priorLiquidityHigh &&
close1 < open1 &&
(upperWick1 / range1) >= InpMinWickRatio);
// Pattern B: 2-Bar Sweep (Bar 2 sweeps, Bar 1 confirms Micro-BoS & Breaks Bar 2 Low)
bool bearPattern2 = (high2 > priorLiquidityHigh &&
close1 < priorLiquidityHigh &&
close1 < low2 &&
close1 < open1);
if((bearPattern1 || bearPattern2) &&
bearSweepSize >= InpMinSweepUSD && bearSweepSize <= InpMaxSweepUSD)
{
bool sweptDaily = false;
if(IsNearH4OrDailyStructure(bearTrapHigh, false, sweptDaily))
{
if(d1Bearish || sweptDaily)
{
ExecuteAutonomousSetup(false, bearTrapHigh, low1, high1, realizedPnLToday);
return;
}
}
}
}
//+------------------------------------------------------------------+
//| Place Pullback Limit Order (or Market Order) with Exact 1R Tag |
//+------------------------------------------------------------------+
void ExecuteAutonomousSetup(bool isBuy, double trapExtremePrice, double bar1Low, double bar1High, double realizedPnLToday)
{
double ask = ExtSymbol.Ask();
double bid = ExtSymbol.Bid();
double stopsLevel = MathMax(SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL) * _Point, 0.20);
double slPrice = isBuy ? NormalizeDouble(trapExtremePrice - InpSLBufferUSD, _Digits)
: NormalizeDouble(trapExtremePrice + InpSLBufferUSD, _Digits);
// Calculate ideal 50% displacement pullback entry price
double dispRange = bar1High - bar1Low;
double limitPrice = isBuy ? NormalizeDouble(bar1High - (dispRange * InpRetraceEntryRatio), _Digits)
: NormalizeDouble(bar1Low + (dispRange * InpRetraceEntryRatio), _Digits);
bool useLimitOrder = InpUsePullbackLimit;
// Verify whether limitPrice is valid relative to current market price & stops level
if(isBuy && limitPrice >= (ask - stopsLevel))
useLimitOrder = false;
if(!isBuy && limitPrice <= (bid + stopsLevel))
useLimitOrder = false;
double execPrice = useLimitOrder ? limitPrice : (isBuy ? ask : bid);
double slDistUSD = isBuy ? (execPrice - slPrice) : (slPrice - execPrice);
if(slDistUSD < InpMinSLDistanceUSD || slDistUSD > InpMaxSLDistanceUSD)
return;
double tpPrice = isBuy ? NormalizeDouble(execPrice + (slDistUSD * InpTargetRMultiple), _Digits)
: NormalizeDouble(execPrice - (slDistUSD * InpTargetRMultiple), _Digits);
double lots = CalculateHouseMoneyLots(slDistUSD, realizedPnLToday);
if(lots <= 0.0)
return;
// Encode exact 1R USD distance in comment for state-persistent Phase 2 management
string orderComment = StringFormat("XAU_AUTO|R:%.2f", slDistUSD);
datetime expiryTime = TimeCurrent() + (InpLimitExpiryM15Bars * 15 * 60);
if(useLimitOrder)
{
if(isBuy)
ExtTrade.BuyLimit(lots, execPrice, _Symbol, slPrice, tpPrice, ORDER_TIME_SPECIFIED, expiryTime, orderComment);
else
ExtTrade.SellLimit(lots, execPrice, _Symbol, slPrice, tpPrice, ORDER_TIME_SPECIFIED, expiryTime, orderComment);
}
else
{
if(isBuy)
ExtTrade.Buy(lots, _Symbol, execPrice, slPrice, tpPrice, orderComment);
else
ExtTrade.Sell(lots, _Symbol, execPrice, slPrice, tpPrice, orderComment);
}
}
//+------------------------------------------------------------------+
//| House-Money Position Sizing (Base Risk + Realized Daily Profit) |
//+------------------------------------------------------------------+
double CalculateHouseMoneyLots(double slDistanceUSD, double realizedPnLToday)
{
if(slDistanceUSD <= 0.0)
return(0.0);
double baseBalance = (ExtDayStartBalance > 0.0) ? ExtDayStartBalance : AccountInfoDouble(ACCOUNT_BALANCE);
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double totalRiskUSD = baseBalance * (InpBaseRiskPct / 100.0);
// Scale position size strictly from today's locked-in realized profits
if(realizedPnLToday > 0.0 && InpReinvestProfitPct > 0.0)
totalRiskUSD += (realizedPnLToday * (InpReinvestProfitPct / 100.0));
double maxCapUSD = equity * (InpMaxTotalRiskPct / 100.0);
if(totalRiskUSD > maxCapUSD)
totalRiskUSD = maxCapUSD;
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);
double lossPerLot = (slDistanceUSD / tickSize) * tickValue;
if(lossPerLot <= 0.0)
return(0.0);
double rawLots = totalRiskUSD / lossPerLot;
double volStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double volMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double volMax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double normLots = MathFloor(rawLots / volStep) * volStep;
if(normLots < volMin)
return(0.0);
if(normLots > volMax)
normLots = volMax;
return(NormalizeDouble(normLots, 2));
}
//+------------------------------------------------------------------+
//| Extract Exact 1R Distance from Order Comment or TP Distance |
//+------------------------------------------------------------------+
double ExtractInitialOneR(double openPrice, double currentSL, double currentTP, string comment)
{
int pos = StringFind(comment, "R:");
if(pos >= 0)
{
string rStr = StringSubstr(comment, pos + 2);
double parsedR = StringToDouble(rStr);
if(parsedR >= 0.50)
return(parsedR);
}
if(currentTP > 0.0 && InpTargetRMultiple > 0.0)
return(MathAbs(currentTP - openPrice) / InpTargetRMultiple);
if(currentSL > 0.0)
return(MathAbs(openPrice - currentSL));
return(2.50);
}
//+------------------------------------------------------------------+
//| Autonomous Position Management (+1R Partial/BE & +2R M15 Trail) |
//+------------------------------------------------------------------+
void ManageOpenPositions()
{
double volStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double volMin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
if(!ExtPosition.SelectByIndex(i))
continue;
if(ExtPosition.Symbol() != _Symbol || ExtPosition.Magic() != InpMagicNumber)
continue;
ulong ticket = ExtPosition.Ticket();
double openPrice = ExtPosition.PriceOpen();
double currentSL = ExtPosition.StopLoss();
double currentTP = ExtPosition.TakeProfit();
double volume = ExtPosition.Volume();
bool isBuy = (ExtPosition.PositionType() == POSITION_TYPE_BUY);
if(currentSL <= 0.0)
continue;
double oneR = ExtractInitialOneR(openPrice, currentSL, currentTP, ExtPosition.Comment());
double currentGainUSD= isBuy ? (ExtSymbol.Bid() - openPrice) : (openPrice - ExtSymbol.Ask());
bool isLockedAtBE = isBuy ? (currentSL >= openPrice) : (currentSL <= openPrice);
// --- STAGE 1: +1R Partial Profit & Breakeven+Commission Lock ---
if(!isLockedAtBE)
{
if(currentGainUSD >= (oneR * InpPartialCloseAtR))
{
double closeVol = MathFloor((volume * InpPartialCloseRatio) / volStep) * volStep;
double remVol = volume - closeVol;
if(closeVol >= volMin && remVol >= volMin)
ExtTrade.PositionClosePartial(ticket, NormalizeDouble(closeVol, 2));
double newSL = isBuy ? NormalizeDouble(openPrice + InpBECommissionUSD, _Digits)
: NormalizeDouble(openPrice - InpBECommissionUSD, _Digits);
ExtTrade.PositionModify(ticket, newSL, currentTP);
}
}
// --- STAGE 2: +2R Structural 3-Bar M15 Swing Trailing Stop ---
else
{
if(currentGainUSD < (oneR * InpTrailTriggerR))
continue;
if(isBuy)
{
double structureLow = MathMin(iLow(_Symbol, PERIOD_M15, 1),
MathMin(iLow(_Symbol, PERIOD_M15, 2), iLow(_Symbol, PERIOD_M15, 3)));
double candidateSL = NormalizeDouble(structureLow - 0.30, _Digits);
if(candidateSL > currentSL + 0.10 && candidateSL < (ExtSymbol.Bid() - InpMinSLDistanceUSD))
ExtTrade.PositionModify(ticket, candidateSL, currentTP);
}
else
{
double structureHigh = MathMax(iHigh(_Symbol, PERIOD_M15, 1),
MathMax(iHigh(_Symbol, PERIOD_M15, 2), iHigh(_Symbol, PERIOD_M15, 3)));
double candidateSL = NormalizeDouble(structureHigh + 0.30, _Digits);
if(candidateSL < currentSL - 0.10 && candidateSL > (ExtSymbol.Ask() + InpMinSLDistanceUSD))
ExtTrade.PositionModify(ticket, candidateSL, currentTP);
}
}
}
}
//+------------------------------------------------------------------+
//| Calculate Today's Realized Net PnL and Consecutive Loss Streak |
//+------------------------------------------------------------------+
double GetTodayRealizedStats(int &outConsecutiveLosses)
{
outConsecutiveLosses = 0;
double netPnL = 0.0;
datetime startOfDay = iTime(_Symbol, PERIOD_D1, 0);
if(!HistorySelect(startOfDay, TimeCurrent()))
return(0.0);
int totalDeals = HistoryDealsTotal();
for(int i = 0; i < totalDeals; i++)
{
ulong dealTicket = HistoryDealGetTicket(i);
if(dealTicket == 0)
continue;
if(HistoryDealGetString(dealTicket, DEAL_SYMBOL) != _Symbol)
continue;
if((ulong)HistoryDealGetInteger(dealTicket, DEAL_MAGIC) != InpMagicNumber)
continue;
ENUM_DEAL_ENTRY entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(dealTicket, DEAL_ENTRY);
if(entry != DEAL_ENTRY_OUT && entry != DEAL_ENTRY_INOUT)
continue;
double dealNet = HistoryDealGetDouble(dealTicket, DEAL_PROFIT)
+ HistoryDealGetDouble(dealTicket, DEAL_COMMISSION)
+ HistoryDealGetDouble(dealTicket, DEAL_SWAP);
netPnL += dealNet;
if(dealNet < -2.50)
outConsecutiveLosses++;
else if(dealNet > 2.50)
outConsecutiveLosses = 0;
}
return(netPnL);
}
//+------------------------------------------------------------------+
//| On-Chart Telemetry HUD for Unattended VPS Monitoring |
//+------------------------------------------------------------------+
void RenderTelemetryHUD(string statusLine, bool newsActive, double realizedPnLToday, int lossStreak)
{
MqlDateTime gmt;
TimeGMT(gmt);
double baseBalance = (ExtDayStartBalance > 0.0) ? ExtDayStartBalance : AccountInfoDouble(ACCOUNT_BALANCE);
double nextRiskUSD = baseBalance * (InpBaseRiskPct / 100.0);
if(realizedPnLToday > 0.0 && InpReinvestProfitPct > 0.0)
nextRiskUSD += (realizedPnLToday * (InpReinvestProfitPct / 100.0));
string hud = StringFormat(
"========================================================\n"
" XAUUSD AUTONOMOUS INSTITUTIONAL ENGINE v3.0 (M15/H4/D1)\n"
"========================================================\n"
" GMT Clock : %02d:%02d:%02d UTC\n"
" Engine Status : %s\n"
" USD News Shield : %s\n"
" Current Spread : $%.2f (Max Allowed: $%.2f)\n"
"--------------------------------------------------------\n"
" Day Start Balance : $%.2f\n"
" Today Realized PnL: $%.2f (Loss Streak: %d / %d)\n"
" Next Setup Risk $ : $%.2f (Base %.2f%% + %.0f%% House-Money)\n"
"========================================================",
gmt.hour, gmt.min, gmt.sec,
statusLine,
newsActive ? "BLOCKING (HIGH-IMPACT USD EVENT)" : "CLEAR",
ExtSymbol.Ask() - ExtSymbol.Bid(), InpMaxSpreadUSD,
baseBalance,
realizedPnLToday, lossStreak, InpMaxConsecutiveLosses,
nextRiskUSD, InpBaseRiskPct, InpReinvestProfitPct
);
Comment(hud);
}
//+------------------------------------------------------------------+