//+------------------------------------------------------------------+ //| MyProEA.mq5 - Professional Expert Advisor | //| Main EA file with clean lifecycle and separation of concerns | //+------------------------------------------------------------------+ #property copyright "Educational EA - BackTesting Only" #property link "https://www.mql5.com" #property version "1.00" #property strict #property description "Professional modular EA with MA crossover strategy" #property description "For educational and backtesting purposes only" // Include all class definitions #include "Include/Config.mqh" #include "Include/Logger.mqh" #include "Include/Utilities.mqh" #include "Include/MarketData.mqh" #include "Include/Signal.mqh" #include "Include/Strategy.mqh" #include "Include/RiskManager.mqh" #include "Include/PositionManager.mqh" #include "Include/TradeManager.mqh" #include "Include/TrailingStop.mqh" //+------------------------------------------------------------------+ // Global class instances //+------------------------------------------------------------------+ CLogger *g_logger = NULL; CMarketData *g_market_data = NULL; CStrategy *g_strategy = NULL; CRiskManager *g_risk_manager = NULL; CPositionManager *g_position_manager = NULL; CTradeManager *g_trade_manager = NULL; CTrailingStop *g_trailing_stop = NULL; //+------------------------------------------------------------------+ // EA Initialization //+------------------------------------------------------------------+ int OnInit() { // Create logger instance g_logger = new CLogger(g_debug_mode); g_logger.Info("===== EA INITIALIZATION START ====="); // Create market data handler g_market_data = new CMarketData(_Symbol, g_logger); if(!g_market_data.IsTradingAllowed()) { g_logger.Error("Trading not allowed for this symbol"); return INIT_FAILED; } // Create strategy g_strategy = new CStrategy(g_market_data, g_logger); if(!g_strategy.Init()) { g_logger.Error("Failed to initialize strategy"); return INIT_FAILED; } // Create risk manager g_risk_manager = new CRiskManager(g_market_data, g_logger); // Create position manager g_position_manager = new CPositionManager(g_logger); // Create trade manager g_trade_manager = new CTradeManager(g_logger, g_risk_manager); // Create trailing stop manager g_trailing_stop = new CTrailingStop(g_market_data, g_logger, g_trade_manager); // Log configuration g_logger.Info(StringFormat("Magic Number: %d", g_magic_number)); g_logger.Info(StringFormat("Symbol: %s", _Symbol)); g_logger.Info(StringFormat("Timeframe: %s", EnumToString(PERIOD_CURRENT))); g_logger.Info(StringFormat("Lot Mode: %s", g_lot_mode == LOT_MODE_FIXED ? "FIXED" : "RISK")); g_logger.Info(StringFormat("Stop Loss: %d points, Take Profit: %d points", g_stop_loss_points, g_take_profit_points)); g_logger.Info(StringFormat("Max Positions: %d, Max Spread: %d points", g_max_positions, g_max_spread_points)); g_logger.Info("===== EA INITIALIZATION COMPLETE ====="); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ // EA Deinitialization //+------------------------------------------------------------------+ void OnDeinit(const int reason) { g_logger.Info("===== EA DEINITIALIZATION START ====="); string reason_text = ""; switch(reason) { case REASON_ACCOUNT: reason_text = "Account changed"; break; case REASON_CHARTCHANGE: reason_text = "Chart changed"; break; case REASON_CHARTCLOSE: reason_text = "Chart closed"; break; case REASON_PARAMETERS: reason_text = "Parameters changed"; break; case REASON_RECOMPILE: reason_text = "EA recompiled"; break; case REASON_REMOVE: reason_text = "EA removed"; break; default: reason_text = "Unknown reason"; break; } g_logger.Info(StringFormat("Deinit reason: %s (%d)", reason_text, reason)); // Clean up strategy (release indicator handles) if(g_strategy != NULL) { delete g_strategy; g_strategy = NULL; } // Clean up all other objects if(g_trailing_stop != NULL) { delete g_trailing_stop; g_trailing_stop = NULL; } if(g_trade_manager != NULL) { delete g_trade_manager; g_trade_manager = NULL; } if(g_position_manager != NULL) { delete g_position_manager; g_position_manager = NULL; } if(g_risk_manager != NULL) { delete g_risk_manager; g_risk_manager = NULL; } if(g_market_data != NULL) { delete g_market_data; g_market_data = NULL; } if(g_logger != NULL) { g_logger.Info("===== EA DEINITIALIZATION COMPLETE ====="); delete g_logger; g_logger = NULL; } } //+------------------------------------------------------------------+ // Main EA Logic - OnTick() //+------------------------------------------------------------------+ void OnTick() { // Step 1: Update market data (always) if(!g_market_data.IsTradingAllowed()) { return; } // Step 2: Check spread - if spread is too wide, don't trade if(!g_risk_manager.IsSpreadAcceptable()) { return; } // Step 3: Check trading hours if(!g_risk_manager.IsTradingHourValid()) { return; } // Step 4: Manage existing positions (trailing stop, break-even) g_trailing_stop.UpdateAllPositions(); // Step 5: Only process signals on new bar if(!g_market_data.IsNewBar()) { return; } // Step 6: Get trading signal from strategy E_SIGNAL signal = g_strategy.GetSignal(); if(signal == SIGNAL_NONE) { return; } // Step 7: Check if we already have a position if(g_position_manager.HasOpenPosition(_Symbol)) { if(g_debug_mode) g_logger.Info("Already have open position, skipping entry"); return; } // Step 8: Check if new position is allowed if(!g_position_manager.IsNewPositionAllowed(_Symbol)) { g_logger.Warning("New position not allowed (max positions reached)"); return; } // Step 9: Calculate lot size double lot = g_risk_manager.CalculateLotSize(g_stop_loss_points); if(lot <= 0) { g_logger.Error("Invalid lot size calculated"); return; } // Step 10: Execute trade based on signal bool trade_success = false; if(signal == SIGNAL_BUY) { trade_success = g_trade_manager.OpenBuyTrade(_Symbol, lot); } else if(signal == SIGNAL_SELL) { trade_success = g_trade_manager.OpenSellTrade(_Symbol, lot); } if(trade_success) { if(g_logger) g_logger.Info("Trade executed successfully"); } else { if(g_logger) g_logger.Error("Trade execution failed"); } }