Files
Universal_MTF_EA/Universal_MTF_EA.mq5
2026-05-28 19:46:22 +03:00

473 lines
16 KiB
Plaintext

//+------------------------------------------------------------------+
//| 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);
}
}
}
//+------------------------------------------------------------------+