//+------------------------------------------------------------------+ //| Universal_Buffer_Reader_EA.mq5 | //| Universal Buffer Reader EA v2.0 | //+------------------------------------------------------------------+ #property copyright "Copyright 2025" #property link "" #property version "2.0" #property strict #include #include #include #include "Include\SignalDetector.mqh" #include "Include\TimeFilter.mqh" #include "Include\MoneyManager.mqh" #include "Include\RiskManager.mqh" #include "Include\PartialCloseManager.mqh" #include "Include\TradeExecutor.mqh" #include "Include\StateManager.mqh" #include "Include\LoggingManager.mqh" #include "Include\UIManager.mqh" //+------------------------------------------------------------------+ //| Trade Mode Enum | //+------------------------------------------------------------------+ enum ENUM_TRADE_MODE { MODE_INDICATOR, MODE_MANUAL }; //+------------------------------------------------------------------+ //| Input Parameters | //+------------------------------------------------------------------+ // --- General Settings --- input string General_Settings = "--- General Settings ---"; input ENUM_TRADE_MODE Trade_Mode = MODE_INDICATOR; input double LotSize = 0.03; input int Slippage = 3; input int MagicNumber = 24680; input bool TakeScreenshotOnOpen = true; input bool EnableDebugPrints = true; input bool ExitOnOppositeSignal = false; // --- Money Management Settings --- input string Money_Management_Settings = "--- Money Management Settings ---"; input bool UsePercentBalanceLot = true; input double PercentOfBalanceForProfit = 1.0; input double DailyProfitTargetPercent = 2.0; // --- Time Filtering Settings --- input string Time_Filter_Settings = "--- Time Filtering Settings ---"; input bool EnableTimeFiltering = false; input string Day_Filter_Header = "--- Day of Week Filter ---"; input bool TradeMondayEnabled = true; input bool TradeTuesdayEnabled = true; input bool TradeWednesdayEnabled = true; input bool TradeThursdayEnabled = true; input bool TradeFridayEnabled = true; input bool TradeSaturdayEnabled = false; input bool TradeSundayEnabled = false; input string Session_Filter_Header = "--- Trading Session Filter ---"; input bool TradeAsianSessionEnabled = true; input bool TradeEuropeSessionEnabled = true; input bool TradeAmericaSessionEnabled = true; // --- Risk Management Settings --- input string Risk_Management_Settings = "--- Risk Management Settings ---"; input bool UseBreakeven = true; input int BreakevenPips = 30; input bool UseTrailingStop = false; input int TrailingStopPips = 300; input int MinimumTakeProfitPips = 300; // --- Indicator Settings --- input string Indicator_Settings = "--- Indicator Settings ---"; input string IndicatorFileName = "My_Indicator"; input int BuySignalBuffer = 0; input int SellSignalBuffer = 1; // --- SL/TP Mode Settings --- input string SLTP_Settings = "--- SL/TP Mode Settings ---"; input int SLTP_Mode = 0; // 0=ATR, 1=Indicator // --- ATR Settings (Mode 0) --- input string ATR_Settings = "--- (Mode 0) ATR Settings ---"; input int AtrPeriod = 14; input double StopLossAtrMultiplier = 1.5; input double TakeProfitAtrMultiplier = 3.0; // --- Indicator SL/TP Buffers (Mode 1) --- input string Indicator_SLTP_Settings = "--- (Mode 1) Indicator SL/TP ---"; input int BuyStopLossBuffer = 2; input int BuyTP1Buffer = 3; input int BuyTP2Buffer = 4; input int BuyTP3Buffer = 5; input int SellStopLossBuffer = 6; input int SellTP1Buffer = 7; input int SellTP2Buffer = 8; input int SellTP3Buffer = 9; // --- Partial Close Settings --- input string Partial_Close_Settings = "--- Partial Close Settings ---"; input bool EnablePartialClose = true; input bool UseEqualDivision = true; input double TP1_ClosePercent = 50.0; input double TP2_ClosePercent = 30.0; input double TP3_ClosePercent = 20.0; //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ // Component instances CSignalDetector *g_signal_detector; CTimeFilter *g_time_filter; CMoneyManager *g_money_manager; CRiskManager *g_risk_manager; CPartialCloseManager *g_partial_close_manager; CTradeExecutor *g_trade_executor; CStateManager *g_state_manager; CLoggingManager *g_logging_manager; CUIManager *g_ui_manager; // Symbol info string g_symbol; int g_digits; double g_point_value; double g_pip_value; double m_tick_value; double m_stop_level_points; // Lot info double g_min_lot; double g_max_lot; double g_lot_step; // Time tracking datetime g_last_bar_time; datetime g_last_daily_reset_time; // State double g_accumulated_loss; int g_consecutive_losses; double g_daily_profit_accumulated; double g_daily_start_balance; // Chart long g_chart_id; // Manual mode bool g_manual_trade_button_pressed; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { // Initialize logging first g_logging_manager = new CLoggingManager(); g_logging_manager.SetParameters(EnableDebugPrints); g_logging_manager.LogInfo("========== EA Initializing =========="); // Get symbol info g_symbol = _Symbol; g_digits = (int)SymbolInfoInteger(g_symbol, SYMBOL_DIGITS); g_point_value = SymbolInfoDouble(g_symbol, SYMBOL_POINT); g_pip_value = (g_digits == 3 || g_digits == 5) ? g_point_value * 10 : g_point_value; m_tick_value = SymbolInfoDouble(g_symbol, SYMBOL_TRADE_TICK_VALUE); m_stop_level_points = (double)SymbolInfoInteger(g_symbol, SYMBOL_TRADE_STOPS_LEVEL); // Get lot info g_min_lot = SymbolInfoDouble(g_symbol, SYMBOL_VOLUME_MIN); g_max_lot = SymbolInfoDouble(g_symbol, SYMBOL_VOLUME_MAX); g_lot_step = SymbolInfoDouble(g_symbol, SYMBOL_VOLUME_STEP); g_chart_id = ChartID(); // Initialize state manager g_state_manager = new CStateManager(); g_state_manager.SetParameters(g_symbol, MagicNumber, EnableDebugPrints); g_state_manager.LoadState(g_accumulated_loss, g_consecutive_losses); // Initialize time filter g_time_filter = new CTimeFilter(); g_time_filter.SetParameters( EnableTimeFiltering, TradeMondayEnabled, TradeTuesdayEnabled, TradeWednesdayEnabled, TradeThursdayEnabled, TradeFridayEnabled, TradeSaturdayEnabled, TradeSundayEnabled, TradeAsianSessionEnabled, TradeEuropeSessionEnabled, TradeAmericaSessionEnabled, EnableDebugPrints ); // Initialize money manager g_money_manager = new CMoneyManager(); g_money_manager.SetParameters( LotSize, UsePercentBalanceLot, PercentOfBalanceForProfit, DailyProfitTargetPercent, g_min_lot, g_max_lot, g_lot_step, g_point_value, m_tick_value, EnableDebugPrints ); // Initialize signal detector g_signal_detector = new CSignalDetector(); g_signal_detector.SetParameters( IndicatorFileName, BuySignalBuffer, SellSignalBuffer, BuyStopLossBuffer, SellStopLossBuffer, SLTP_Mode, AtrPeriod, StopLossAtrMultiplier, TakeProfitAtrMultiplier, MinimumTakeProfitPips, g_pip_value, g_digits, g_symbol, EnableDebugPrints ); // Set TP buffers int buy_tp_buffers[] = {BuyTP1Buffer, BuyTP2Buffer, BuyTP3Buffer}; int sell_tp_buffers[] = {SellTP1Buffer, SellTP2Buffer, SellTP3Buffer}; g_signal_detector.SetBuyTPBuffers(buy_tp_buffers); g_signal_detector.SetSellTPBuffers(sell_tp_buffers); if(!g_signal_detector.Initialize()) { g_logging_manager.LogError(GetLastError(), "OnInit - SignalDetector initialization"); return INIT_FAILED; } // Initialize risk manager g_risk_manager = new CRiskManager(); g_risk_manager.SetParameters( UseTrailingStop, TrailingStopPips, UseBreakeven, BreakevenPips, g_pip_value, g_digits, m_stop_level_points, MagicNumber, g_symbol, EnableDebugPrints ); g_risk_manager.EnablePartialClose(EnablePartialClose); // Initialize partial close manager g_partial_close_manager = new CPartialCloseManager(); double partial_close_percentages[] = {TP1_ClosePercent, TP2_ClosePercent, TP3_ClosePercent}; g_partial_close_manager.SetParameters( EnablePartialClose, UseEqualDivision, partial_close_percentages, MagicNumber, g_symbol, EnableDebugPrints ); // Initialize trade executor g_trade_executor = new CTradeExecutor(); g_trade_executor.SetParameters( Slippage, MagicNumber, g_symbol, g_digits, TakeScreenshotOnOpen, g_chart_id, IndicatorFileName, EnableDebugPrints ); // Initialize UI manager g_ui_manager = new CUIManager(); g_ui_manager.SetParameters( g_chart_id, (Trade_Mode == MODE_MANUAL), MagicNumber, g_symbol, 0, // High loss threshold (not used in v2.0) EnableDebugPrints ); g_ui_manager.CreateUI(); // Initialize time tracking g_last_bar_time = 0; g_last_daily_reset_time = 0; g_manual_trade_button_pressed = false; // Reset daily profit if needed ResetDailyProfitIfNeeded(); g_logging_manager.LogInfo("========== EA Initialized Successfully =========="); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { g_logging_manager.LogInfo("========== EA Deinitializing =========="); // Save state if(g_state_manager != NULL) { g_state_manager.SaveState(g_accumulated_loss, g_consecutive_losses); } // Delete UI if(g_ui_manager != NULL) { g_ui_manager.DeleteUI(); } // Delete components if(g_signal_detector != NULL) { delete g_signal_detector; g_signal_detector = NULL; } if(g_time_filter != NULL) { delete g_time_filter; g_time_filter = NULL; } if(g_money_manager != NULL) { delete g_money_manager; g_money_manager = NULL; } if(g_risk_manager != NULL) { delete g_risk_manager; g_risk_manager = NULL; } if(g_partial_close_manager != NULL) { delete g_partial_close_manager; g_partial_close_manager = NULL; } if(g_trade_executor != NULL) { delete g_trade_executor; g_trade_executor = NULL; } if(g_state_manager != NULL) { delete g_state_manager; g_state_manager = NULL; } if(g_ui_manager != NULL) { delete g_ui_manager; g_ui_manager = NULL; } if(g_logging_manager != NULL) { delete g_logging_manager; g_logging_manager = NULL; } g_logging_manager.LogInfo("========== EA Deinitialized =========="); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Update UI UpdateUI(); // Manage risk (breakeven, trailing) g_risk_manager.ManageRiskManagement(); // Check partial closes g_partial_close_manager.CheckAndExecutePartialCloses(); // Check new bar if(!IsNewBar()) return; g_logging_manager.LogInfo("========== New Bar Detected =========="); // Update daily profit tracking UpdateDailyProfitTracking(); // Process based on trade mode if(Trade_Mode == MODE_MANUAL) { ProcessManualTrade(); } else if(Trade_Mode == MODE_INDICATOR) { ProcessIndicatorTrade(); } } //+------------------------------------------------------------------+ //| Chart event function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(id == CHARTEVENT_OBJECT_CLICK && Trade_Mode == MODE_MANUAL && sparam == "ManualTradeButton") { g_manual_trade_button_pressed = true; g_logging_manager.LogDebug("Manual trade button clicked"); } } //+------------------------------------------------------------------+ //| Check if new bar | //+------------------------------------------------------------------+ bool IsNewBar() { datetime current_bar_time = iTime(g_symbol, PERIOD_CURRENT, 0); if(current_bar_time != g_last_bar_time) { g_last_bar_time = current_bar_time; return true; } return false; } //+------------------------------------------------------------------+ //| Update UI | //+------------------------------------------------------------------+ void UpdateUI() { double account_balance = AccountInfoDouble(ACCOUNT_BALANCE); double loss_percent = 0; if(account_balance > 0) { loss_percent = (g_accumulated_loss / account_balance) * 100.0; } g_ui_manager.UpdateLossDisplay(g_accumulated_loss, loss_percent); } //+------------------------------------------------------------------+ //| Reset daily profit if needed | //+------------------------------------------------------------------+ void ResetDailyProfitIfNeeded() { datetime now = TimeCurrent(); datetime midnight = now - (now % 86400); datetime reset_time = midnight + 3600; // 01:00 GMT if(now >= reset_time && (g_last_daily_reset_time < reset_time || TimeToString(now, TIME_DATE) != TimeToString(g_last_daily_reset_time, TIME_DATE))) { double current_balance = AccountInfoDouble(ACCOUNT_BALANCE); g_money_manager.ResetDailyProfit(current_balance); g_last_daily_reset_time = now; g_logging_manager.LogInfo("Daily Profit Tracking Reset at 01:00. Start Balance: " + DoubleToString(current_balance, 2)); } } //+------------------------------------------------------------------+ //| Update daily profit tracking | //+------------------------------------------------------------------+ void UpdateDailyProfitTracking() { ResetDailyProfitIfNeeded(); // Calculate daily profit from history double daily_profit = 0; for(int i = HistoryDealsTotal() - 1; i >= 0; i--) { if(HistoryDealSelect(i)) { string symbol; long magic, entry_type, deal_time; double profit, commission, swap; if(HistoryDealGetString(i, DEAL_SYMBOL, symbol) && HistoryDealGetInteger(i, DEAL_MAGIC, magic) && HistoryDealGetInteger(i, DEAL_ENTRY, entry_type) && HistoryDealGetInteger(i, DEAL_TIME, deal_time) && HistoryDealGetDouble(i, DEAL_PROFIT, profit) && HistoryDealGetDouble(i, DEAL_COMMISSION, commission) && HistoryDealGetDouble(i, DEAL_SWAP, swap)) { if(symbol == g_symbol && magic == MagicNumber && entry_type == DEAL_ENTRY_OUT && deal_time > g_last_daily_reset_time) { daily_profit += profit + commission + swap; } } } } g_money_manager.SetDailyProfitAccumulated(daily_profit); } //+------------------------------------------------------------------+ //| Process manual trade | //+------------------------------------------------------------------+ void ProcessManualTrade() { if(!g_manual_trade_button_pressed) return; g_manual_trade_button_pressed = false; double manual_tp = g_ui_manager.GetManualTP(); double manual_sl = g_ui_manager.GetManualSL(); if(manual_tp == 0 || manual_sl == 0) { g_logging_manager.LogWarning("Please fill both Stop Loss and Take Profit values for manual trade."); return; } double bid = SymbolInfoDouble(g_symbol, SYMBOL_BID); double ask = SymbolInfoDouble(g_symbol, SYMBOL_ASK); bool is_buy = (manual_tp > bid && manual_sl < bid); bool is_sell = (manual_tp < bid && manual_sl > bid); if(!is_buy && !is_sell) { g_logging_manager.LogWarning("Invalid SL/TP values for a market order."); return; } // Calculate lot size double lot_size = g_money_manager.CalculateLotSize(is_buy, is_buy ? ask : bid, manual_tp, AccountInfoDouble(ACCOUNT_BALANCE)); // Validate SL/TP double tp_prices[] = {manual_tp}; CRiskManager::ValidatedSLTP validated = g_risk_manager.ValidateSLTP(is_buy, is_buy ? ask : bid, manual_sl, tp_prices, 1); if(!validated.is_valid) { g_logging_manager.LogWarning("SL/TP validation failed: ", validated.error_message); return; } // Execute trade CTradeExecutor::TradeResult result = g_trade_executor.ExecuteTrade( is_buy, lot_size, is_buy ? ask : bid, validated.sl_price, validated.tp_prices, validated.tp_count ); if(!result.success) { g_logging_manager.LogError(GetLastError(), "ProcessManualTrade - ExecuteTrade"); } } //+------------------------------------------------------------------+ //| Process indicator trade | //+------------------------------------------------------------------+ void ProcessIndicatorTrade() { // Check daily profit target if(g_money_manager.IsDailyProfitTargetReached()) { g_logging_manager.LogInfo("Daily profit target reached. Skipping trade."); return; } // Check time filter if(!g_time_filter.IsTimeAllowed()) { g_logging_manager.LogDebug("Time filter not allowed. Skipping trade."); return; } // Check if trade is already open if(g_trade_executor.IsTradeOpen()) { g_logging_manager.LogDebug("Trade already open. Skipping new signal."); return; } // Detect signal CSignalDetector::SignalData signal = g_signal_detector.DetectSignal(1); if(!signal.has_signal) { g_logging_manager.LogDebug("No signal detected."); return; } g_logging_manager.LogInfo(signal.is_buy ? "BUY signal detected" : "SELL signal detected"); g_logging_manager.LogInfo("Signal Price: " + DoubleToString(signal.signal_price, g_digits)); g_logging_manager.LogInfo("SL: " + DoubleToString(signal.sl_price, g_digits)); for(int i = 0; i < signal.tp_count; i++) { g_logging_manager.LogInfo("TP", i + 1, ": ", DoubleToString(signal.tp_prices[i], g_digits)); } if(signal.used_atr_fallback) { g_logging_manager.LogInfo("ATR fallback used for SL/TP"); } // Exit opposite trade if enabled if(ExitOnOppositeSignal) { g_trade_executor.CloseOppositeTrade(signal.is_buy); } // Calculate lot size double open_price = SymbolInfoDouble(g_symbol, SYMBOL_BID); double lot_size = g_money_manager.CalculateLotSize( signal.is_buy, open_price, signal.tp_prices[0], // Use first TP for lot calculation AccountInfoDouble(ACCOUNT_BALANCE) ); g_logging_manager.LogInfo("Lot size: " + DoubleToString(lot_size, 2)); // Validate SL/TP CRiskManager::ValidatedSLTP validated = g_risk_manager.ValidateSLTP( signal.is_buy, open_price, signal.sl_price, signal.tp_prices, signal.tp_count ); if(!validated.is_valid) { g_logging_manager.LogWarning("SL/TP validation failed: ", validated.error_message); return; } // Execute trade CTradeExecutor::TradeResult result = g_trade_executor.ExecuteTrade( signal.is_buy, lot_size, open_price, validated.sl_price, validated.tp_prices, validated.tp_count ); if(!result.success) { g_logging_manager.LogError(GetLastError(), "ProcessIndicatorTrade - ExecuteTrade"); } } //+------------------------------------------------------------------+