///+------------------------------------------------------------------+ //| ERMT_PME.mq5 v1.3 | //| Enhanced Risk Management Tool - PME | //| Pure Management Edition - No Entry, Exit Only | //| | //| v1.3 CHANGES: | //| - Phase locks NOW act as safety floors only (not active mgmt) | //| - Adaptive trailing is PHASE-AWARE (wider at higher phases) | //| - Volatility logic FIXED (widens stops in high vol, not tighten)| //| - Retreat tightening DISABLED (no penalty for retracements) | //| - Optimized partial closure schedule (earlier, larger %) | //+------------------------------------------------------------------+ #property copyright "ERMT PME v1.3 - Pure Management Edition" #property link "https://github.com/ERMT" #property version "1.3" #property description "Professional position management - Decoupled phase locks & adaptive trailing" //+------------------------------------------------------------------+ //| SYSTEM CONFIGURATION FLAGS (MUST BE BEFORE INCLUDES) | //+------------------------------------------------------------------+ // Control which profit protection systems are active // Set to false to disable a system entirely (cleaner than commenting out code) // IMPORTANT: These must be defined BEFORE including modules #define USE_BREAKEVEN_SYSTEM false // DISABLED - Replaced by phase-based profit locking // Reason: Phase locks provide superior protection // - Breakeven: 8pts fixed lock at 40pts (20% efficiency) // - Phase locks: 10-14pts adaptive at 40pts (35% efficiency) // - Conflict: Both trigger at same 40pts level #define USE_PHASE_LOCKING true // ENABLED - Safety floor protection system (v1.3) // Floor-only locks: 10→200pts minimum guarantees // NO dynamic tightening or breathing room reduction // Maintains highest phase achieved as safety net #define USE_PARTIAL_CLOSURES true // ENABLED - Primary profit-taking mechanism // Banks 75% profit by 150pts (v1.3: earlier triggers) // Creates 10% runner with ultra-wide trail // Optimized schedule for faster profit realization //+------------------------------------------------------------------+ //| Include Modules (AFTER configuration flags) | //+------------------------------------------------------------------+ #include "Modules_PME/DataTypes_PME.mqh" #include "Modules_PME/Utilities_PME.mqh" #include "Modules_PME/RiskManager_PME.mqh" //Original - may work with Galileo FX //#include "Modules_PME/TechnicalAnalysis_PME.mqh" //#include "Modules_PME/PositionManager_PME.mqh" // Fix for premature exits #include "Modules_PME/TechnicalAnalysis_PME_Merged.mqh" #include "Modules_PME/PositionManager_PME_Complete.mqh" #include "Modules_PME/ProfitMaximizer_PME.mqh" ////+------------------------------------------------------------------+ ////| Input Parameters | ////+------------------------------------------------------------------+ // //+------------------------------------------------------------------+ //| PROFIT MAXIMIZATION CONFIGURATION | //+------------------------------------------------------------------+ // === ENHANCED PROFIT SETTINGS (Replace old ones) ===// input group "=== Management Control ===" input bool InpManageAllPositions = true; // Manage all positions input int InpMagicFilter = 0; // 0 = manage all trades input ENUM_MANAGEMENT_MODE InpDefaultMode = MODE_BREAKEVEN_TRAIL; // Default Mode input ENUM_MANAGEMENT_LEVEL InpStartLevel = LEVEL_STANDARD; // Starting Level input group "Profit Maximization Settings" // Phase-Based Management input bool InpUsePhaseManagement = true; // Enable Phase-Based Management input double InpPhase1Trigger = 40; // Phase 1: Protection (points) input double InpPhase2Trigger = 60; // Phase 2: Accumulation (points) input double InpPhase3Trigger = 100; // Phase 3: Maximization (points) input double InpPhase4Trigger = 200; // Phase 4: Runner (points) input double InpPhase5Trigger = 400; // Phase 5: Extreme (points) // === RISK PROTECTION (Priority 1: Critical Risk Limits) === input group "=== Risk Protection ===" input double InpMaxLossPerTrade = 3.0; // Max Loss Per Trade (%) input double InpMaxDailyLoss = 10.0; // Max Daily Loss (%) input double InpMaxDrawdown = 50.0; // Max Drawdown (%) input double InpMaxCorrelation = 0.80; // Max Correlation Between Positions // === EMERGENCY PROTECTION (Wider Stops) === input group "=== Emergency Protection ===" input bool InpApplyEmergencyStops = true; // Apply Emergency Stops input double InpEmergencySLMultiplier = 7.0; // Emergency SL (ATR) input double InpEmergencyTPMultiplier = 4.0; // Emergency TP (ATR) // === DYNAMIC STOP MANAGEMENT === input group "=== Dynamic Stop Management ===" input bool InpDynamicStops = false; // Enable Dynamic Stop Adjustment input bool InpTightenOnProfit = true; // Tighten Stops on Profit input double InpTightenThreshold = 75; // Tighten After (points) input bool InpProtectProfits = true; // Protect Accumulated Profits input double InpProtectionThreshold = 100; // Protection Start (points) // === BREAKEVEN CONFIGURATION === // NOTE: Breakeven system controlled by USE_BREAKEVEN_SYSTEM flag (currently DISABLED) // When USE_BREAKEVEN_SYSTEM = false, these inputs are ignored // Phase-based profit locking provides superior adaptive protection input group "=== Breakeven Settings (Currently Disabled) ===" input bool InpBreakevenEnabled = false; // Enable Breakeven (Disabled by Flag) input double InpBreakevenTrigger = 40; // BE Trigger (points) input double InpBreakevenOffset = 8; // BE Offset (points) input bool InpMultiLevelBE = false; // Multi-Level Breakeven // Multi-Level Breakeven Thresholds (only used when USE_BREAKEVEN_SYSTEM = true) double InpBE_Level1_Trigger = 40; // First BE level double InpBE_Level1_Offset = 8; double InpBE_Level2_Trigger = 80; // Second BE level double InpBE_Level2_Offset = 20; double InpBE_Level3_Trigger = 150; // Third BE level double InpBE_Level3_Offset = 50; // === TRAILING STOP CONFIGURATION (Priority 2: Trailing Parameters) === // v1.3: Phase-aware adaptive trailing now calculated automatically in code // Trail multipliers: PROTECTION=2.5x, ACCUMULATION=2.2x, MAXIMIZATION=1.8x, RUNNER=3.0x, EXTREME=3.5x input group "=== Trailing Stop Settings (v1.3 Phase-Aware) ===" input ENUM_TRAILING_METHOD InpTrailingMethod = TRAIL_ATR; // Trailing Method input double InpTrailStart = 60; // Trail Start (points) input double InpTrailDistance = 50; // Trail Distance (points) [v1.3: +25%] input double InpTrailStep = 20; // Trail Step (points) [v1.3: +33%] input bool InpAdaptiveTrailing = true; // Adaptive Trailing (Phase-aware) // Volatility-Based Trail Adjustments (v1.3: CORRECTED - widens in high vol!) input double InpLowVolatilityMultiplier = 0.85; // Low Volatility Multiplier input double InpHighVolatilityMultiplier = 1.3; // High Vol WIDENING [v1.3: fixed logic] input double InpVolatilityThreshold = 1.2; // Volatility Threshold (ATR) // === PARTIAL CLOSE STRATEGY (Priority 3: Partial Closure Settings) === // v1.3: Optimized schedule - earlier triggers, larger percentages for faster profit banking input group "=== Partial Close Strategy (v1.3 Optimized) ===" input bool InpPartialEnabled = true; // Enable Partial Closing input int InpPartialLevels = 4; // Number of Partial Levels // Progressive Partial Close Levels (v1.3: Earlier & Larger) input double InpPartialTrigger1 = 40; // Level 1 Trigger (points) [v1.3: was 50] input double InpPartialPercent1 = 25; // Level 1 Close (%) [v1.3: was 20] input double InpPartialTrigger2 = 80; // Level 2 Trigger (points) [v1.3: was 100] input double InpPartialPercent2 = 25; // Level 2 Close (%) [v1.3: was 20] input double InpPartialTrigger3 = 150; // Level 3 Trigger (points) [v1.3: was 200] input double InpPartialPercent3 = 25; // Level 3 Close (%) [v1.3: was 25] input double InpPartialTrigger4 = 300; // Level 4 Trigger (points) [v1.3: was 400] input double InpPartialPercent4 = 15; // Level 4 Close (%) [v1.3: was 20] // Runner Configuration (v1.3: Smaller runner, wider trail) input double InpRunnerPercentage = 10; // Runner Size (% to keep) [v1.3: was 15] input double InpRunnerTrailMultiplier = 3.0; // Runner Trail Multiplier [v1.3: was 2.0] input double InpRunnerExitThreshold = 500; // Runner Exit (points) // === EXIT MANAGEMENT === input group "=== Exit Management ===" input bool InpUseTechnicalExits = false; // Technical Exit Signals input bool InpTimeBasedExits = false; // Time-Based Exits input int InpMaxBarsInTrade = 1000; // Max Bars in Trade input bool InpReduceRiskOverTime = false; // Reduce Risk Over Time // === PROFIT PROTECTION MECHANISM === input group "=== Profit Protection ===" input bool InpProtectProfitEnabled = false; // Enable Profit Protection input double InpProfitProtectionStart = 100; // Protection Start (points) input double InpMaxRetracement = 60; // Max Retracement from Peak (%) input double InpLockInProfit = 40; // Minimum Profit Lock (%) // === PHASE-BASED PROFIT LOCKING === // v1.3: Phase locks are SAFETY FLOORS ONLY (not active management) // No progressive locking, no breathing room reduction, no dynamic tightening // Provides guaranteed minimum profit for highest phase achieved input group "Phase-Based Profit Locking (v1.3 Floor-Only Mode)" input bool InpUsePhaseProfitLocks = true; // Enable Phase Profit Locks input double InpPhaseLockBreathingRoom = 80; // Breathing Room [v1.3: was 50] (UNUSED in floor mode) input bool InpMaintainLockOnRetreat = true; // Keep Lock When Retreating input double InpRetreatLockMultiplier = 1.0; // Lock Tightening [v1.3: was 1.2, DISABLED] // Phase Minimum Locks (These ARE the actual stops in v1.3 - no progressive calculation) input double InpPhase1MinLock = 10; // PROTECTION Min Lock (pts) input double InpPhase2MinLock = 25; // ACCUMULATION Min Lock (pts) input double InpPhase3MinLock = 50; // MAXIMIZATION Min Lock (pts) input double InpPhase4MinLock = 100; // RUNNER Min Lock (pts) input double InpPhase5MinLock = 200; // EXTREME Min Lock (pts) // === ADVANCED FEATURES (v1.3 Solutions 2 & 3) === input group "=== Advanced Optimization (v1.3) ===" input bool InpUseDynamicPartials = true; // Dynamic Partial Adjustment input bool InpUseATRBreathingRoom = false; // ATR-Aware Breathing Room (Advanced) input bool InpFloorOnlyMode = true; // Floor-Only Phase Locks (Recommended) // === TIME FILTERS === input group "=== Time Filters ===" input bool InpUseTimeFilter = false; // Use Time Filter input int InpStartHour = 0; // Start Hour input int InpEndHour = 24; // End Hour input bool InpFridayClose = false; // Friday Close input int InpFridayCloseHour = 23; // Friday Close Hour // === SESSION-BASED ADJUSTMENTS === input group "=== Session Management ===" input bool InpSessionBasedManagement = true; // Session-Based Adjustments // Asian Session (Conservative) input double InpAsianTrailMultiplier = 1.2; // Asian Trail Multiplier input double InpAsianPartialMultiplier = 1.5; // Asian Partial Multiplier // London Session (Standard) input double InpLondonTrailMultiplier = 1.0; // London Trail Multiplier input double InpLondonPartialMultiplier = 1.0; // London Partial Multiplier // New York Session (Aggressive) input double InpNewYorkTrailMultiplier = 0.9; // NY Trail Multiplier input double InpNewYorkPartialMultiplier = 0.8; // NY Partial Multiplier // === ADVANCED PROFIT MAXIMIZATION === input group "=== Advanced Settings ===" input bool InpUseVolumeAnalysis = true; // Volume Analysis input double InpHighVolumeThreshold = 1.5; // High Volume Threshold input bool InpExtendTargetsOnMomentum = true; // Extend Targets on Momentum input double InpMomentumThreshold = 2.0; // Momentum Threshold (ATR) // === SMART EXIT FILTERS === input bool InpUseSmartExits = true; // Smart Exit Logic input double InpMinProfitForExit = 30; // Min Profit for Exit (points) input bool InpCheckSupportResistance = true; // Check S/R Before Exit input double InpSRBuffer = 10; // S/R Buffer (points) // === DISPLAY SETTINGS === input group "=== Display Settings ===" input bool InpShowDashboard = true; // Show Dashboard input int InpDashboardX = 20; // Dashboard X Position input int InpDashboardY = 50; // Dashboard Y Position input int InpUpdateFrequency = 2; // Update Frequency (seconds) // === SYSTEM SETTINGS === input group "=== System Settings ===" input ENUM_LOG_LEVEL InpLogLevel = LOG_INFO; // Log Level input bool InpSaveReports = true; // Save Reports input bool InpEmailAlerts = false; // Email Alerts input bool InpPushAlerts = false; // Push Alerts input bool InpSoundAlerts = true; // Sound Alerts //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ // Core components CUtilities* g_utils = NULL; CRiskManager* g_risk = NULL; CTechnicalAnalysis* g_tech = NULL; CPositionManager* g_manager = NULL; CProfitMaximizer* g_profit_max = NULL; // State tracking bool g_initialized = false; datetime g_last_update = 0; datetime g_session_start = 0; double g_session_start_balance = 0; double g_session_start_equity = 0; // Performance tracking int g_positions_detected = 0; int g_positions_managed = 0; int g_positions_closed = 0; double g_total_prevented = 0; double g_total_captured = 0; // Alert management datetime g_last_alert = 0; int g_alert_count = 0; // Dashboard elements (simplified) //string g_dashboard_prefix = "PME_" + InpInstanceID + "-"; string g_dashboard_prefix = "PME_1.1"; int g_dashboard_objects = 0; // Performance tracking struct PerformanceTracker { int trades_managed; double total_profit_captured; double total_loss_prevented; int runners_created; int extreme_profits; datetime last_update; }; PerformanceTracker g_performance; //+------------------------------------------------------------------+ //| Configure Profit Maximizer | //+------------------------------------------------------------------+ void ConfigureProfitMaximizer() { if(g_profit_max == NULL) return; // === V1.3: Configure ProfitMaximizer with optimized settings === // Pass v1.3 solution flags to ProfitMaximizer g_profit_max.SetFloorOnlyMode(InpFloorOnlyMode); g_profit_max.SetDynamicPartials(InpUseDynamicPartials); g_profit_max.SetATRBreathingRoom(InpUseATRBreathingRoom); // Configure optimized partial closure schedule (v1.3) g_profit_max.SetPartialLevel(0, InpPartialTrigger1, InpPartialPercent1); g_profit_max.SetPartialLevel(1, InpPartialTrigger2, InpPartialPercent2); g_profit_max.SetPartialLevel(2, InpPartialTrigger3, InpPartialPercent3); g_profit_max.SetPartialLevel(3, InpPartialTrigger4, InpPartialPercent4); // Configure runner settings g_profit_max.SetRunnerConfig(InpRunnerPercentage, InpRunnerTrailMultiplier, InpRunnerExitThreshold); // Configure phase minimum locks g_profit_max.SetPhaseMinLock(PHASE_PROTECTION, InpPhase1MinLock); g_profit_max.SetPhaseMinLock(PHASE_ACCUMULATION, InpPhase2MinLock); g_profit_max.SetPhaseMinLock(PHASE_MAXIMIZATION, InpPhase3MinLock); g_profit_max.SetPhaseMinLock(PHASE_RUNNER, InpPhase4MinLock); g_profit_max.SetPhaseMinLock(PHASE_EXTREME, InpPhase5MinLock); // Configure phase lock behavior g_profit_max.SetPhaseLockBehavior(InpMaintainLockOnRetreat, InpRetreatLockMultiplier, InpPhaseLockBreathingRoom); if(g_utils != NULL) { g_utils.Log("Phase Management Enabled - Using adaptive profit protection", LOG_INFO); g_utils.Log(StringFormat("Phase Triggers: P1=%.0f P2=%.0f P3=%.0f P4=%.0f P5=%.0f", InpPhase1Trigger, InpPhase2Trigger, InpPhase3Trigger, InpPhase4Trigger, InpPhase5Trigger), LOG_INFO); g_utils.Log(StringFormat("V1.3 Solutions: FloorOnly=%s, DynamicPartials=%s, ATRBreathing=%s", InpFloorOnlyMode ? "ON" : "OFF", InpUseDynamicPartials ? "ON" : "OFF", InpUseATRBreathingRoom ? "ON" : "OFF"), LOG_INFO); } } //+------------------------------------------------------------------+ //| Apply Phase Management to Position | //+------------------------------------------------------------------+ void ApplyPhaseManagement(ulong ticket) { if(!InpUsePhaseManagement || g_profit_max == NULL) return; // Get position info if(!PositionSelectByTicket(ticket)) return; string symbol = PositionGetString(POSITION_SYMBOL); double current_price = PositionGetDouble(POSITION_PRICE_CURRENT); double entry_price = PositionGetDouble(POSITION_PRICE_OPEN); double symbol_point = SymbolInfoDouble(symbol, SYMBOL_POINT); if(symbol_point <= 0.0) symbol_point = _Point; double profit_points = 0.0; if(symbol_point > 0.0) profit_points = (current_price - entry_price) / symbol_point; // For short positions, profit calculation is inverted if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL && symbol_point > 0.0) profit_points = (entry_price - current_price) / symbol_point; // Analyze position and determine phase g_profit_max.AnalyzePosition(ticket, current_price, profit_points); // Get current phase ENUM_PROFIT_PHASE phase = g_profit_max.GetCurrentPhase(ticket); // === NEW: Apply phase-based profit lock === double phase_stop_price; string lock_reason; if(g_profit_max.GetPhaseProtectionStop(ticket, phase_stop_price, lock_reason)) { // Phase lock suggests a stop update if(g_manager != NULL && !g_manager.AdjustStopLoss(ticket, phase_stop_price)) { if(g_utils != NULL) g_utils.Log(StringFormat("Failed to apply phase lock for #%I64u: %s", ticket, lock_reason), LOG_ERROR); } else { if(g_utils != NULL) g_utils.Log(StringFormat("Applied phase lock for #%I64u: %s", ticket, lock_reason), LOG_INFO); // Sound alert for lock application if(InpSoundAlerts) PlaySound("ok.wav"); } } // === V1.3: Check and execute partial closures === if(InpPartialEnabled && g_profit_max != NULL && g_manager != NULL) { double partial_percentage = 0.0; if(g_profit_max.ShouldExecutePartial(ticket, partial_percentage)) { // Execute partial closure (PartialClose handles volume validation internally) if(g_manager.PartialClose(ticket, partial_percentage)) { // Partial close counter is tracked internally by PositionManager if(g_utils != NULL) g_utils.Log(StringFormat("Executed %.0f%% partial close for #%I64u at %.0f pts", partial_percentage, ticket, profit_points), LOG_INFO); if(InpSoundAlerts) PlaySound("tick.wav"); } else { if(g_utils != NULL) g_utils.Log(StringFormat("Failed to execute %.0f%% partial close for #%I64u (volume too small or trade error)", partial_percentage, ticket), LOG_WARNING); } } } // Update performance tracking based on phase if(phase == PHASE_RUNNER) { g_performance.runners_created++; } else if(phase == PHASE_EXTREME) { g_performance.extreme_profits++; } } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("=================================================="); Print(" ERMT PME v1.3 - Pure Management Edition"); Print(" DECOUPLED PHASE LOCKS & ADAPTIVE TRAILING"); Print("=================================================="); Print("Initializing v1.3 management system..."); Print("- Phase locks: Safety floors only (no dynamic tightening)"); Print("- Adaptive trailing: Phase-aware (wider at higher phases)"); Print("- Volatility logic: Fixed (widens in high vol)"); Print("- Partial closures: Optimized schedule (75% by 150pts)"); // Validate inputs if(!ValidateInputs()) { Print("ERROR: Invalid input parameters"); return INIT_PARAMETERS_INCORRECT; } // Create core components g_utils = new CUtilities(); if(g_utils == NULL) { Print("ERROR: Failed to create Utilities"); return INIT_FAILED; } g_risk = new CRiskManager(); if(g_risk == NULL) { Print("ERROR: Failed to create RiskManager"); Cleanup(); return INIT_FAILED; } g_tech = new CTechnicalAnalysis(); if(g_tech == NULL) { Print("ERROR: Failed to create TechnicalAnalysis"); Cleanup(); return INIT_FAILED; } g_manager = new CPositionManager(); if(g_manager == NULL) { Print("ERROR: Failed to create PositionManager"); Cleanup(); return INIT_FAILED; } // Initialize profit maximizer g_profit_max = new CProfitMaximizer(); if(g_profit_max == NULL) { Print("ERROR: Failed to create ProfitMaximizer"); Cleanup(); return INIT_FAILED; } // Configure profit maximizer with input parameters if(InpUsePhaseManagement) { ConfigureProfitMaximizer(); } // Initialize utilities if(!g_utils.Initialize(InpLogLevel, InpSaveReports)) { Print("ERROR: Failed to initialize Utilities"); Cleanup(); return INIT_FAILED; } // Initialize risk manager if(!g_risk.Initialize(g_utils, InpMaxLossPerTrade, InpMaxDailyLoss, InpMaxDrawdown)) { Print("ERROR: Failed to initialize RiskManager"); Cleanup(); return INIT_FAILED; } // Initialize technical analysis with retry mechanism if(!g_tech.Initialize(g_utils)) { Print("WARNING: Technical Analysis initialization incomplete"); // Try alternative symbol format ChartSetSymbolPeriod(0, _Symbol, PERIOD_CURRENT); Sleep(100); // Retry initialization if(!g_tech.Initialize(g_utils)) { Print("Technical Analysis initialization still incomplete after retry"); Print("This is normal if chart data is still loading. EA will continue..."); if(g_utils != NULL) g_utils.Log("Technical Analysis initialization incomplete - will retry on first tick", LOG_WARNING); // Don't fail - EA can work without technical indicators initially } else { Print("Technical Analysis initialized successfully on retry"); if(g_utils != NULL) g_utils.Log("Technical Analysis initialized successfully on retry", LOG_INFO); } } // Initialize position manager if(!g_manager.Initialize(g_utils, g_risk, g_tech, InpMagicFilter)) { Print("ERROR: Failed to initialize PositionManager"); Cleanup(); return INIT_FAILED; } // Configure position manager ManagementConfig config; config.apply_default_sl = InpApplyEmergencyStops; config.default_sl_atr = InpEmergencySLMultiplier; config.apply_default_tp = InpApplyEmergencyStops; config.default_tp_atr = InpEmergencyTPMultiplier; config.dynamic_sl_adjust = InpDynamicStops; config.tighten_on_profit = InpTightenOnProfit; config.tighten_threshold = InpTightenThreshold; config.breakeven_enabled = InpBreakevenEnabled; config.breakeven_trigger = InpBreakevenTrigger; config.breakeven_offset = InpBreakevenOffset; config.multi_level_be = InpMultiLevelBE; config.trailing_method = InpTrailingMethod; config.trail_start = InpTrailStart; config.trail_distance = InpTrailDistance; config.trail_step = InpTrailStep; config.adaptive_trailing = InpAdaptiveTrailing; config.partial_enabled = InpPartialEnabled; config.partial_trigger_1 = InpPartialTrigger1; config.partial_percent_1 = InpPartialPercent1; config.partial_trigger_2 = InpPartialTrigger2; config.partial_percent_2 = InpPartialPercent2; config.partial_trigger_3 = InpPartialTrigger3; config.partial_percent_3 = InpPartialPercent3; config.partial_trigger_4 = InpPartialTrigger4; config.partial_percent_4 = InpPartialPercent4; config.time_based_mgmt = InpTimeBasedExits; config.max_bars_in_trade = InpMaxBarsInTrade; config.reduce_risk_overtime = InpReduceRiskOverTime; config.friday_close_hour = InpFridayCloseHour; config.max_loss_per_trade = InpMaxLossPerTrade; config.max_daily_loss = InpMaxDailyLoss; config.max_correlation = InpMaxCorrelation; config.max_drawdown = InpMaxDrawdown; g_manager.SetConfiguration(config); // Initialize session g_session_start = TimeCurrent(); g_session_start_balance = AccountInfoDouble(ACCOUNT_BALANCE); g_session_start_equity = AccountInfoDouble(ACCOUNT_EQUITY); // Initialize dashboard if(InpShowDashboard) { InitializeDashboard(); } // Log configuration LogConfiguration(); // Set timer EventSetTimer(InpUpdateFrequency); g_initialized = true; // Initial status int initial_positions = g_manager.GetManagedCount(); Print(StringFormat("PME Ready - Managing %d positions", initial_positions)); g_utils.Log(StringFormat("PME initialized successfully - %d positions detected", initial_positions), LOG_INFO); // Sound alert if(InpSoundAlerts) PlaySound("alert.wav"); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); string reason_text = GetDeinitReasonText(reason); if(g_utils != NULL) { g_utils.Log(StringFormat("PME Shutdown: %s", reason_text), LOG_INFO); } // Generate final report if(g_manager != NULL && g_utils != NULL) { GenerateFinalReport(); } // Clean up dashboard if(InpShowDashboard) { RemoveDashboard(); } // Clean up components Cleanup(); Comment(""); Print("=================================================="); Print(StringFormat("PME Shutdown Complete: %s", reason_text)); Print("=================================================="); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { if(!g_initialized) return; // Check if we should be active if(!CheckTradingConditions()) return; // Apply phase-based management if enabled if(InpUsePhaseManagement && g_profit_max != NULL) { int total = PositionsTotal(); for(int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if(ticket > 0) { ApplyPhaseManagement(ticket); } } } // Main management cycle (handles standard management) g_manager.ManageAllPositions(); // Check risk limits CheckRiskLimits(); // Update dashboard if visible if(InpShowDashboard) { UpdateDashboard(); } // Check for Friday close if(InpFridayClose && IsFridayClose()) { g_utils.Log("Friday close time - closing all positions", LOG_WARNING); g_manager.CloseAllPositions(EXIT_TIME); if(InpSoundAlerts) PlaySound("alert2.wav"); } } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { if(!g_initialized) return; // Periodic status update static int status_counter = 0; status_counter++; if(status_counter >= 60 / InpUpdateFrequency) // Every minute { status_counter = 0; LogStatus(); } // Save snapshot static int snapshot_counter = 0; snapshot_counter++; if(snapshot_counter >= 300 / InpUpdateFrequency) // Every 5 minutes { snapshot_counter = 0; if(InpSaveReports) { SaveSnapshot(); } } // Check for alerts CheckAlerts(); } //+------------------------------------------------------------------+ //| Trade function | //+------------------------------------------------------------------+ void OnTrade() { if(!g_initialized) return; // Update metrics on trade events g_positions_closed++; // Log trade event if(g_utils != NULL) { g_utils.Log("Trade event detected", LOG_DEBUG); } } //+------------------------------------------------------------------+ //| Validate Inputs | //+------------------------------------------------------------------+ bool ValidateInputs() { // === Risk Limit Validation === if(InpMaxLossPerTrade <= 0 || InpMaxLossPerTrade > 20) { Print("ERROR: MaxLossPerTrade must be between 0.1 and 20 (percentage)"); return false; } if(InpMaxDailyLoss <= 0 || InpMaxDailyLoss > 50) { Print("ERROR: MaxDailyLoss must be between 0.1 and 50 (percentage)"); return false; } if(InpMaxDrawdown <= 0 || InpMaxDrawdown > 100) { Print("ERROR: MaxDrawdown must be between 0.1 and 100 (percentage)"); return false; } if(InpMaxCorrelation < 0 || InpMaxCorrelation > 1.0) { Print("ERROR: MaxCorrelation must be between 0 and 1.0"); return false; } // === Trailing Stop Validation === if(InpTrailStart < 0 || InpTrailStart > 2000) { Print("ERROR: TrailStart must be between 0 and 2000 points"); return false; } if(InpTrailDistance < 5 || InpTrailDistance > 1000) { Print("ERROR: TrailDistance must be between 5 and 1000 points"); return false; } if(InpTrailStep < 1 || InpTrailStep > 500) { Print("ERROR: TrailStep must be between 1 and 500 points"); return false; } // === Partial Closure Validation === if(InpPartialEnabled) { // Check that triggers are in ascending order if(InpPartialTrigger2 <= InpPartialTrigger1 || InpPartialTrigger3 <= InpPartialTrigger2 || InpPartialTrigger4 <= InpPartialTrigger3) { Print("ERROR: Partial triggers must be in ascending order (L1 < L2 < L3 < L4)"); return false; } // Check percentages are valid if(InpPartialPercent1 <= 0 || InpPartialPercent1 > 100 || InpPartialPercent2 <= 0 || InpPartialPercent2 > 100 || InpPartialPercent3 <= 0 || InpPartialPercent3 > 100 || InpPartialPercent4 <= 0 || InpPartialPercent4 > 100) { Print("ERROR: Partial percentages must be between 0 and 100"); return false; } // Check that total closure doesn't exceed 100% double total_closure = InpPartialPercent1 + InpPartialPercent2 + InpPartialPercent3 + InpPartialPercent4; if(total_closure > 95) { Print(StringFormat("WARNING: Total partial closure is %.1f%% - leaving less than 5%% as runner", total_closure)); } } // === Breakeven Validation === if(InpBreakevenTrigger < 0 || InpBreakevenTrigger > 2000) { Print("ERROR: BreakevenTrigger must be between 0 and 2000 points"); return false; } // === Time Filter Validation === if(InpUseTimeFilter) { if(InpStartHour < 0 || InpStartHour > 23 || InpEndHour < 0 || InpEndHour > 24) { Print("ERROR: Trading hours must be between 0-23 (start) and 0-24 (end)"); return false; } } // === Phase Lock Validation === if(InpUsePhaseProfitLocks) { // Check that phase locks are in ascending order if(InpPhase2MinLock <= InpPhase1MinLock || InpPhase3MinLock <= InpPhase2MinLock || InpPhase4MinLock <= InpPhase3MinLock || InpPhase5MinLock <= InpPhase4MinLock) { Print("ERROR: Phase minimum locks must be in ascending order"); return false; } if(InpPhaseLockBreathingRoom < 0 || InpPhaseLockBreathingRoom > 100) { Print("ERROR: Phase lock breathing room must be between 0 and 100 percent"); return false; } } Print("✓ All input parameters validated successfully"); return true; } //+------------------------------------------------------------------+ //| Check Trading Conditions | //+------------------------------------------------------------------+ bool CheckTradingConditions() { // Check if terminal is connected if(!TerminalInfoInteger(TERMINAL_CONNECTED)) return false; // Check if trade is allowed if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return false; // Check time filter if(InpUseTimeFilter) { MqlDateTime current; TimeToStruct(TimeCurrent(), current); if(current.hour < InpStartHour || current.hour >= InpEndHour) return false; } return true; } //+------------------------------------------------------------------+ //| Check Risk Limits | //+------------------------------------------------------------------+ void CheckRiskLimits() { // Check daily loss double daily_loss = g_risk.GetDailyLoss(); if(daily_loss > InpMaxDailyLoss) { g_utils.Log(StringFormat("Daily loss limit reached: %.2f%%", daily_loss), LOG_ERROR); g_manager.CloseAllPositions(EXIT_RISK); // Send alerts SendAlert("Daily loss limit reached!"); } // Check drawdown double drawdown = g_risk.GetDrawdown(); if(drawdown > InpMaxDrawdown) { g_utils.Log(StringFormat("Max drawdown reached: %.2f%%", drawdown), LOG_ERROR); g_manager.CloseAllPositions(EXIT_DRAWDOWN); // Send alerts SendAlert("Max drawdown reached!"); } // Check individual position risks double total_risk = g_manager.GetTotalRisk(); double balance = AccountInfoDouble(ACCOUNT_BALANCE); double risk_percent = (total_risk / balance) * 100; if(risk_percent > InpMaxDailyLoss) { g_utils.Log(StringFormat("Total risk too high: %.2f%%", risk_percent), LOG_WARNING); } } //+------------------------------------------------------------------+ //| Check if Friday Close | //+------------------------------------------------------------------+ bool IsFridayClose() { MqlDateTime current; TimeToStruct(TimeCurrent(), current); return (current.day_of_week == 5 && current.hour >= InpFridayCloseHour); } //+------------------------------------------------------------------+ //| Initialize Dashboard | //+------------------------------------------------------------------+ void InitializeDashboard() { int y = InpDashboardY; color text_color = clrWhite; color header_color = clrGold; // Background (streamlined v1.3 - reduced height) CreateRectangle(g_dashboard_prefix + "BG", InpDashboardX - 5, y - 5, 250, 280, clrBlack, STYLE_SOLID, 1); // Header CreateLabel(g_dashboard_prefix + "HEADER", InpDashboardX, y, "ERMT PME v1.3", header_color, 11); y += 20; CreateLabel(g_dashboard_prefix + "LINE1", InpDashboardX, y, "────────────────────", text_color, 9); y += 15; // Status section CreateLabel(g_dashboard_prefix + "STATUS", InpDashboardX, y, "STATUS", header_color, 10); y += 18; CreateLabel(g_dashboard_prefix + "ACTIVE", InpDashboardX, y, "Active: 0", text_color, 9); y += 15; CreateLabel(g_dashboard_prefix + "CLOSED", InpDashboardX, y, "Closed: 0", text_color, 9); y += 20; // Risk section CreateLabel(g_dashboard_prefix + "RISK", InpDashboardX, y, "RISK", header_color, 10); y += 18; CreateLabel(g_dashboard_prefix + "EXPOSURE", InpDashboardX, y, "Exposure: 0.00", text_color, 9); y += 15; CreateLabel(g_dashboard_prefix + "DRAWDOWN", InpDashboardX, y, "Drawdown: 0.0%", text_color, 9); y += 20; // Management section (streamlined - removed breakevens) CreateLabel(g_dashboard_prefix + "MGMT", InpDashboardX, y, "MANAGEMENT", header_color, 10); y += 18; CreateLabel(g_dashboard_prefix + "TRAILS", InpDashboardX, y, "Trails: 0", text_color, 9); y += 15; CreateLabel(g_dashboard_prefix + "PARTIALS", InpDashboardX, y, "Partials: 0", text_color, 9); y += 15; CreateLabel(g_dashboard_prefix + "RUNNERS", InpDashboardX, y, "Runners: 0", text_color, 9); y += 20; // === V1.3 SOLUTIONS METRICS (Primary Focus) === CreateLabel(g_dashboard_prefix + "V13_HEADER", InpDashboardX, y, "V1.3 SOLUTIONS", header_color, 10); y += 18; CreateLabel(g_dashboard_prefix + "SOLUTION1", InpDashboardX, y, "S1-Floors: Active", clrLime, 9); y += 15; CreateLabel(g_dashboard_prefix + "SOLUTION2", InpDashboardX, y, "S2-Dynamic: Enabled", clrLime, 9); y += 15; CreateLabel(g_dashboard_prefix + "SOLUTION3", InpDashboardX, y, "S3-ATR: Off", clrGray, 9); y += 15; CreateLabel(g_dashboard_prefix + "PREMATURE_EXITS", InpDashboardX, y, "Premature: 0.0%", text_color, 9); y += 15; CreateLabel(g_dashboard_prefix + "AVG_PROFIT", InpDashboardX, y, "Avg Profit: 0pts", text_color, 9); g_dashboard_objects = 21; // Reduced from 42 (removed redundant features) } //+------------------------------------------------------------------+ //| Update Dashboard | //+------------------------------------------------------------------+ void UpdateDashboard() { SessionMetrics metrics; g_manager.GetSessionMetrics(metrics); // Update status UpdateLabel(g_dashboard_prefix + "ACTIVE", StringFormat("Active: %d", g_manager.GetManagedCount())); UpdateLabel(g_dashboard_prefix + "CLOSED", StringFormat("Closed: %d", metrics.positions_closed)); // Update risk UpdateLabel(g_dashboard_prefix + "EXPOSURE", StringFormat("Exposure: %.2f", g_manager.GetTotalExposure())); UpdateLabel(g_dashboard_prefix + "DRAWDOWN", StringFormat("Drawdown: %.1f%%", g_risk.GetDrawdown())); // Update management UpdateLabel(g_dashboard_prefix + "BREAKEVENS", StringFormat("Breakevens: %d", metrics.breakevens_applied)); UpdateLabel(g_dashboard_prefix + "TRAILS", StringFormat("Trails: %d", metrics.trails_activated)); UpdateLabel(g_dashboard_prefix + "PARTIALS", StringFormat("Partials: %d", metrics.partial_closes)); // Update performance UpdateLabel(g_dashboard_prefix + "SAVED", StringFormat("Saved: $%.2f", metrics.total_prevented_loss)); UpdateLabel(g_dashboard_prefix + "CAPTURED", StringFormat("Captured: $%.2f", metrics.total_captured_profit)); UpdateLabel(g_dashboard_prefix + "EFFICIENCY", StringFormat("Efficiency: %.1f%%", metrics.management_efficiency)); // Update phase distribution if(InpUsePhaseManagement && g_profit_max != NULL) { // Count positions by phase int phase_count[6] = {0, 0, 0, 0, 0, 0}; int total = PositionsTotal(); for(int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if(ticket > 0) { ENUM_PROFIT_PHASE phase = g_profit_max.GetCurrentPhase(ticket); phase_count[phase]++; } } // Display phase distribution UpdateLabel(g_dashboard_prefix + "PHASES_HEADER", "Position Phases:"); UpdateLabel(g_dashboard_prefix + "PHASE_INIT", StringFormat("Initial: %d", phase_count[PHASE_INITIAL])); UpdateLabel(g_dashboard_prefix + "PHASE_PROT", StringFormat("Protection: %d", phase_count[PHASE_PROTECTION])); UpdateLabel(g_dashboard_prefix + "PHASE_ACCUM", StringFormat("Accumulation: %d", phase_count[PHASE_ACCUMULATION])); UpdateLabel(g_dashboard_prefix + "PHASE_MAX", StringFormat("Maximization: %d", phase_count[PHASE_MAXIMIZATION])); UpdateLabel(g_dashboard_prefix + "PHASE_RUN", StringFormat("Runner: %d", phase_count[PHASE_RUNNER])); UpdateLabel(g_dashboard_prefix + "PHASE_EXT", StringFormat("Extreme: %d", phase_count[PHASE_EXTREME])); // Display runner and extreme stats UpdateLabel(g_dashboard_prefix + "RUNNERS", StringFormat("Runners Created: %d", g_performance.runners_created)); UpdateLabel(g_dashboard_prefix + "EXTREMES", StringFormat("Extreme Profits: %d", g_performance.extreme_profits)); // Update phase lock statistics int locked_positions = 0; double total_locked_profit = 0; for(int i = 0; i < total; i++) { ulong ticket = PositionGetTicket(i); if(ticket > 0) { double protected_profit, peak_profit, retracement_pct; g_profit_max.GetProtectionStatus(ticket, protected_profit, peak_profit, retracement_pct); if(protected_profit > 0) { locked_positions++; total_locked_profit += protected_profit; } } } UpdateLabel(g_dashboard_prefix + "LOCKED_MIN", StringFormat("Min Locked: %.0f pts", total_locked_profit)); UpdateLabel(g_dashboard_prefix + "LOCK_ACTIVE", StringFormat("Active Locks: %d", locked_positions)); // === V1.3 SOLUTIONS METRICS === // Solution 1: Floor-Only Mode Status string s1_status = InpFloorOnlyMode ? "Active" : "Off"; color s1_color = InpFloorOnlyMode ? clrLime : clrGray; UpdateLabel(g_dashboard_prefix + "SOLUTION1", StringFormat("S1-Floors: %s", s1_status)); ObjectSetInteger(0, g_dashboard_prefix + "SOLUTION1", OBJPROP_COLOR, s1_color); // Solution 2: Dynamic Partials - count adjustments int dynamic_partial_count = 0; // Note: This would require tracking in ProfitMaximizer, for now show enabled/disabled string s2_status = InpUseDynamicPartials ? "Enabled" : "Disabled"; color s2_color = InpUseDynamicPartials ? clrLime : clrGray; UpdateLabel(g_dashboard_prefix + "SOLUTION2", StringFormat("S2-Dynamic: %s", s2_status)); ObjectSetInteger(0, g_dashboard_prefix + "SOLUTION2", OBJPROP_COLOR, s2_color); // Solution 3: ATR Breathing Room Status string s3_status = InpUseATRBreathingRoom ? "Active" : "Off"; color s3_color = InpUseATRBreathingRoom ? clrLime : clrGray; UpdateLabel(g_dashboard_prefix + "SOLUTION3", StringFormat("S3-ATR: %s", s3_status)); ObjectSetInteger(0, g_dashboard_prefix + "SOLUTION3", OBJPROP_COLOR, s3_color); // Calculate premature exit rate (positions closed below phase floor vs total closed) double premature_rate = 0; if(metrics.positions_closed > 0) { // Estimate: trails_activated shows positions that reached profit // If positions_closed >> trails_activated, suggests premature exits int positions_that_reached_profit = metrics.trails_activated; int premature_exits = MathMax(0, metrics.positions_closed - positions_that_reached_profit - metrics.partial_closes); premature_rate = (premature_exits / (double)metrics.positions_closed) * 100.0; } color premature_color = premature_rate < 25 ? clrLime : (premature_rate < 50 ? clrYellow : clrRed); UpdateLabel(g_dashboard_prefix + "PREMATURE_EXITS", StringFormat("Premature: %.1f%%", premature_rate)); ObjectSetInteger(0, g_dashboard_prefix + "PREMATURE_EXITS", OBJPROP_COLOR, premature_color); // Calculate average profit per closed position double avg_profit = 0; if(metrics.positions_closed > 0) { double total_profit = metrics.total_captured_profit - metrics.total_prevented_loss; avg_profit = (total_profit / metrics.positions_closed); } color avg_profit_color = avg_profit > 110 ? clrLime : (avg_profit > 85 ? clrYellow : clrWhite); UpdateLabel(g_dashboard_prefix + "AVG_PROFIT", StringFormat("Avg Profit: %.0fpts", avg_profit)); ObjectSetInteger(0, g_dashboard_prefix + "AVG_PROFIT", OBJPROP_COLOR, avg_profit_color); } // Update comment if dashboard not shown if(!InpShowDashboard) { Comment(StringFormat( "PME v1.3 | Active: %d | P/L: %.2f | Saved: %.2f | Eff: %.1f%% | S1:%s S2:%s S3:%s", g_manager.GetManagedCount(), g_manager.GetTotalProfit(), metrics.total_prevented_loss + metrics.total_captured_profit, metrics.management_efficiency, InpFloorOnlyMode ? "ON" : "OFF", InpUseDynamicPartials ? "ON" : "OFF", InpUseATRBreathingRoom ? "ON" : "OFF" )); } } //+------------------------------------------------------------------+ //| Remove Dashboard | //+------------------------------------------------------------------+ void RemoveDashboard() { for(int i = 0; i < g_dashboard_objects + 10; i++) { string name = g_dashboard_prefix + IntegerToString(i); ObjectDelete(0, name); } // Remove named objects ObjectDelete(0, g_dashboard_prefix + "BG"); ObjectDelete(0, g_dashboard_prefix + "HEADER"); ObjectDelete(0, g_dashboard_prefix + "LINE1"); ObjectDelete(0, g_dashboard_prefix + "STATUS"); ObjectDelete(0, g_dashboard_prefix + "ACTIVE"); ObjectDelete(0, g_dashboard_prefix + "CLOSED"); ObjectDelete(0, g_dashboard_prefix + "RISK"); ObjectDelete(0, g_dashboard_prefix + "EXPOSURE"); ObjectDelete(0, g_dashboard_prefix + "DRAWDOWN"); ObjectDelete(0, g_dashboard_prefix + "MGMT"); ObjectDelete(0, g_dashboard_prefix + "BREAKEVENS"); ObjectDelete(0, g_dashboard_prefix + "TRAILS"); ObjectDelete(0, g_dashboard_prefix + "PARTIALS"); ObjectDelete(0, g_dashboard_prefix + "PERF"); ObjectDelete(0, g_dashboard_prefix + "SAVED"); ObjectDelete(0, g_dashboard_prefix + "CAPTURED"); ObjectDelete(0, g_dashboard_prefix + "EFFICIENCY"); ObjectDelete(0, g_dashboard_prefix + "PHASES_HEADER"); ObjectDelete(0, g_dashboard_prefix + "PHASE_INIT"); ObjectDelete(0, g_dashboard_prefix + "PHASE_PROT"); ObjectDelete(0, g_dashboard_prefix + "PHASE_ACCUM"); ObjectDelete(0, g_dashboard_prefix + "PHASE_MAX"); ObjectDelete(0, g_dashboard_prefix + "PHASE_RUN"); ObjectDelete(0, g_dashboard_prefix + "PHASE_EXT"); ObjectDelete(0, g_dashboard_prefix + "RUNNERS"); ObjectDelete(0, g_dashboard_prefix + "EXTREMES"); ObjectDelete(0, g_dashboard_prefix + "LOCK_HEADER"); ObjectDelete(0, g_dashboard_prefix + "LOCKED_MIN"); ObjectDelete(0, g_dashboard_prefix + "LOCK_ACTIVE"); // v1.3 Solutions ObjectDelete(0, g_dashboard_prefix + "V13_HEADER"); ObjectDelete(0, g_dashboard_prefix + "SOLUTION1"); ObjectDelete(0, g_dashboard_prefix + "SOLUTION2"); ObjectDelete(0, g_dashboard_prefix + "SOLUTION3"); ObjectDelete(0, g_dashboard_prefix + "PREMATURE_EXITS"); ObjectDelete(0, g_dashboard_prefix + "AVG_PROFIT"); } //+------------------------------------------------------------------+ //| Create Label | //+------------------------------------------------------------------+ void CreateLabel(string name, int x, int y, string text, color clr, int size) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetString(0, name, OBJPROP_FONT, "Arial"); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); } //+------------------------------------------------------------------+ //| Update Label | //+------------------------------------------------------------------+ void UpdateLabel(string name, string text) { if(ObjectFind(0, name) >= 0) { ObjectSetString(0, name, OBJPROP_TEXT, text); } } //+------------------------------------------------------------------+ //| Create Rectangle | //+------------------------------------------------------------------+ void CreateRectangle(string name, int x, int y, int width, int height, color clr, ENUM_LINE_STYLE style, int line_width) { ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_XSIZE, width); ObjectSetInteger(0, name, OBJPROP_YSIZE, height); ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clr); ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, name, OBJPROP_WIDTH, line_width); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_STYLE, style); ObjectSetInteger(0, name, OBJPROP_BACK, false); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); } //+------------------------------------------------------------------+ //| Log Configuration | //+------------------------------------------------------------------+ void LogConfiguration() { if(g_utils == NULL) return; g_utils.Log("=== PME Configuration ===", LOG_INFO); g_utils.Log(StringFormat("Magic Filter: %d", InpMagicFilter), LOG_INFO); g_utils.Log(StringFormat("Management Mode: %s", ManagementModeToString(InpDefaultMode)), LOG_INFO); g_utils.Log(StringFormat("Max Loss/Trade: %.2f%%", InpMaxLossPerTrade), LOG_INFO); g_utils.Log(StringFormat("Max Daily Loss: %.2f%%", InpMaxDailyLoss), LOG_INFO); g_utils.Log(StringFormat("Max Drawdown: %.2f%%", InpMaxDrawdown), LOG_INFO); g_utils.Log(StringFormat("Breakeven: %s @ %.0f points", InpBreakevenEnabled ? "Enabled" : "Disabled", InpBreakevenTrigger), LOG_INFO); g_utils.Log(StringFormat("Trailing: %s", TrailingMethodToString(InpTrailingMethod)), LOG_INFO); g_utils.Log(StringFormat("Partial Close: %s", InpPartialEnabled ? "Enabled" : "Disabled"), LOG_INFO); g_utils.Log(StringFormat("Start Balance: %.2f", g_session_start_balance), LOG_INFO); g_utils.Log("========================", LOG_INFO); } //+------------------------------------------------------------------+ //| Log Status | //+------------------------------------------------------------------+ void LogStatus() { if(g_utils == NULL || g_manager == NULL) return; SessionMetrics metrics; g_manager.GetSessionMetrics(metrics); g_utils.Log(StringFormat( "Status: Active=%d | Closed=%d | BE=%d | Trails=%d | Saved=%.2f | Captured=%.2f", g_manager.GetManagedCount(), metrics.positions_closed, metrics.breakevens_applied, metrics.trails_activated, metrics.total_prevented_loss, metrics.total_captured_profit ), LOG_INFO); } //+------------------------------------------------------------------+ //| Save Snapshot | //+------------------------------------------------------------------+ void SaveSnapshot() { if(g_utils == NULL || g_manager == NULL) return; SessionMetrics metrics; g_manager.GetSessionMetrics(metrics); // Use filename-safe date format MqlDateTime dt; TimeToStruct(TimeCurrent(), dt); string filename = StringFormat("PME_Snapshot_%04d%02d%02d.csv", dt.year, dt.mon, dt.day); // CSV content with safe time format string time_str = StringFormat("%04d-%02d-%02d %02d:%02d", dt.year, dt.mon, dt.day, dt.hour, dt.min); string content = StringFormat( "%s,%d,%d,%d,%d,%d,%.2f,%.2f,%.2f,%.2f\n", time_str, g_manager.GetManagedCount(), metrics.positions_closed, metrics.breakevens_applied, metrics.trails_activated, metrics.partial_closes, metrics.total_prevented_loss, metrics.total_captured_profit, metrics.management_efficiency, AccountInfoDouble(ACCOUNT_BALANCE) ); g_utils.SaveToFile(filename, content, true); // Append mode } //+------------------------------------------------------------------+ //| Generate Final Report | //+------------------------------------------------------------------+ void GenerateFinalReport() { if(g_utils == NULL || g_manager == NULL) return; SessionMetrics metrics; g_manager.GetSessionMetrics(metrics); double session_duration = (TimeCurrent() - g_session_start) / 3600.0; // Hours double final_balance = AccountInfoDouble(ACCOUNT_BALANCE); double session_profit = final_balance - g_session_start_balance; string report = "\n"; report += "==================================================\n"; report += " ERMT PME - Final Session Report\n"; report += "==================================================\n"; report += StringFormat("Session Duration: %.1f hours\n", session_duration); report += StringFormat("Starting Balance: $%.2f\n", g_session_start_balance); report += StringFormat("Final Balance: $%.2f\n", final_balance); report += StringFormat("Session P/L: $%.2f (%.2f%%)\n", session_profit, (session_profit / g_session_start_balance) * 100); report += "\n"; report += "--- Management Statistics ---\n"; report += StringFormat("Positions Managed: %d\n", metrics.total_managed); report += StringFormat("Positions Closed: %d\n", metrics.positions_closed); report += StringFormat("Emergency Closes: %d\n", metrics.emergency_closes); report += "\n"; report += "--- Actions Taken ---\n"; report += StringFormat("Stops Added: %d\n", metrics.stops_added); report += StringFormat("Stops Adjusted: %d\n", metrics.stops_adjusted); report += StringFormat("Breakevens Applied: %d\n", metrics.breakevens_applied); report += StringFormat("Trails Activated: %d\n", metrics.trails_activated); report += StringFormat("Partial Closes: %d\n", metrics.partial_closes); report += StringFormat("Total Actions: %d\n", metrics.total_actions); report += "\n"; report += "--- Performance Metrics ---\n"; report += StringFormat("Loss Prevented: $%.2f\n", metrics.total_prevented_loss); report += StringFormat("Profit Captured: $%.2f\n", metrics.total_captured_profit); report += StringFormat("Total Value Added: $%.2f\n", metrics.total_prevented_loss + metrics.total_captured_profit); report += StringFormat("Management Efficiency: %.2f%%\n", metrics.management_efficiency); report += StringFormat("Success Rate: %.2f%%\n", metrics.success_rate); report += "\n"; report += "--- Risk Metrics ---\n"; report += StringFormat("Risk Reduced: $%.2f\n", metrics.total_risk_reduced); report += StringFormat("Avg Risk Reduction: %.2f%%\n", metrics.average_risk_reduction); report += StringFormat("Max Single Risk: $%.2f\n", metrics.max_single_risk); report += StringFormat("Final Exposure: $%.2f\n", metrics.current_exposure); report += "==================================================\n"; g_utils.Log(report, LOG_INFO); if(InpSaveReports) { string filename = StringFormat("PME_FinalReport_%s.txt", TimeToString(TimeCurrent(), TIME_DATE|TIME_MINUTES)); g_utils.SaveToFile(filename, report, false); } } //+------------------------------------------------------------------+ //| Check Alerts | //+------------------------------------------------------------------+ void CheckAlerts() { if(TimeCurrent() - g_last_alert < 60) return; // Max 1 alert per minute // Check for positions without stops SessionMetrics metrics; g_manager.GetSessionMetrics(metrics); // Alert conditions bool alert_needed = false; string alert_message = ""; // Check drawdown double drawdown = g_risk.GetDrawdown(); if(drawdown > InpMaxDrawdown * 0.8) // 80% of max { alert_needed = true; alert_message = StringFormat("Warning: Drawdown at %.1f%%", drawdown); } // Check daily loss double daily_loss = g_risk.GetDailyLoss(); if(daily_loss > InpMaxDailyLoss * 0.8) // 80% of max { alert_needed = true; alert_message = StringFormat("Warning: Daily loss at %.1f%%", daily_loss); } if(alert_needed) { SendAlert(alert_message); g_last_alert = TimeCurrent(); } } //+------------------------------------------------------------------+ //| Send Alert | //+------------------------------------------------------------------+ void SendAlert(string message) { string full_message = StringFormat("PME Alert: %s", message); // Terminal alert Alert(full_message); // Sound alert if(InpSoundAlerts) { PlaySound("alert2.wav"); } // Email alert if(InpEmailAlerts) { SendMail("PME Alert", full_message); } // Push notification if(InpPushAlerts) { SendNotification(full_message); } // Log if(g_utils != NULL) { g_utils.Log(full_message, LOG_WARNING); } g_alert_count++; } //+------------------------------------------------------------------+ //| Get Deinitialization Reason Text | //+------------------------------------------------------------------+ string GetDeinitReasonText(int reason) { switch(reason) { case REASON_PROGRAM: return "Program terminated"; case REASON_REMOVE: return "Removed from chart"; case REASON_RECOMPILE: return "Recompiled"; case REASON_CHARTCHANGE: return "Chart changed"; case REASON_CHARTCLOSE: return "Chart closed"; case REASON_PARAMETERS: return "Parameters changed"; case REASON_ACCOUNT: return "Account changed"; case REASON_TEMPLATE: return "Template applied"; case REASON_INITFAILED: return "Initialization failed"; case REASON_CLOSE: return "Terminal closed"; default: return StringFormat("Unknown (%d)", reason); } } //+------------------------------------------------------------------+ //| Cleanup | //+------------------------------------------------------------------+ void Cleanup() { if(g_manager != NULL) { delete g_manager; g_manager = NULL; } if(g_tech != NULL) { delete g_tech; g_tech = NULL; } if(g_risk != NULL) { delete g_risk; g_risk = NULL; } if(g_profit_max != NULL) { delete g_profit_max; g_profit_max = NULL; } if(g_utils != NULL) { delete g_utils; g_utils = NULL; } } //+------------------------------------------------------------------+