Files
MyProEA/MyProEA.mq5
T

280 lines
8.6 KiB
Plaintext

//+------------------------------------------------------------------+
//| 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;
// Diagnostics counters for blocked entries
long g_blocked_existing_position = 0;
long g_blocked_spread = 0;
long g_blocked_hours = 0;
long g_blocked_max_positions = 0;
//+------------------------------------------------------------------+
// 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");
delete g_market_data;
g_market_data = NULL;
delete g_logger;
g_logger = NULL;
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");
delete g_strategy;
g_strategy = NULL;
delete g_market_data;
g_market_data = NULL;
delete g_logger;
g_logger = NULL;
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("Chart Timeframe: %s", EnumToString(PERIOD_CURRENT)));
g_logger.Info(StringFormat("Strategy Evaluation: %s on %s",
g_evaluate_every_tick ? "Every tick" : (g_evaluate_on_new_bar ? "New bar" : "Every tick"),
EnumToString(g_strategy_entry_timeframe)));
g_logger.Info(StringFormat("Lot Mode: %s",
g_lot_mode == LOT_MODE_FIXED ? "FIXED" : "RISK"));
g_logger.Info("Initial SL/TP source: Strategy TradeSetup");
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())
{
g_blocked_spread++;
if(g_debug_mode)
g_logger.Info(StringFormat("Blocked entry due to spread (count=%d)", g_blocked_spread));
return;
}
// Step 3: Check trading hours
if(!g_risk_manager.IsTradingHourValid())
{
g_blocked_hours++;
if(g_debug_mode)
g_logger.Info(StringFormat("Blocked entry due to trading hours (count=%d)", g_blocked_hours));
return;
}
// Step 4: Manage existing positions (trailing stop, break-even)
g_trailing_stop.UpdateAllPositions();
// Step 5: Evaluate strategy on configured entry timeframe unless every-tick mode is enabled
bool should_evaluate_strategy = true;
if(!g_evaluate_every_tick && g_evaluate_on_new_bar)
should_evaluate_strategy = g_market_data.IsNewBar(g_strategy_entry_timeframe);
if(!should_evaluate_strategy)
{
return;
}
// Log diagnostics on each new entry bar
if(g_strategy != NULL)
g_strategy.LogDiagnostics();
if(g_logger != NULL && g_debug_mode)
g_logger.Info(StringFormat("Blocked totals: existing=%d spread=%d hours=%d maxpos=%d", g_blocked_existing_position, g_blocked_spread, g_blocked_hours, g_blocked_max_positions));
// Step 6: Get the trade setup from strategy
TradeSetup setup = g_strategy.GetTradeSetup();
if(setup.signal == SIGNAL_NONE)
{
if(g_debug_mode && g_logger != NULL)
g_logger.Info(StringFormat("No trade setup: %s", setup.reason));
return;
}
// Step 7: Check if we already have a position
if(g_position_manager.HasOpenPosition(_Symbol))
{
g_blocked_existing_position++;
if(g_debug_mode)
g_logger.Info(StringFormat("Already have open position, skipping entry (count=%d)", g_blocked_existing_position));
return;
}
// Step 8: Check if new position is allowed
if(!g_position_manager.IsNewPositionAllowed(_Symbol))
{
g_blocked_max_positions++;
g_logger.Warning(StringFormat("New position not allowed (max positions reached) (count=%d)", g_blocked_max_positions));
return;
}
double lot = 0.0;
if(!g_risk_manager.ValidateTradeSetup(setup, lot))
{
if(g_logger)
g_logger.Warning(StringFormat("Trade setup rejected: %s", setup.reason));
return;
}
bool trade_success = false;
if(setup.signal == SIGNAL_BUY)
{
trade_success = g_trade_manager.OpenBuyTrade(_Symbol, lot, setup.stopLoss, setup.takeProfit, setup.entryPrice);
}
else if(setup.signal == SIGNAL_SELL)
{
trade_success = g_trade_manager.OpenSellTrade(_Symbol, lot, setup.stopLoss, setup.takeProfit, setup.entryPrice);
}
if(trade_success)
{
if(g_logger)
g_logger.Info("Trade executed successfully");
}
else
{
if(g_logger)
g_logger.Error("Trade execution failed");
}
}