//+------------------------------------------------------------------+ //| Risk Management Overlay EA v7.1 | //| Fully Optimized Version | //| Fixed Multi-Symbol Detection | //+------------------------------------------------------------------+ #property copyright "Institutional Risk Management System v7.1" #property version "7.1" #property strict #property description "Modular risk management system with advanced monitoring" //--- Include system modules #include #include "Modules_optimised/Dashboard_Enhanced.mqh" #include "Modules_optimised/Datatypes_Optimised.mqh" #include "Modules_optimised/EntrySystem_Optimised.mqh" #include "Modules_optimised/Performance_Tracker.mqh" #include "Modules_optimised/Risk_Manager_Optimised.mqh" #include "Modules_optimised/Symbol_Manager.mqh" #include "Modules_optimised/Trade_Executor.mqh" #include "Modules_optimised/Trade_Manager_Optimised.mqh" #include "Modules/TechnicalAnalysis.mqh" #include "Modules/Utilities.mqh" #include "Modules/MultiTradeReporter.mqh" //+------------------------------------------------------------------+ //| INPUT PARAMETERS - GROUPED BY MODULE | //+------------------------------------------------------------------+ //--- System Configuration input group "=== SYSTEM CONFIGURATION ===" input bool SystemEnabled = true; // Enable System input int TradingMagic = 12345; // EA Magic Number input bool ManageExternalTrades = true; // Manage External Trades input int MagicNumberFilter = 0; // External Magic Filter (0=all) input ENUM_LOG_LEVEL LogLevel = LOG_INFO; // Logging Level //--- Entry System Parameters input group "=== ENTRY SYSTEM ===" input ENUM_ENTRY_MODE EntryMode = ENTRY_MA_CROSS; // Entry System Type input bool EnableMultipleEntries = false; // Allow Multiple Entries input int MaxPositions = 3; // Maximum Positions input double MinTimeBetweenTrades = 60; // Min Minutes Between Trades //--- Risk Management Parameters input group "=== RISK MANAGEMENT ===" input ENUM_POSITION_SIZING SizingMode = PS_RISK_PERCENT; // Position Sizing Mode input double RiskPercent = 2.5; // Risk Per Trade (%) input double MaxRiskPercent = 5.0; // Maximum Risk (%) input double MaxDailyDrawdown = 5.0; // Max Daily Drawdown (%) input double MaxTotalExposure = 10.0; // Max Total Exposure (%) input bool UseKellyCriterion = false; // Use Kelly Criterion input double KellyFraction = 0.25; // Kelly Fraction input double MinLotSize = 0.01; // Minimum Lot Size input double MaxLotSize = 10.0; // Maximum Lot Size //--- Trade Management Parameters input group "=== TRADE MANAGEMENT ===" input ENUM_TP_MODE TPMode = TP_ADAPTIVE; // Take Profit Mode input ENUM_SL_MODE SLMode = SL_ATR; // Stop Loss Mode input bool EnableBreakeven = true; // Enable Breakeven input double BreakevenTrigger = 1.0; // Breakeven at X:1 input bool EnableTrailing = true; // Enable Trailing Stop input double TrailingStart = 1.5; // Start Trailing at X:1 input bool EnablePartialClose = true; // Enable Partial Closes input string PartialLevels = "1.0:33,2.0:33,3.0:20"; // Partial Close Levels //--- External Trade Management input group "=== EXTERNAL TRADE RULES ===" input bool ForceRiskRules = true; // Force Risk Rules input bool ForceStopLoss = true; // Force Stop Loss input bool ForceTakeProfit = true; // Force Take Profit input bool OverrideExternalSL = false; // Override Existing SL input bool OverrideExternalTP = false; // Override Existing TP input double DefaultExternalRisk = 1.0; // Default External Risk (%) input bool CloseExcessiveRisk = true; // Close Excessive Risk //--- Technical Analysis Parameters input group "=== TECHNICAL ANALYSIS ===" input bool UseSupportResistance = true; // Use S/R Levels input bool UseFibonacci = true; // Use Fibonacci input bool UsePivotPoints = true; // Use Pivot Points input bool UseMarketStructure = true; // Use Market Structure input bool EnableLogging = true; // Enable Detailed Logging input int TechnicalLookback = 200; // Technical Lookback Bars //--- Dashboard Parameters input group "=== DASHBOARD SETTINGS ===" input bool ShowDashboard = true; // Show Dashboard input int DashboardX = 20; // Dashboard X Position input int DashboardY = 30; // Dashboard Y Position input color DashboardColor = clrWhiteSmoke; // Dashboard Text Color input color ProfitColor = clrLime; // Profit Color input color LossColor = clrRed; // Loss Color input int UpdateFrequency = 1; // Update Frequency (seconds) //--- Enhanced Display Settings input group "=== ENHANCED DISPLAY SETTINGS ===" input int MaxTradesDisplay = 10; // Maximum Trades to Display input bool GroupBySource = true; // Group Trades by Source input bool ShowCorrelation = true; // Show Position Correlation input color InternalTradeColor = clrAqua; // Internal Trade Color input color ExternalTradeColor = clrOrange; // External Trade Color input color WarningColor = clrYellow; // Warning Color //--- Reporting Options input group "=== REPORTING OPTIONS ===" input bool GenerateReports = true; // Generate Periodic Reports input bool ExportCSV = true; // Export Reports to CSV input bool DetectEAsOnStartup = true; // Detect All EAs on Startup input bool AutoDetectSymbols = true; // Auto-Detect Traded Symbols input bool DebugMode = false; // Enable Debug Mode //+------------------------------------------------------------------+ //| GLOBAL OBJECTS | //+------------------------------------------------------------------+ //--- Module instances CRiskManager *RiskMgr; CTradeManager *TradeMgr; CEntrySystem *EntrySys; CTechnicalAnalysis *TechAnalysis; CDashboardEnhanced *Dashboard; CUtilities *Utils; CMultiTradeReporter *Reporter; //--- System state SystemState g_SystemState; PerformanceMetrics g_Performance; MarketConditions g_MarketConditions; //--- Trade tracking ManagedTrade g_ManagedTrades[]; int g_TotalTrades = 0; //--- Multi-symbol monitoring string g_MonitoredSymbols[]; int g_SymbolCount = 0; //--- Timing variables datetime g_LastUpdateTime = 0; datetime g_LastTradeTime = 0; datetime g_LastReportTime = 0; datetime g_LastSymbolScan = 0; datetime g_LastDiagnostic = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Initialize system state g_SystemState.is_active = SystemEnabled; g_SystemState.magic_number = TradingMagic; g_SystemState.start_balance = AccountInfoDouble(ACCOUNT_BALANCE); g_SystemState.peak_balance = g_SystemState.start_balance; g_SystemState.session_start = TimeCurrent(); //--- Create module instances RiskMgr = new CRiskManager(); TradeMgr = new CTradeManager(); EntrySys = new CEntrySystem(); TechAnalysis = new CTechnicalAnalysis(); Dashboard = new CDashboardEnhanced(); Utils = new CUtilities(); Reporter = new CMultiTradeReporter(); //--- In OnInit() // Initialize Symbol Manager (singleton) CSymbolManager *symbolMgr = CSymbolManager::GetInstance(); // Initialize Performance Tracker CPerformanceTracker *perfTracker = new CPerformanceTracker(); perfTracker.Initialize(1000, 252); // Initialize Trade Executor CTradeExecutor *tradeExec = new CTradeExecutor(); tradeExec.Initialize(TradingMagic, 10); tradeExec.SetSymbolManager(symbolMgr); // Update Dashboard to use new version CDashboardEnhanced *dashboard = new CDashboardEnhanced(); dashboard.SetReferences(symbolMgr, perfTracker); //--- Initialize modules if(!InitializeModules()) { Print("Failed to initialize modules"); return(INIT_FAILED); } //--- Wait for indicators to be ready if(MQLInfoInteger(MQL_TESTER)) { Print("Backtest mode: Waiting for indicators to initialize..."); int required_bars = MathMax(200, TechnicalLookback); if(Bars(_Symbol, PERIOD_CURRENT) < required_bars) { Print("Insufficient bars for indicator calculation. Need ", required_bars, ", have ", Bars(_Symbol, PERIOD_CURRENT)); return(INIT_FAILED); } double test_atr = (*TechAnalysis).GetATR(14); if(test_atr <= 0) { Print("ATR indicator not ready. Please ensure sufficient historical data."); return(INIT_FAILED); } Print("Indicators initialized successfully. ATR: ", test_atr); } //--- Initialize performance metrics ZeroMemory(g_Performance); //--- Initialize managed trades array ArrayResize(g_ManagedTrades, 0); ArraySetAsSeries(g_ManagedTrades, false); //--- Initialize multi-symbol monitoring if(ManageExternalTrades) { InitializeSymbolMonitoring(); //--- Initial detection if(DetectEAsOnStartup) { DetectAllEAs(); } //--- Initial external trade scan Print("Performing initial external trade scan..."); CheckForNewExternalTradesEnhanced(); //--- Run diagnostic if in debug mode if(DebugMode) { RunExternalTradeDiagnostics(); } } //--- Load existing positions LoadExistingPositions(); //--- Create dashboard if(ShowDashboard) { (*Dashboard).Create(DashboardX, DashboardY, DashboardColor, ProfitColor, LossColor); (*Dashboard).Update(g_Performance, g_ManagedTrades, g_MarketConditions); } //--- Initialize reporter if(Reporter != NULL && GenerateReports) { (*Reporter).Initialize("Reports"); } //--- Set timer for periodic updates EventSetTimer(UpdateFrequency); //--- Log initialization (*Utils).Log(LOG_INFO, StringFormat("Risk Management Overlay v7.1 initialized. Balance: %.2f", g_SystemState.start_balance)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Kill timer EventKillTimer(); //--- Save final report if(Utils != NULL && GenerateReports) (*Utils).GenerateReport(g_Performance, g_ManagedTrades); //--- Cleanup modules if(Dashboard != NULL && ShowDashboard) (*Dashboard).Destroy(); //--- Delete module instances delete Reporter; delete RiskMgr; delete TradeMgr; delete EntrySys; delete TechAnalysis; delete Dashboard; delete Utils; //--- Log shutdown Print("Risk Management Overlay shutdown: ", (*Utils).GetUninitReasonText(reason)); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Check if system is enabled if(!g_SystemState.is_active || !SystemEnabled) return; //--- Check terminal connection if(!TerminalInfoInteger(TERMINAL_CONNECTED)) return; //--- Check terminal connection and auto trading if(Utils != NULL) { if(!(*Utils).CheckTerminalConnection()) return; if(!(*Utils).CheckAutoTrading()) return; } //--- Update market conditions UpdateMarketConditions(); //--- Process existing trades ProcessManagedTrades(); //--- Check for new external trades (enhanced multi-symbol) if(ManageExternalTrades) { CheckForNewExternalTradesEnhanced(); } //--- Check entry signals (if enabled) if(EntryMode != ENTRY_DISABLED) CheckEntrySignals(); //--- Update dashboard if(ShowDashboard && TimeCurrent() - g_LastUpdateTime >= UpdateFrequency) { (*Dashboard).Update(g_Performance, g_ManagedTrades, g_MarketConditions); g_LastUpdateTime = TimeCurrent(); } //--- Periodic tasks PerformPeriodicTasks(); //--- Debug output if enabled if(DebugMode) { static datetime last_debug = 0; if(TimeCurrent() - last_debug > 2) { string debug = StringFormat("DEBUG: Pos=%d Array=%d Ext=%d", PositionsTotal(), ArraySize(g_ManagedTrades), CountExternalTrades()); Comment(debug); last_debug = TimeCurrent(); } } } //+------------------------------------------------------------------+ //| Timer function for periodic updates | //+------------------------------------------------------------------+ void OnTimer() { //--- Update dashboard if(ShowDashboard) { (*Dashboard).Update(g_Performance, g_ManagedTrades, g_MarketConditions); } //--- Monitor positions if(DebugMode) { MonitorPositions(); } //--- Periodic EA detection static datetime last_ea_detect = 0; if(ManageExternalTrades && TimeCurrent() - last_ea_detect > 300) // Every 5 minutes { if(AutoDetectSymbols) { DetectTradedSymbols(); } last_ea_detect = TimeCurrent(); } } //+------------------------------------------------------------------+ //| Initialize symbol monitoring list | //+------------------------------------------------------------------+ void InitializeSymbolMonitoring() { if(AutoDetectSymbols) { // Auto-detect all symbols with open positions DetectTradedSymbols(); } else { // Manual symbol list - customize as needed g_SymbolCount = 10; ArrayResize(g_MonitoredSymbols, g_SymbolCount); g_MonitoredSymbols[0] = "EURUSD"; g_MonitoredSymbols[1] = "GBPUSD"; g_MonitoredSymbols[2] = "USDJPY"; g_MonitoredSymbols[3] = "AUDUSD"; g_MonitoredSymbols[4] = "USDCAD"; g_MonitoredSymbols[5] = "NZDUSD"; g_MonitoredSymbols[6] = "USDCHF"; g_MonitoredSymbols[7] = "EURJPY"; g_MonitoredSymbols[8] = "GBPJPY"; g_MonitoredSymbols[9] = "GOLD"; } Print("Symbol Monitoring initialized with ", g_SymbolCount, " symbols"); } //+------------------------------------------------------------------+ //| Auto-detect all symbols with positions | //+------------------------------------------------------------------+ void DetectTradedSymbols() { // Clear existing array ArrayFree(g_MonitoredSymbols); g_SymbolCount = 0; // Temporary array to collect unique symbols string temp_symbols[]; int temp_count = 0; // Scan all positions int total_positions = PositionsTotal(); for(int i = 0; i < total_positions; i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { string symbol = PositionGetString(POSITION_SYMBOL); // Check if symbol already in list bool found = false; for(int j = 0; j < temp_count; j++) { if(temp_symbols[j] == symbol) { found = true; break; } } // Add new symbol if(!found) { ArrayResize(temp_symbols, temp_count + 1); temp_symbols[temp_count] = symbol; temp_count++; } } } // Also add current chart symbol if not already included bool current_found = false; for(int i = 0; i < temp_count; i++) { if(temp_symbols[i] == _Symbol) { current_found = true; break; } } if(!current_found) { ArrayResize(temp_symbols, temp_count + 1); temp_symbols[temp_count] = _Symbol; temp_count++; } // Copy to global array g_SymbolCount = temp_count; ArrayResize(g_MonitoredSymbols, g_SymbolCount); for(int i = 0; i < g_SymbolCount; i++) { g_MonitoredSymbols[i] = temp_symbols[i]; } // Log detected symbols if(g_SymbolCount > 0) { string symbol_list = "Detected symbols: "; for(int i = 0; i < g_SymbolCount; i++) { symbol_list += g_MonitoredSymbols[i]; if(i < g_SymbolCount - 1) symbol_list += ", "; } (*Utils).Log(LOG_INFO, symbol_list); } } //+------------------------------------------------------------------+ //| Enhanced multi-symbol external trade detection | //+------------------------------------------------------------------+ void CheckForNewExternalTradesEnhanced() { static datetime last_symbol_update = 0; // Update symbol list periodically (every 60 seconds) if(AutoDetectSymbols && TimeCurrent() - last_symbol_update > 60) { DetectTradedSymbols(); last_symbol_update = TimeCurrent(); } // Scan all positions int total_positions = PositionsTotal(); int external_trades_found = 0; int trades_added = 0; for(int i = 0; i < total_positions; i++) { ulong ticket = PositionGetTicket(i); if(!ticket) continue; if(PositionSelectByTicket(ticket)) { // Get position details string symbol = PositionGetString(POSITION_SYMBOL); ulong magic = PositionGetInteger(POSITION_MAGIC); // Skip our own trades if(magic == TradingMagic) { continue; } // Check if already managed if(IsTradeManaged(ticket)) { continue; } // Apply magic number filter if(MagicNumberFilter != 0 && magic != MagicNumberFilter) { continue; } external_trades_found++; // Create managed trade entry ManagedTrade trade; if(CreateManagedTradeEnhanced(trade, ticket, symbol)) { // Mark as external trade trade.is_external = true; trade.entry_reason = "External: " + GetEANameFromMagic(magic); // Apply risk rules if configured if(ForceRiskRules) { (*Utils).Log(LOG_INFO, StringFormat("Applying risk rules to external trade #%d on %s", ticket, symbol)); (*RiskMgr).EnforceRiskRules(trade, DefaultExternalRisk, CloseExcessiveRisk); } // Add to managed trades array if(AddManagedTrade(trade)) { trades_added++; (*Utils).Log(LOG_INFO, StringFormat("Added external trade #%d (%s %.2f lots) from %s to management", ticket, symbol, trade.volume, GetEANameFromMagic(magic))); // Apply default stops if needed if((trade.sl == 0 && ForceStopLoss) || (trade.tp == 0 && ForceTakeProfit)) { (*Utils).Log(LOG_INFO, "Applying default stops to external trade"); // Get ATR for the specific symbol double symbol_atr = GetSymbolATR(symbol); (*TradeMgr).ApplyDefaultStops(trade, symbol_atr); } } } } } if(external_trades_found > 0 || trades_added > 0) { (*Utils).Log(LOG_DEBUG, StringFormat("External trade scan complete: Found %d, Added %d new trades", external_trades_found, trades_added)); } } //+------------------------------------------------------------------+ //| Create managed trade with multi-symbol support | //+------------------------------------------------------------------+ bool CreateManagedTradeEnhanced(ManagedTrade &trade, ulong ticket, string symbol) { // Ensure we're working with the correct position if(!PositionSelectByTicket(ticket)) { (*Utils).Log(LOG_ERROR, StringFormat("Failed to select position #%d", ticket)); return false; } // Verify symbol matches if(PositionGetString(POSITION_SYMBOL) != symbol) { (*Utils).Log(LOG_ERROR, StringFormat("Symbol mismatch for position #%d", ticket)); return false; } // Fill trade structure trade.ticket = ticket; trade.symbol = symbol; trade.magic = PositionGetInteger(POSITION_MAGIC); trade.type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); trade.volume = PositionGetDouble(POSITION_VOLUME); trade.current_volume = trade.volume; trade.open_price = PositionGetDouble(POSITION_PRICE_OPEN); trade.open_time = (datetime)PositionGetInteger(POSITION_TIME); trade.sl = PositionGetDouble(POSITION_SL); trade.tp = PositionGetDouble(POSITION_TP); trade.profit = PositionGetDouble(POSITION_PROFIT); trade.swap = PositionGetDouble(POSITION_SWAP); trade.comment = PositionGetString(POSITION_COMMENT); // Get commission from deals trade.commission = (*Utils).CalculatePositionCommission(ticket); // Calculate risk metrics for the specific symbol if(trade.sl > 0) { double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double stop_distance; if(trade.type == POSITION_TYPE_BUY) stop_distance = trade.open_price - trade.sl; else stop_distance = trade.sl - trade.open_price; if(stop_distance > 0 && tick_size > 0) { double potential_loss = (stop_distance / tick_size) * tick_value * trade.volume; trade.risk_amount = potential_loss; trade.risk_percent = (potential_loss / AccountInfoDouble(ACCOUNT_BALANCE)) * 100; } } else { // No stop loss - use default risk calculation trade.risk_amount = 0; trade.risk_percent = DefaultExternalRisk; } // Calculate current metrics double current_price = (trade.type == POSITION_TYPE_BUY) ? SymbolInfoDouble(symbol, SYMBOL_BID) : SymbolInfoDouble(symbol, SYMBOL_ASK); // Calculate R-multiple if(trade.risk_amount > 0) { double current_pl = trade.profit + trade.swap + trade.commission; trade.r_multiple = current_pl / trade.risk_amount; } else { trade.r_multiple = 0; } // Calculate MAE/MFE (simplified for initial creation) trade.mae = 0; trade.mfe = 0; // Management flags trade.is_managed = true; trade.is_external = true; trade.be_activated = false; trade.trailing_activated = false; trade.partial_count = 0; // Time tracking trade.bars_in_trade = 0; trade.management_start = TimeCurrent(); return true; } //+------------------------------------------------------------------+ //| Get ATR for specific symbol | //+------------------------------------------------------------------+ double GetSymbolATR(string symbol, int period = 14) { int atr_handle = iATR(symbol, PERIOD_CURRENT, period); if(atr_handle == INVALID_HANDLE) { (*Utils).Log(LOG_ERROR, "Failed to create ATR handle for " + symbol); return 50 * SymbolInfoDouble(symbol, SYMBOL_POINT); // Default fallback } double atr_buffer[1]; if(CopyBuffer(atr_handle, 0, 0, 1, atr_buffer) > 0 && atr_buffer[0] > 0) { IndicatorRelease(atr_handle); return atr_buffer[0]; } IndicatorRelease(atr_handle); // Fallback calculation double sum = 0; for(int i = 1; i <= period; i++) { double high = iHigh(symbol, PERIOD_CURRENT, i); double low = iLow(symbol, PERIOD_CURRENT, i); double close_prev = iClose(symbol, PERIOD_CURRENT, i + 1); if(high > 0 && low > 0 && close_prev > 0) { double tr = MathMax(high - low, MathMax(MathAbs(high - close_prev), MathAbs(low - close_prev))); sum += tr; } } return (sum > 0) ? sum / period : 50 * SymbolInfoDouble(symbol, SYMBOL_POINT); } //+------------------------------------------------------------------+ //| Count external trades in array | //+------------------------------------------------------------------+ int CountExternalTrades() { int count = 0; for(int i = 0; i < ArraySize(g_ManagedTrades); i++) { if(g_ManagedTrades[i].is_external) count++; } return count; } //+------------------------------------------------------------------+ //| Monitor positions (debug function) | //+------------------------------------------------------------------+ void MonitorPositions() { static datetime last_check = 0; static int last_total = -1; // Check every 5 seconds if(TimeCurrent() - last_check < 5) return; last_check = TimeCurrent(); int total = PositionsTotal(); // Only print if changed if(total != last_total) { last_total = total; string summary = StringFormat("\n[POSITION MONITOR] Total: %d | Managed Array: %d | ", total, ArraySize(g_ManagedTrades)); // Count by type int own = 0, ext = 0, managed_ext = 0; for(int i = 0; i < total; i++) { if(PositionSelectByTicket(PositionGetTicket(i))) { ulong magic = PositionGetInteger(POSITION_MAGIC); if(magic == TradingMagic) own++; else { ext++; if(IsTradeManaged(PositionGetTicket(i))) managed_ext++; } } } summary += StringFormat("Own: %d | External: %d (Managed: %d)", own, ext, managed_ext); Print(summary); // If external trades exist but aren't managed, run diagnostic if(ext > 0 && managed_ext == 0 && ManageExternalTrades) { Print("⚠️ External trades not being managed! Running diagnostic..."); RunExternalTradeDiagnostics(); } } } //+------------------------------------------------------------------+ //| Run external trade diagnostics | //+------------------------------------------------------------------+ void RunExternalTradeDiagnostics() { Print("\n========== EXTERNAL TRADE DETECTION DIAGNOSTICS =========="); Print("Timestamp: ", TimeToString(TimeCurrent())); Print("Running from: ", _Symbol, " ", EnumToString((ENUM_TIMEFRAMES)_Period)); //--- 1. Check EA Settings Print("\n[1] EA CONFIGURATION CHECK:"); Print(" SystemEnabled: ", SystemEnabled ? "YES" : "NO"); Print(" ManageExternalTrades: ", ManageExternalTrades ? "ENABLED" : "DISABLED"); Print(" MagicNumberFilter: ", MagicNumberFilter, (MagicNumberFilter == 0) ? " (All external trades)" : " (Specific magic only)"); Print(" TradingMagic (Own): ", TradingMagic); Print(" ForceRiskRules: ", ForceRiskRules ? "YES" : "NO"); Print(" DefaultExternalRisk: ", DoubleToString(DefaultExternalRisk, 2), "%"); Print(" AutoDetectSymbols: ", AutoDetectSymbols ? "YES" : "NO"); //--- 2. Scan all open positions Print("\n[2] POSITION SCAN:"); int total_positions = PositionsTotal(); Print(" Total positions in terminal: ", total_positions); if(total_positions == 0) { Print(" ⚠️ NO OPEN POSITIONS FOUND!"); Print(" Make sure other EAs have open trades."); return; } //--- Categorize positions int own_trades = 0; int external_trades = 0; int filtered_trades = 0; int managed_trades = 0; Print("\n[3] POSITION DETAILS:"); for(int i = 0; i < total_positions; i++) { ulong ticket = PositionGetTicket(i); if(ticket == 0) { Print(" Error getting ticket at index ", i); continue; } if(!PositionSelectByTicket(ticket)) { Print(" Error selecting position ", ticket); continue; } string symbol = PositionGetString(POSITION_SYMBOL); ulong magic = PositionGetInteger(POSITION_MAGIC); double volume = PositionGetDouble(POSITION_VOLUME); string type = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? "BUY" : "SELL"; bool is_managed = IsTradeManaged(ticket); Print("\n Position #", ticket, ":"); Print(" - Symbol: ", symbol); Print(" - Type: ", type); Print(" - Volume: ", DoubleToString(volume, 2)); Print(" - Magic: ", magic, " (", GetEANameFromMagic(magic), ")"); // Determine status if(magic == TradingMagic) { own_trades++; Print(" - Status: OWN TRADE (will skip)"); } else if(MagicNumberFilter != 0 && magic != MagicNumberFilter) { filtered_trades++; Print(" - Status: FILTERED OUT (magic doesn't match filter ", MagicNumberFilter, ")"); } else if(is_managed) { managed_trades++; Print(" - Status: ALREADY MANAGED ✓"); } else { external_trades++; Print(" - Status: EXTERNAL TRADE - SHOULD BE ADDED! ⚠️"); if(!ManageExternalTrades) { Print(" → ISSUE: ManageExternalTrades is DISABLED!"); } } } //--- 4. Summary Print("\n[4] SUMMARY:"); Print(" Own trades: ", own_trades); Print(" External trades (eligible): ", external_trades); Print(" Filtered out: ", filtered_trades); Print(" Already managed: ", managed_trades); //--- 5. Check managed trades array Print("\n[5] MANAGED TRADES ARRAY:"); int array_size = ArraySize(g_ManagedTrades); Print(" Size of g_ManagedTrades: ", array_size); if(array_size > 0) { int internal_count = 0; int external_count = 0; for(int i = 0; i < array_size; i++) { if(g_ManagedTrades[i].is_external) external_count++; else internal_count++; Print(" Trade[", i, "]: #", g_ManagedTrades[i].ticket, " ", g_ManagedTrades[i].symbol, " Magic: ", g_ManagedTrades[i].magic, " External: ", g_ManagedTrades[i].is_external ? "YES" : "NO", " Valid: ", (g_ManagedTrades[i].ticket > 0) ? "YES" : "NO"); } Print(" Internal trades in array: ", internal_count); Print(" External trades in array: ", external_count); } else { Print(" ⚠️ Managed trades array is EMPTY!"); } //--- 6. Symbol monitoring Print("\n[6] SYMBOL MONITORING:"); Print(" Monitored symbols: ", g_SymbolCount); for(int i = 0; i < g_SymbolCount; i++) { Print(" - ", g_MonitoredSymbols[i]); } //--- 7. Dashboard check Print("\n[7] DASHBOARD STATUS:"); Print(" ShowDashboard: ", ShowDashboard ? "ENABLED" : "DISABLED"); Print(" Dashboard pointer: ", (Dashboard != NULL) ? "VALID" : "NULL"); //--- 8. Recommendations Print("\n[8] DIAGNOSTIC RECOMMENDATIONS:"); if(!SystemEnabled) { Print(" ❌ CRITICAL: SystemEnabled is FALSE - EA is disabled!"); } if(!ManageExternalTrades) { Print(" ❌ CRITICAL: Enable ManageExternalTrades to detect external trades!"); } if(external_trades > 0 && external_count == 0) { Print(" ❌ ISSUE: External trades exist but none in managed array!"); Print(" → Verify CheckForNewExternalTradesEnhanced() is being called in OnTick()"); Print(" → Check if AddManagedTrade() function is working correctly"); Print(" → Ensure CreateManagedTradeEnhanced() is creating valid trade objects"); } if(MagicNumberFilter != 0 && filtered_trades > 0) { Print(" ⚠️ WARNING: ", filtered_trades, " trades filtered out by MagicNumberFilter"); Print(" → Set MagicNumberFilter = 0 to manage ALL external trades"); } if(array_size == 0 && (own_trades > 0 || external_trades > 0)) { Print(" ❌ CRITICAL: Managed trades array is empty but trades exist!"); Print(" → Check array initialization in OnInit()"); Print(" → Verify ProcessManagedTrades() isn't clearing the array"); } Print("\n========== END OF DIAGNOSTICS ==========\n"); } //+------------------------------------------------------------------+ //| Add managed trade to array with validation | //+------------------------------------------------------------------+ bool AddManagedTrade(ManagedTrade &trade) { // Validate trade if(trade.ticket == 0) { (*Utils).Log(LOG_ERROR, "Cannot add trade with ticket 0"); return false; } // Check if already exists if(IsTradeManaged(trade.ticket)) { (*Utils).Log(LOG_WARNING, StringFormat("Trade #%d already managed", trade.ticket)); return false; } // Add to array int size = ArraySize(g_ManagedTrades); if(ArrayResize(g_ManagedTrades, size + 1) < 0) { (*Utils).Log(LOG_ERROR, "Failed to resize managed trades array"); return false; } g_ManagedTrades[size] = trade; g_TotalTrades++; (*Utils).Log(LOG_DEBUG, StringFormat("Added trade #%d to position %d in array", trade.ticket, size)); return true; } //+------------------------------------------------------------------+ //| Create managed trade structure (for compatibility) | //+------------------------------------------------------------------+ bool CreateManagedTrade(ManagedTrade &trade, ulong ticket) { if(!PositionSelectByTicket(ticket)) return false; string symbol = PositionGetString(POSITION_SYMBOL); return CreateManagedTradeEnhanced(trade, ticket, symbol); } //+------------------------------------------------------------------+ //| Initialize all modules | //+------------------------------------------------------------------+ bool InitializeModules() { //--- Initialize Risk Manager RiskManagerConfig riskConfig; riskConfig.sizing_mode = SizingMode; riskConfig.risk_percent = RiskPercent; riskConfig.max_risk_percent = MaxRiskPercent; riskConfig.max_daily_dd = MaxDailyDrawdown; riskConfig.max_exposure = MaxTotalExposure; riskConfig.use_kelly = UseKellyCriterion; riskConfig.kelly_fraction = KellyFraction; riskConfig.min_lot_size = MinLotSize; riskConfig.max_lot_size = MaxLotSize; if(!(*RiskMgr).Initialize(riskConfig)) return false; //--- Initialize Trade Manager TradeManagerConfig tradeConfig; tradeConfig.tp_mode = TPMode; tradeConfig.sl_mode = SLMode; tradeConfig.enable_breakeven = EnableBreakeven; tradeConfig.breakeven_trigger = BreakevenTrigger; tradeConfig.enable_trailing = EnableTrailing; tradeConfig.trailing_start = TrailingStart; tradeConfig.enable_partial = EnablePartialClose; tradeConfig.partial_levels = PartialLevels; tradeConfig.force_sl = ForceStopLoss; tradeConfig.force_tp = ForceTakeProfit; tradeConfig.override_sl = OverrideExternalSL; tradeConfig.override_tp = OverrideExternalTP; if(!(*TradeMgr).Initialize(tradeConfig, TradingMagic)) return false; //--- Initialize Entry System EntrySystemConfig entryConfig; entryConfig.entry_mode = EntryMode; entryConfig.max_positions = MaxPositions; entryConfig.min_time_between = MinTimeBetweenTrades; entryConfig.allow_multiple = EnableMultipleEntries; if(!(*EntrySys).Initialize(entryConfig)) return false; //--- Initialize Technical Analysis TechnicalConfig techConfig; techConfig.use_sr = UseSupportResistance; techConfig.use_fib = UseFibonacci; techConfig.use_pivot = UsePivotPoints; techConfig.use_structure = UseMarketStructure; techConfig.lookback = TechnicalLookback; if(!(*TechAnalysis).Initialize(techConfig)) return false; //--- Initialize Utilities if(!(*Utils).Initialize(LogLevel)) return false; return true; } //+------------------------------------------------------------------+ //| Load existing positions into management system | //+------------------------------------------------------------------+ void LoadExistingPositions() { int total = PositionsTotal(); int loaded = 0; for(int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if(!PositionSelectByTicket(ticket)) continue; string symbol = PositionGetString(POSITION_SYMBOL); ulong magic = PositionGetInteger(POSITION_MAGIC); bool should_manage = false; //--- Check if we should manage this position if(magic == TradingMagic) { should_manage = true; } else if(ManageExternalTrades && (MagicNumberFilter == 0 || magic == MagicNumberFilter)) { should_manage = true; } if(should_manage && !IsTradeManaged(ticket)) { ManagedTrade trade; if(CreateManagedTradeEnhanced(trade, ticket, symbol)) { if(magic != TradingMagic) trade.is_external = true; if(AddManagedTrade(trade)) { loaded++; (*Utils).Log(LOG_INFO, StringFormat("Loaded position #%d (%s) into management", ticket, symbol)); } } } } if(loaded > 0) { (*Utils).Log(LOG_INFO, StringFormat("Loaded %d existing positions", loaded)); } } //+------------------------------------------------------------------+ //| Update market conditions | //+------------------------------------------------------------------+ void UpdateMarketConditions() { // Get fresh market analysis g_MarketConditions = (*TechAnalysis).AnalyzeMarket(); // Additional validation and fallback if(g_MarketConditions.volatility <= 0) { Print("UpdateMarketConditions: Invalid volatility from TechAnalysis, calculating fallback"); // Direct ATR calculation double atr = (*TechAnalysis).GetATR(14); if(atr > 0) { g_MarketConditions.volatility = atr; Print("UpdateMarketConditions: Set volatility to ", atr); } else { // Emergency fallback double price = SymbolInfoDouble(_Symbol, SYMBOL_BID); g_MarketConditions.volatility = price * 0.001; // 0.1% of price Print("UpdateMarketConditions: Using emergency volatility: ", g_MarketConditions.volatility); } } g_MarketConditions.spread = (double)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); //--- Update risk manager with market conditions (*RiskMgr).UpdateMarketConditions(g_MarketConditions); } //+------------------------------------------------------------------+ //| Process all managed trades | //+------------------------------------------------------------------+ void ProcessManagedTrades() { for(int i = ArraySize(g_ManagedTrades) - 1; i >= 0; i--) { //--- Check if position still exists if(!PositionSelectByTicket(g_ManagedTrades[i].ticket)) { //--- Position closed, update performance UpdatePerformanceMetrics(g_ManagedTrades[i]); //--- Save to history if external if(g_ManagedTrades[i].is_external) { (*Utils).SaveTradeHistory(g_ManagedTrades[i]); } RemoveManagedTrade(i); continue; } //--- Update trade information UpdateTradeInfo(g_ManagedTrades[i]); //--- Apply risk management (*RiskMgr).ValidateAndAdjustRisk(g_ManagedTrades[i]); //--- Apply trade management (*TradeMgr).ManageTrade(g_ManagedTrades[i], g_MarketConditions); } } //+------------------------------------------------------------------+ //| Check entry signals | //+------------------------------------------------------------------+ void CheckEntrySignals() { //--- Check position limits if(ArraySize(g_ManagedTrades) >= MaxPositions) { if(EnableLogging) (*Utils).Log(LOG_DEBUG, "Max positions reached"); return; } //--- Check time restriction if(TimeCurrent() - g_LastTradeTime < MinTimeBetweenTrades * 60) { if(EnableLogging) (*Utils).Log(LOG_DEBUG, "Time restriction active"); return; } //--- Ensure valid market conditions if(g_MarketConditions.volatility <= 0) { UpdateMarketConditions(); } //--- Get entry signal EntrySignal signal = (*EntrySys).CheckSignal(g_MarketConditions); if(signal.signal_type != SIGNAL_NONE) { // Additional safety check if(signal.stop_loss_distance <= 0) { (*Utils).Log(LOG_ERROR, StringFormat("Zero stop distance detected! Signal: %s", signal.comment)); // Emergency fallback double emergency_stop = 50 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); signal.stop_loss_distance = emergency_stop; signal.take_profit_distance = emergency_stop * 2; (*Utils).Log(LOG_WARNING, StringFormat("Applied emergency stop: %.5f", emergency_stop)); } //--- Calculate position size double lotSize = (*RiskMgr).CalculatePositionSize(signal.stop_loss_distance); if(lotSize > 0 && (*RiskMgr).ValidateNewPosition(lotSize, signal.stop_loss_distance)) { //--- Prepare trade request TradeRequest request; request.symbol = _Symbol; request.volume = lotSize; request.type = (signal.signal_type == SIGNAL_BUY) ? ORDER_TYPE_BUY : ORDER_TYPE_SELL; request.sl_distance = signal.stop_loss_distance; request.tp_distance = signal.take_profit_distance; request.comment = signal.comment; //--- Execute trade ulong ticket = (*TradeMgr).OpenPosition(request); if(ticket > 0) { g_LastTradeTime = TimeCurrent(); //--- Add to managed trades ManagedTrade trade; if(CreateManagedTrade(trade, ticket)) { trade.entry_reason = signal.comment; trade.entry_signal = signal; trade.is_external = false; if(AddManagedTrade(trade)) { (*Utils).Log(LOG_INFO, StringFormat("Opened %s position #%d, Lots: %.2f, Risk: %.2f%%", (signal.signal_type == SIGNAL_BUY) ? "BUY" : "SELL", ticket, lotSize, RiskPercent)); } } } } } } //+------------------------------------------------------------------+ //| Perform periodic maintenance tasks | //+------------------------------------------------------------------+ void PerformPeriodicTasks() { //--- Daily reset check MqlDateTime current_time; TimeToStruct(TimeCurrent(), current_time); static int last_day = -1; if(current_time.day != last_day) { last_day = current_time.day; ResetDailyMetrics(); } //--- Generate periodic reports if(GenerateReports && TimeCurrent() - g_LastReportTime > 3600) // Hourly { (*Utils).GenerateReport(g_Performance, g_ManagedTrades); if(Reporter != NULL) { (*Reporter).GenerateFullReport(g_ManagedTrades, g_Performance); } g_LastReportTime = TimeCurrent(); } //--- Check for news events if((*Utils).IsNewsTime()) { g_MarketConditions.news_event = true; } } //+------------------------------------------------------------------+ //| Remove trade from managed array | //+------------------------------------------------------------------+ void RemoveManagedTrade(int index) { int size = ArraySize(g_ManagedTrades); if(index < 0 || index >= size) return; for(int i = index; i < size - 1; i++) { g_ManagedTrades[i] = g_ManagedTrades[i + 1]; } ArrayResize(g_ManagedTrades, size - 1); } //+------------------------------------------------------------------+ //| Check if trade is already managed | //+------------------------------------------------------------------+ bool IsTradeManaged(ulong ticket) { for(int i = 0; i < ArraySize(g_ManagedTrades); i++) { if(g_ManagedTrades[i].ticket == ticket) return true; } return false; } //+------------------------------------------------------------------+ //| Update trade information | //+------------------------------------------------------------------+ void UpdateTradeInfo(ManagedTrade &trade) { if(!PositionSelectByTicket(trade.ticket)) return; trade.current_volume = PositionGetDouble(POSITION_VOLUME); trade.sl = PositionGetDouble(POSITION_SL); trade.tp = PositionGetDouble(POSITION_TP); trade.profit = PositionGetDouble(POSITION_PROFIT); trade.commission = (*Utils).CalculatePositionCommission(trade.ticket); trade.swap = PositionGetDouble(POSITION_SWAP); //--- Update max profit/drawdown double total_profit = trade.profit + trade.commission + trade.swap; if(total_profit > trade.max_profit) trade.max_profit = total_profit; if(total_profit < trade.max_drawdown) trade.max_drawdown = total_profit; //--- Update R-multiple if(trade.risk_amount > 0) { trade.r_multiple = total_profit / trade.risk_amount; } } //+------------------------------------------------------------------+ //| Update performance metrics | //+------------------------------------------------------------------+ void UpdatePerformanceMetrics(ManagedTrade &trade) { double final_profit = trade.profit + trade.commission + trade.swap; //--- Update counts g_Performance.total_trades++; if(final_profit > 0) { g_Performance.winning_trades++; g_Performance.gross_profit += final_profit; g_Performance.consecutive_wins++; g_Performance.consecutive_losses = 0; } else { g_Performance.losing_trades++; g_Performance.gross_loss += MathAbs(final_profit); g_Performance.consecutive_losses++; g_Performance.consecutive_wins = 0; } //--- Update max consecutive if(g_Performance.consecutive_wins > g_Performance.max_consecutive_wins) g_Performance.max_consecutive_wins = g_Performance.consecutive_wins; if(g_Performance.consecutive_losses > g_Performance.max_consecutive_losses) g_Performance.max_consecutive_losses = g_Performance.consecutive_losses; //--- Update profit factor and win rate if(g_Performance.gross_loss > 0) g_Performance.profit_factor = g_Performance.gross_profit / g_Performance.gross_loss; else g_Performance.profit_factor = (g_Performance.gross_profit > 0) ? 999.99 : 0; g_Performance.win_rate = (g_Performance.total_trades > 0) ? (double)g_Performance.winning_trades / g_Performance.total_trades * 100 : 0; //--- Update drawdown double current_balance = AccountInfoDouble(ACCOUNT_BALANCE); if(current_balance > g_SystemState.peak_balance) g_SystemState.peak_balance = current_balance; double drawdown = (g_SystemState.peak_balance - current_balance) / g_SystemState.peak_balance * 100; if(drawdown > g_Performance.max_drawdown_percent) g_Performance.max_drawdown_percent = drawdown; //--- Update net profit g_Performance.net_profit = g_Performance.gross_profit - g_Performance.gross_loss; //--- Update expectancy if(g_Performance.total_trades > 0) g_Performance.expectancy = g_Performance.net_profit / g_Performance.total_trades; //--- Update average win/loss if(g_Performance.winning_trades > 0) g_Performance.avg_win = g_Performance.gross_profit / g_Performance.winning_trades; if(g_Performance.losing_trades > 0) g_Performance.avg_loss = g_Performance.gross_loss / g_Performance.losing_trades; //--- Update daily metrics g_Performance.daily_trades++; g_Performance.daily_profit += final_profit; } //+------------------------------------------------------------------+ //| Reset daily metrics | //+------------------------------------------------------------------+ void ResetDailyMetrics() { g_Performance.daily_profit = 0; g_Performance.daily_trades = 0; g_Performance.daily_volume = 0; (*Utils).Log(LOG_INFO, "Daily metrics reset"); } //+------------------------------------------------------------------+ //| Trade transaction event | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { //--- Handle trade events if(trans.type == TRADE_TRANSACTION_DEAL_ADD) { if(trans.deal_type == DEAL_TYPE_BUY || trans.deal_type == DEAL_TYPE_SELL) { (*Utils).Log(LOG_DEBUG, StringFormat("New deal: #%d, Volume: %.2f", trans.deal, trans.volume)); } } } //+------------------------------------------------------------------+ //| Chart event handler | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handle keyboard shortcuts for debugging if(id == CHARTEVENT_KEYDOWN) { if(lparam == 'D' || lparam == 'd') // D key { RunExternalTradeDiagnostics(); } else if(lparam == 'R' || lparam == 'r') // R key { Print("Forcing external trade refresh..."); CheckForNewExternalTradesEnhanced(); } else if(lparam == 'T' || lparam == 't') // T key { (*Utils).GenerateReport(g_Performance, g_ManagedTrades); } } } //+------------------------------------------------------------------+ //| EA Detection and Monitoring Functions | //+------------------------------------------------------------------+ struct EAInfo { string symbol; long magic_number; string ea_name; int trade_count; double total_volume; double total_risk; double total_profit; }; //+------------------------------------------------------------------+ //| Detect all EAs running on the account | //+------------------------------------------------------------------+ void DetectAllEAs() { Print("=== DETECTING ALL EXPERT ADVISORS ==="); EAInfo detected_eas[]; int ea_count = 0; // Scan all open positions int total_positions = PositionsTotal(); for(int i = 0; i < total_positions; i++) { if(PositionSelectByTicket(PositionGetTicket(i))) { string symbol = PositionGetString(POSITION_SYMBOL); long magic = PositionGetInteger(POSITION_MAGIC); double volume = PositionGetDouble(POSITION_VOLUME); double profit = PositionGetDouble(POSITION_PROFIT); // Check if this magic number already recorded bool found = false; int index = -1; for(int j = 0; j < ea_count; j++) { if(detected_eas[j].magic_number == magic && detected_eas[j].symbol == symbol) { found = true; index = j; break; } } // Add new EA or update existing if(!found) { ArrayResize(detected_eas, ea_count + 1); detected_eas[ea_count].symbol = symbol; detected_eas[ea_count].magic_number = magic; detected_eas[ea_count].ea_name = GetEANameFromMagic(magic); detected_eas[ea_count].trade_count = 1; detected_eas[ea_count].total_volume = volume; detected_eas[ea_count].total_profit = profit; detected_eas[ea_count].total_risk = CalculatePositionRisk(PositionGetTicket(i)); ea_count++; } else { detected_eas[index].trade_count++; detected_eas[index].total_volume += volume; detected_eas[index].total_profit += profit; detected_eas[index].total_risk += CalculatePositionRisk(PositionGetTicket(i)); } } } // Display results Print("\n╔════════════════════════════════════════════════════════╗"); Print("║ DETECTED EXPERT ADVISORS ║"); Print("╚════════════════════════════════════════════════════════╝"); if(ea_count == 0) { Print("No active EA trades detected."); } else { // Sort by magic number for(int i = 0; i < ea_count - 1; i++) { for(int j = i + 1; j < ea_count; j++) { if(detected_eas[i].magic_number > detected_eas[j].magic_number) { EAInfo temp = detected_eas[i]; detected_eas[i] = detected_eas[j]; detected_eas[j] = temp; } } } // Display each EA for(int i = 0; i < ea_count; i++) { Print("\n┌─────────────────────────────────────────────────────────┐"); Print("│ EA #", (i+1), ": ", detected_eas[i].ea_name, " (Magic: ", detected_eas[i].magic_number, ")"); Print("├─────────────────────────────────────────────────────────┤"); Print("│ Symbol: ", detected_eas[i].symbol); Print("│ Active Trades: ", detected_eas[i].trade_count); Print("│ Total Volume: ", DoubleToString(detected_eas[i].total_volume, 2), " lots"); Print("│ Total Risk: ", DoubleToString(detected_eas[i].total_risk, 2), "%"); Print("│ Current P/L: $", DoubleToString(detected_eas[i].total_profit, 2)); Print("└─────────────────────────────────────────────────────────┘"); } } // Configuration suggestions Print("\n╔════════════════════════════════════════════════════════╗"); Print("║ CONFIGURATION SUGGESTIONS ║"); Print("╚════════════════════════════════════════════════════════╝"); if(ea_count > 0) { Print("\nTo manage specific EAs, use these MagicNumberFilter values:"); for(int i = 0; i < ea_count; i++) { if(detected_eas[i].magic_number != 0) // Skip manual trades { Print("- For ", detected_eas[i].ea_name, ": MagicNumberFilter = ", detected_eas[i].magic_number); } } Print("\nTo manage ALL external trades: MagicNumberFilter = 0"); } // Risk warnings double total_risk = 0; for(int i = 0; i < ea_count; i++) { total_risk += detected_eas[i].total_risk; } if(total_risk > 5.0) { Print("\n⚠️ WARNING: Total risk across all EAs: ", DoubleToString(total_risk, 2), "%"); Print("Consider reducing position sizes or number of EAs."); } } //+------------------------------------------------------------------+ //| Get EA name from magic number | //+------------------------------------------------------------------+ string GetEANameFromMagic(long magic) { // Add your known EA magic numbers here switch((int)magic) { case 0: return "Manual Trading"; case 12345: return "Risk Manager EA"; case 55555: return "Commercial EA"; case 77777: return "Scalper EA"; case 88888: return "Grid EA"; case 99999: return "Martingale EA"; // Magic number ranges default: { if(magic >= 10000 && magic < 20000) return StringFormat("External EA (%d)", magic); else if(magic >= 20000 && magic < 30000) return StringFormat("Signal Service (%d)", magic); else if(magic >= 30000 && magic < 40000) return StringFormat("Copy Trader (%d)", magic); else if(magic >= 80000 && magic < 90000) return StringFormat("PAMM/MAM (%d)", magic); else return StringFormat("Unknown EA (%d)", magic); } } } //+------------------------------------------------------------------+ //| Calculate position risk percentage | //+------------------------------------------------------------------+ double CalculatePositionRisk(ulong ticket) { if(!PositionSelectByTicket(ticket)) return 0; string symbol = PositionGetString(POSITION_SYMBOL); double sl = PositionGetDouble(POSITION_SL); double open_price = PositionGetDouble(POSITION_PRICE_OPEN); double volume = PositionGetDouble(POSITION_VOLUME); ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); if(sl == 0) return 0; // No stop loss double stop_distance; if(type == POSITION_TYPE_BUY) stop_distance = open_price - sl; else stop_distance = sl - open_price; if(stop_distance <= 0) return 0; double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); if(tick_size <= 0) return 0; double potential_loss = (stop_distance / tick_size) * tick_value * volume; double balance = AccountInfoDouble(ACCOUNT_BALANCE); return (balance > 0) ? (potential_loss / balance) * 100 : 0; } //+------------------------------------------------------------------+ //| Create EA summary dashboard label | //+------------------------------------------------------------------+ void CreateEASummaryDashboard() { string summary = "═══ EA SUMMARY ═══\n"; int total_positions = PositionsTotal(); long magic_numbers[]; int magic_count = 0; // Collect unique magic numbers for(int i = 0; i < total_positions; i++) { if(PositionSelectByTicket(PositionGetTicket(i))) { long magic = PositionGetInteger(POSITION_MAGIC); bool found = false; for(int j = 0; j < magic_count; j++) { if(magic_numbers[j] == magic) { found = true; break; } } if(!found) { ArrayResize(magic_numbers, magic_count + 1); magic_numbers[magic_count] = magic; magic_count++; } } } // Build summary for(int i = 0; i < magic_count; i++) { int count = 0; double profit = 0; for(int j = 0; j < total_positions; j++) { if(PositionSelectByTicket(PositionGetTicket(j))) { if(PositionGetInteger(POSITION_MAGIC) == magic_numbers[i]) { count++; profit += PositionGetDouble(POSITION_PROFIT); } } } summary += GetEANameFromMagic(magic_numbers[i]) + ": " + IntegerToString(count) + " trades, P/L: $" + DoubleToString(profit, 2) + "\n"; } // Display on chart Comment(summary); } //+------------------------------------------------------------------+