mql5/Experts/Advisors/ERMT_PMEx/ERMT_PME_1.3.mq5
darashikoh f5de41d739 Fix v1.3 partial closures integration and streamline dashboard
- Fix: Add configuration bridge to pass v1.3 flags to ProfitMaximizer
- Fix: Implement ShouldExecutePartial() method for partial execution logic
- Fix: Integrate partial closure execution in ApplyPhaseManagement()

7.2
Add optional ATR trailing exit for entry-only mode


- Fix: Correct PartialClose() call to use 2 parameters (ticket, percentage)
- Refactor: Streamline dashboard by removing redundant features
  * Remove breakevens counter (disabled in v1.3)
  * Remove performance metrics (Saved/Captured/Efficiency)
  * Remove detailed phase breakdown (6 counters)
  * Remove profit locks section (replaced by phase floors)
  * Reduce dashboard objects from 42 to 21 (50% reduction)
  * Reduce height from 400px to 280px
- All three v1.3 solutions now functional:
  * S1: Floor-only phase locks
  * S2: Dynamic partial closures with 4-factor adjustment
  * S3: ATR-aware breathing room
2025-12-04 12:00:09 +00:00

1550 lines
No EOL
64 KiB
MQL5

///+------------------------------------------------------------------+
//| 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;
}
}
//+------------------------------------------------------------------+