//+------------------------------------------------------------------+ //| Universal_MTF_EA.mq5 | //| Universal Multi-Timeframe Expert Advisor v2.1 | //| Enhanced: Fibonacci + Liquidity + Dynamic Risk + Confluence | //+------------------------------------------------------------------+ #property strict #property copyright "Institutional Quantitative Systems" #property version "2.100" #property description "Universal MTF EA v2.1 - Fibonacci + Liquidity + Smart Risk" //--- Input for magic number (ONLY in .mq5, not in any .mqh) input group "=== EA IDENTIFICATION ===" input ulong InpMagicNumber = 20250625; input string InpEALabel = "Universal_MTF"; input group "=== RISK MANAGEMENT ===" input double InpMaxRiskPerTrade = 0.5; input double InpMaxDailyLoss = 2.0; input double InpMaxWeeklyLoss = 5.0; input int InpMaxConsecLosses = 3; input int InpMaxPositions = 5; input double InpMaxTotalRisk = 3.0; input group "=== TIME FRAME CONFIGURATION ===" input ENUM_TIMEFRAMES InpHTF = PERIOD_H4; input ENUM_TIMEFRAMES InpMTF = PERIOD_M15; input ENUM_TIMEFRAMES InpLTF = PERIOD_M5; input group "=== ATR & VOLATILITY ===" input int InpATRPeriod = 14; input int InpATRBaseline = 50; input double InpTrendATRMult = 1.5; input double InpRangeATRMult = 1.0; input double InpTrailingMult = 2.0; input group "=== SESSION & SYMBOL ===" input bool InpUseSessionFilter = true; input bool InpUseSpreadFilter = true; input bool InpUseCorrelationFilter = true; input group "=== NEWS FILTER ===" input bool InpUseNewsFilter = true; input int InpNewsBlockMinutes = 30; input int InpNewsResumeMinutes = 15; input group "=== ORDER EXECUTION ===" input bool InpUseLimitOrders = true; input int InpLimitOrderExpiry = 30; input group "=== TELEGRAM/DISCORD ALERTS ===" input string InpTelegramBotToken = ""; input string InpTelegramChatId = ""; input string InpDiscordWebhook = ""; input bool InpAlertOnTrade = true; input bool InpAlertOnCircuitBreaker = true; input bool InpAlertOnRegimeChange = true; input bool InpSendDailySummary = true; input group "=== LOGGING & AUDIT ===" input string InpLogPath = "Universal_MTF_EA/"; input bool InpDebugMode = false; input int InpDashboardUpdateSec = 5; //+------------------------------------------------------------------+ //| MODULE INCLUDES | //+------------------------------------------------------------------+ #include "Core/Config.mqh" #include "Core/State.mqh" #include "Core/Logger.mqh" #include "Core/SymbolProfiler.mqh" #include "Core/TelegramNotifier.mqh" #include "Data/PriceEngine.mqh" #include "Data/VWAP_Engine.mqh" #include "Data/Volatility.mqh" #include "Data/FibonacciEngine.mqh" #include "Data/LiquidityEngine.mqh" #include "Execution/OrderManager.mqh" #include "Execution/TradeManager.mqh" #include "Logic/MacroAudit.mqh" #include "Logic/ContextFilter.mqh" #include "Logic/MicroTrigger.mqh" #include "Logic/RegimeEngine.mqh" #include "Logic/NewsFilter.mqh" #include "Risk/PositionSizer.mqh" #include "Risk/Protection.mqh" #include "Risk/PortfolioManager.mqh" //+------------------------------------------------------------------+ //| MODULE INSTANCES | //+------------------------------------------------------------------+ CLogger g_logger; CSymbolProfiler g_profiler; CTelegramNotifier g_notifier; CPriceEngine g_priceEngine; CVWAPEngine g_vwapEngine; CVolatility g_volatility; CFibonacciEngine g_fibonacci; CLiquidityEngine g_liquidity; CMacroAudit g_macroAudit; CContextFilter g_contextFilter; CMicroTrigger g_microTrigger; CRegimeEngine g_regimeEngine; CNewsFilter g_newsFilter; CPositionSizer g_positionSizer; CProtection g_protection; CPortfolioManager g_portfolio; COrderManager g_orderManager; CTradeManager g_tradeManager; //+------------------------------------------------------------------+ //| EXPERT INITIALIZATION | //+------------------------------------------------------------------+ int OnInit() { Print("============================================================"); Print("[Universal_MTF_EA] Initializing v2.100..."); Print("============================================================"); if(!g_logger.Init(InpLogPath, InpEALabel, InpMagicNumber)) { Print("[CRITICAL] Logger init failed. EA halted."); return INIT_FAILED; } g_logger.LogEvent("SYSTEM", "EA Initialization started v2.1 (Fib + Liquidity + Smart Risk)"); if(!g_session.Init()) { g_logger.LogError("OnInit", 0, "SessionManager init failed", 0); return INIT_FAILED; } if(!g_profiler.Init(g_state.assetProfile)) { g_logger.LogError("OnInit", 0, "SymbolProfiler init failed", 0); return INIT_FAILED; } g_logger.LogEvent("SYSTEM", StringFormat("Asset: %s", g_state.assetProfile.description)); if(!g_priceEngine.Init(InpHTF, InpMTF, InpLTF)) { g_logger.LogError("OnInit", 0, "PriceEngine init failed", 0); return INIT_FAILED; } if(!g_vwapEngine.Init(g_state.assetProfile)) { g_logger.LogError("OnInit", 0, "VWAPEngine init failed", 0); return INIT_FAILED; } if(!g_volatility.Init(InpATRPeriod, InpATRBaseline, InpHTF, InpMTF)) { g_logger.LogError("OnInit", 0, "Volatility init failed", 0); return INIT_FAILED; } if(!g_fibonacci.Init(InpMTF)) { g_logger.LogError("OnInit", 0, "FibonacciEngine init failed", 0); return INIT_FAILED; } if(!g_liquidity.Init(InpLTF)) { g_logger.LogError("OnInit", 0, "LiquidityEngine init failed", 0); return INIT_FAILED; } if(!g_macroAudit.Init(InpHTF, g_vwapEngine)) { g_logger.LogError("OnInit", 0, "MacroAudit init failed", 0); return INIT_FAILED; } if(!g_contextFilter.Init(InpMTF, g_volatility)) { g_logger.LogError("OnInit", 0, "ContextFilter init failed", 0); return INIT_FAILED; } if(!g_microTrigger.Init(InpLTF, g_priceEngine)) { g_logger.LogError("OnInit", 0, "MicroTrigger init failed", 0); return INIT_FAILED; } if(!g_regimeEngine.Init()) { g_logger.LogError("OnInit", 0, "RegimeEngine init failed", 0); return INIT_FAILED; } if(!g_newsFilter.Init(InpNewsBlockMinutes, InpNewsResumeMinutes)) { g_logger.LogError("OnInit", 0, "NewsFilter init failed", 0); return INIT_FAILED; } if(!g_positionSizer.Init(g_state.assetProfile, InpMaxRiskPerTrade)) { g_logger.LogError("OnInit", 0, "PositionSizer init failed", 0); return INIT_FAILED; } if(!g_protection.Init(InpMaxDailyLoss, InpMaxWeeklyLoss, InpMaxConsecLosses, InpMaxPositions, InpMaxTotalRisk)) { g_logger.LogError("OnInit", 0, "Protection init failed", 0); return INIT_FAILED; } if(!g_portfolio.Init(CORR_LOOKBACK, InpMTF)) { g_logger.LogError("OnInit", 0, "PortfolioManager init failed", 0); return INIT_FAILED; } if(!g_orderManager.Init(InpMagicNumber, g_state.assetProfile)) { g_logger.LogError("OnInit", 0, "OrderManager init failed", 0); return INIT_FAILED; } if(!g_tradeManager.Init(g_state.assetProfile, g_orderManager)) { g_logger.LogError("OnInit", 0, "TradeManager init failed", 0); return INIT_FAILED; } if(!g_notifier.Init(InpTelegramBotToken, InpTelegramChatId, InpDiscordWebhook)) { g_logger.LogEvent("SYSTEM", "TelegramNotifier init failed or disabled."); } g_state.equityAtStart = AccountInfoDouble(ACCOUNT_EQUITY); g_state.equityAtWeekStart = AccountInfoDouble(ACCOUNT_EQUITY); g_state.circuitBreakerUntil = 0; g_state.circuitBreakerReason = ""; g_state.loggerReady = true; g_state.lastDashboardUpdate = 0; EventSetMillisecondTimer(30000); EventSetMillisecondTimer(5000); EventSetMillisecondTimer(InpDashboardUpdateSec * 1000); EventSetMillisecondTimer(3600000); EventSetMillisecondTimer(900000); g_priceEngine.RefreshAll(); g_vwapEngine.Calculate(g_state.vwapState); g_volatility.Update(); g_fibonacci.Calculate(); g_liquidity.Update(); g_macroAudit.Analyze(g_state); g_contextFilter.Analyze(g_state); g_logger.LogEvent("SYSTEM", "EA Initialization completed successfully v2.1"); g_logger.LogEvent("SYSTEM", StringFormat("Symbol: %s | Class: %s | HTF: %s | MTF: %s | LTF: %s", _Symbol, g_state.assetProfile.description, EnumToString(InpHTF), EnumToString(InpMTF), EnumToString(InpLTF))); if(InpAlertOnTrade) { g_notifier.SendMessage("*Universal MTF EA v2.1 Started*\n\nSymbol: " + _Symbol + "\nAsset: " + g_state.assetProfile.description + "\nTime: " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)); } Print("[Universal_MTF_EA] Initialization complete. Ready for trading."); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| EXPERT DEINITIALIZATION | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { Print("============================================================"); Print("[Universal_MTF_EA] Deinitializing... Reason: ", reason); Print("============================================================"); EventKillTimer(); g_logger.Shutdown(); g_priceEngine.Release(); g_vwapEngine.Release(); g_volatility.Release(); g_macroAudit.Release(); g_contextFilter.Release(); g_microTrigger.Release(); if(InpAlertOnTrade) { g_notifier.SendMessage("*Universal MTF EA v2.1 Stopped*\n\nSymbol: " + _Symbol + "\nReason: " + IntegerToString(reason) + "\nDaily PnL: " + StringFormat("%.2f", g_state.dailyPnL) + "\nTime: " + TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)); } g_logger.LogEvent("SYSTEM", StringFormat("EA Stopped. Daily: %.2f | Weekly: %.2f | Trades: %d", g_state.dailyPnL, g_state.weeklyPnL, g_state.totalTradesToday)); Print("[Universal_MTF_EA] Deinitialization complete."); } //+------------------------------------------------------------------+ //| EXPERT TICK HANDLER | //+------------------------------------------------------------------+ void OnTick() { if(g_protection.IsCircuitBreakerActive(g_state)) { g_tradeManager.ManageOpenPositions(g_state, g_volatility); return; } if(InpUseSessionFilter && !g_session.IsSessionValid(g_state.assetProfile)) return; if(g_session.IsRolloverTime()) return; if(InpUseNewsFilter && !g_newsFilter.IsTradingAllowed()) return; static datetime lastLTFTime = 0; datetime currentLTFTime = iTime(_Symbol, InpLTF, 0); if(currentLTFTime != lastLTFTime) { if(g_priceEngine.IsBarClosed(InpLTF)) { g_state.isBarClosedLTF = true; g_state.lastLTFBarTime = currentLTFTime; g_priceEngine.RefreshLTF(); if(g_state.currentBias != BIAS_NEUTRAL || g_state.currentRegime == REGIME_RANGE) { SignalData signal; g_microTrigger.GenerateSignal(signal, g_state, g_priceEngine); g_logger.LogSignal(signal, g_state); if(signal.isValid) ProcessSignal(signal); } } lastLTFTime = currentLTFTime; } g_tradeManager.ManageOpenPositions(g_state, g_volatility); g_portfolio.UpdateState(g_state); if(InpUseLimitOrders) { static datetime lastOrderCheck = 0; if(TimeCurrent() - lastOrderCheck > 300) { g_orderManager.CancelStaleOrders(InpLimitOrderExpiry); lastOrderCheck = TimeCurrent(); } } } //+------------------------------------------------------------------+ //| TIMER HANDLER | //+------------------------------------------------------------------+ void OnTimer() { static int timerCount = 0; timerCount++; if(timerCount % 6 == 0) { if(g_priceEngine.IsBarClosed(InpHTF)) { g_state.isBarClosedHTF = true; g_state.lastHTFBarTime = iTime(_Symbol, InpHTF, 0); g_vwapEngine.Calculate(g_state.vwapState); g_macroAudit.Analyze(g_state); } } if(timerCount % 1 == 0) { if(g_priceEngine.IsBarClosed(InpMTF)) { g_state.isBarClosedMTF = true; g_state.lastMTFBarTime = iTime(_Symbol, InpMTF, 0); g_volatility.Update(); g_fibonacci.Calculate(); g_liquidity.Update(); g_contextFilter.Analyze(g_state); g_regimeEngine.UpdateState(g_state); } } if(TimeCurrent() - g_state.lastDashboardUpdate >= InpDashboardUpdateSec) { g_logger.UpdateDashboard(g_state); g_state.lastDashboardUpdate = TimeCurrent(); } g_protection.CheckDailyReset(g_state); if(InpSendDailySummary) { MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); static bool summarySentToday = false; if(dt.hour == 23 && !summarySentToday) { g_notifier.SendDailySummary(g_state); summarySentToday = true; } if(dt.hour == 0) summarySentToday = false; } } //+------------------------------------------------------------------+ //| SIGNAL PROCESSING | //+------------------------------------------------------------------+ void ProcessSignal(const SignalData &signal) { if(InpUseSpreadFilter && !g_protection.IsSpreadAcceptable(g_state.assetProfile)) { g_logger.LogEvent("FILTER", "Signal rejected: Spread too wide"); return; } if(g_state.openPositions >= InpMaxPositions) { g_logger.LogEvent("FILTER", StringFormat("Max positions reached (%d)", g_state.openPositions)); return; } if(InpUseCorrelationFilter && g_portfolio.IsCorrelated(signal, g_state)) { g_logger.LogEvent("FILTER", "High correlation"); return; } TradeParams tradeParams; g_positionSizer.Calculate(tradeParams, signal, g_state); if(!tradeParams.isValid) { g_logger.LogEvent("FILTER", StringFormat("Sizing failed: %s", tradeParams.rejectReason)); return; } if(!g_portfolio.CheckExposure(tradeParams, g_state)) { g_logger.LogEvent("FILTER", "Portfolio risk limit exceeded"); return; } if(!g_protection.PreTradeCheck(g_state)) { g_logger.LogEvent("FILTER", StringFormat("Circuit breaker: %s", g_state.circuitBreakerReason)); return; } ulong ticket = 0; bool executed = g_orderManager.ExecuteOrder(signal, tradeParams, g_state, ticket); if(executed && ticket > 0) { g_state.openPositions++; g_logger.LogTradeOpen(signal, tradeParams, ticket); g_logger.LogEvent("EXECUTE", StringFormat("Order Ticket=%llu | %s | Lots: %.2f | RiskMult: %.2f", ticket, signal.isBuy ? "BUY" : "SELL", tradeParams.lotSize, g_protection.GetRiskMultiplier())); if(InpAlertOnTrade) g_notifier.SendTradeOpen(signal, tradeParams, ticket); } else { g_logger.LogEvent("EXECUTE", "Order execution failed"); } } //+------------------------------------------------------------------+ //| TRADE EVENT HANDLER | //+------------------------------------------------------------------+ void OnTrade() { g_tradeManager.CheckClosedTrades(g_state); g_protection.UpdateState(g_state); if(g_state.lastTradeClose > 0) { g_logger.LogTradeClose(g_state); if(InpAlertOnTrade) g_notifier.SendTradeClose(g_state); if(g_state.dailyLimitHit || g_state.weeklyLimitHit || g_state.consecLossHalted) { if(InpAlertOnCircuitBreaker) g_notifier.SendCircuitBreaker(g_state); } } } //+------------------------------------------------------------------+