mql5/Experts/Advisors/ERMT_PMEx/ERMT_PME_1.2.mq5
darashikoh cea5a4e393 ERMT 1.2-> 1.3:
Solution 1: Phase locks guarantee minimum profit for highest phase achieved. Adaptive trailing manages dynamic protection above that floor. Partial closures realize profits progressively. Together, they work in harmony instead of conflict.

EMRT 7x
Critical – Spread filter always rejects signals (EntrySystem_Optimised.mqh:L858-L882; ERMT_7.1_ERMT-ML.mq5:L1290-L1305) The validator compares market.spread (set to the raw point count from SYMBOL_SPREAD) against stop distances expressed in price units. Typical FX spreads (e.g. 18 points) dwarf an ATR-derived stop such as 0.0024, so every candidate fails the 20%-of-stop check. Until the spread is normalised (e.g. market.spread * _Point) or the stop distances are converted to points, the EA cannot emit any live entry orders.

Medium – Technical context is largely empty (TechnicalAnalysis_Optimised.mqh:L38-L119; EntrySystem_Optimised.mqh:L1005-L1030) Market snapshots never populate sr_levels, Fibonacci, pivots, or market-structure data—the ana
2025-12-03 13:57:36 +00:00

1518 lines
No EOL
61 KiB
MQL5

///+------------------------------------------------------------------+
//| ERMT_PME.mq5 v1.2 |
//| Enhanced Risk Management Tool - PME |
//| Pure Management Edition - No Entry, Exit Only |
//+------------------------------------------------------------------+
#property copyright "ERMT PME v1.2 - Pure Management Edition"
#property link "https://github.com/ERMT"
#property version "1.2"
#property description "Professional position management overlay - Manages ALL positions"
//+------------------------------------------------------------------+
//| SYSTEM CONFIGURATION FLAGS (MUST BE BEFORE INCLUDES) |
//+------------------------------------------------------------------+
// Control which pDear 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 - Primary profit protection system
// Progressive locks: 10→200pts across 6 phases
// Adaptive: momentum/volatility adjustments
// Retreat protection: maintains highest phase lock
#define USE_PARTIAL_CLOSURES true // ENABLED - Complementary to phase locks
// Banks 60% profit at 50pts & 100pts
// Creates 40% runner for upside
// No conflicts: different trigger points
//+------------------------------------------------------------------+
//| 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 = true; // 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) ===
input group "=== Trailing Stop Settings ==="
input ENUM_TRAILING_METHOD InpTrailingMethod = TRAIL_ATR; // Trailing Method
input double InpTrailStart = 60; // Trail Start (points)
input double InpTrailDistance = 40; // Trail Distance (points)
input double InpTrailStep = 15; // Trail Step (points)
input bool InpAdaptiveTrailing = true; // Adaptive Trailing
// Volatility-Based Trail Adjustments
input double InpLowVolatilityMultiplier = 0.8; // Low Volatility Multiplier
input double InpHighVolatilityMultiplier = 1.5; // High Volatility Multiplier
input double InpVolatilityThreshold = 1.2; // Volatility Threshold (ATR)
// === PARTIAL CLOSE STRATEGY (Priority 3: Partial Closure Settings) ===
input group "=== Partial Close Strategy ==="
input bool InpPartialEnabled = true; // Enable Partial Closing
input int InpPartialLevels = 4; // Number of Partial Levels
// Progressive Partial Close Levels
input double InpPartialTrigger1 = 50; // Level 1 Trigger (points)
input double InpPartialPercent1 = 20; // Level 1 Close (%)
input double InpPartialTrigger2 = 100; // Level 2 Trigger (points)
input double InpPartialPercent2 = 20; // Level 2 Close (%)
input double InpPartialTrigger3 = 200; // Level 3 Trigger (points)
input double InpPartialPercent3 = 25; // Level 3 Close (%)
input double InpPartialTrigger4 = 400; // Level 4 Trigger (points)
input double InpPartialPercent4 = 20; // Level 4 Close (%)
// Runner Configuration
input double InpRunnerPercentage = 15; // Runner Size (% to keep)
input double InpRunnerTrailMultiplier = 2.0; // Runner Trail Multiplier
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 = true; // 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 ===
input group "Phase-Based Profit Locking"
input bool InpUsePhaseProfitLocks = true; // Enable Phase Profit Locks
input double InpPhaseLockBreathingRoom = 50; // Breathing Room from Peak (%)
input bool InpMaintainLockOnRetreat = true; // Keep Lock When Retreating
input double InpRetreatLockMultiplier = 1.2; // Lock Tightening on Retreat
// Phase Minimum Locks
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)
// === 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
/*
// Management Control
input group "=== Management Control ==="
input string InpInstanceID = "PME1"; // Unique Instance ID
input bool InpManageAllPositions = true; // Manage ALL positions
input int InpMagicFilter = 0; // Filter by Magic (0=all)
input ENUM_MANAGEMENT_MODE InpDefaultMode = MODE_BREAKEVEN_TRAIL; // Default Mode
input ENUM_MANAGEMENT_LEVEL InpStartLevel = LEVEL_STANDARD; // Starting Level
// Risk Protection
input group "=== Risk Protection ==="
input double InpMaxLossPerTrade = 3.0; // Max Loss Per Trade (%)
input double InpMaxDailyLoss = 10.0; // Max Daily Loss (%)
input double InpMaxDrawdown = 25.0; // Max Drawdown (%)
input double InpMaxCorrelation = 0.8; // Max Correlation
// Emergency Stops
input group "=== Emergency Protection ==="
input bool InpApplyEmergencyStops = true; // Apply Emergency Stops
input double InpEmergencySLMultiplier = 2.5; // Emergency SL (ATR)
input double InpEmergencyTPMultiplier = 4.0; // Emergency TP (ATR)
// Stop Management
input group "=== Stop Loss Management ==="
input bool InpDynamicStops = true; // Dynamic Stop Adjustment
input bool InpTightenOnProfit = true; // Tighten Stops on Profit
input double InpTightenThreshold = 50; // Tighten Threshold (points)
input bool InpProtectProfits = true; // Protect Profits
// Breakeven
input group "=== Breakeven Settings ==="
input bool InpBreakevenEnabled = true; // Enable Breakeven
input double InpBreakevenTrigger = 30; // BE Trigger (points)
input double InpBreakevenOffset = 5; // BE Offset (points)
input bool InpMultiLevelBE = false; // Multi-Level Breakeven
// Trailing Stop
input group "=== Trailing Stop ==="
input ENUM_TRAILING_METHOD InpTrailingMethod = TRAIL_ATR; // Trailing Method
input double InpTrailStart = 50; // Trail Start (points)
input double InpTrailDistance = 30; // Trail Distance
input double InpTrailStep = 10; // Trail Step
input bool InpAdaptiveTrailing = true; // Adaptive Trailing
// Partial Close
input group "=== Partial Close ==="
input bool InpPartialEnabled = true; // Enable Partial Close
input double InpPartialTrigger1 = 50; // First Trigger (points)
input double InpPartialPercent1 = 30; // First Close (%)
input double InpPartialTrigger2 = 100; // Second Trigger (points)
input double InpPartialPercent2 = 25; // Second Close (%)
// Exit Management
input group "=== Exit Management ==="
input bool InpUseTechnicalExits = true; // Technical Exit Signals
input bool InpTimeBasedExits = false; // Time-Based Exits
input int InpMaxBarsInTrade = 500; // Max Bars in Trade
input bool InpReduceRiskOverTime = false; // Reduce Risk Over Time
// Time Filters
input group "=== Time Filters ==="
input bool InpUseTimeFilter = false; // Use Time Filter
input int InpStartHour = 8; // Start Hour
input int InpEndHour = 20; // End Hour
input bool InpFridayClose = true; // Friday Close
input int InpFridayCloseHour = 21; // Friday Close Hour
// Display
input group "=== Display Settings ==="
input bool InpShowDashboard = true; // Show Dashboard
input int InpDashboardX = 20; // Dashboard X
input int InpDashboardY = 50; // Dashboard Y
input int InpUpdateFrequency = 2; // Update Frequency (sec)
// System
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 Notifications
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;
// The ProfitMaximizer has its own internal configuration
// Phase thresholds are determined by the module based on profit points
// We just need to ensure it's initialized and will be called during management
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);
}
}
//+------------------------------------------------------------------+
//| 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");
}
}
// 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.2 - Pure Management Edition");
Print("==================================================");
Print("Initializing management system...");
// 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
CreateRectangle(g_dashboard_prefix + "BG", InpDashboardX - 5, y - 5, 250, 400, clrBlack, STYLE_SOLID, 1);
// Header
CreateLabel(g_dashboard_prefix + "HEADER", InpDashboardX, y, "ERMT PME v1.0", 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
CreateLabel(g_dashboard_prefix + "MGMT", InpDashboardX, y, "MANAGEMENT", header_color, 10);
y += 18;
CreateLabel(g_dashboard_prefix + "BREAKEVENS", InpDashboardX, y, "Breakevens: 0", text_color, 9);
y += 15;
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 += 20;
// Performance section
CreateLabel(g_dashboard_prefix + "PERF", InpDashboardX, y, "PERFORMANCE", header_color, 10);
y += 18;
CreateLabel(g_dashboard_prefix + "SAVED", InpDashboardX, y, "Saved: $0.00", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "CAPTURED", InpDashboardX, y, "Captured: $0.00", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "EFFICIENCY", InpDashboardX, y, "Efficiency: 0.0%", text_color, 9);
y += 20;
// Phase Management section (optional - only shown if phase management enabled)
CreateLabel(g_dashboard_prefix + "PHASES_HEADER", InpDashboardX, y, "Position Phases:", header_color, 10);
y += 18;
CreateLabel(g_dashboard_prefix + "PHASE_INIT", InpDashboardX, y, "Initial: 0", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "PHASE_PROT", InpDashboardX, y, "Protection: 0", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "PHASE_ACCUM", InpDashboardX, y, "Accumulation: 0", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "PHASE_MAX", InpDashboardX, y, "Maximization: 0", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "PHASE_RUN", InpDashboardX, y, "Runner: 0", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "PHASE_EXT", InpDashboardX, y, "Extreme: 0", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "RUNNERS", InpDashboardX, y, "Runners Created: 0", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "EXTREMES", InpDashboardX, y, "Extreme Profits: 0", text_color, 9);
y += 20;
// Phase Lock section
CreateLabel(g_dashboard_prefix + "LOCK_HEADER", InpDashboardX, y, "PROFIT LOCKS", header_color, 10);
y += 18;
CreateLabel(g_dashboard_prefix + "LOCKED_MIN", InpDashboardX, y, "Min Locked: 0 pts", text_color, 9);
y += 15;
CreateLabel(g_dashboard_prefix + "LOCK_ACTIVE", InpDashboardX, y, "Active Locks: 0", text_color, 9);
g_dashboard_objects = 35; // Track number of objects (increased from 30)
}
//+------------------------------------------------------------------+
//| 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));
}
// Update comment if dashboard not shown
if(!InpShowDashboard)
{
Comment(StringFormat(
"PME v1.0 | Active: %d | P/L: %.2f | Saved: %.2f | Efficiency: %.1f%%",
g_manager.GetManagedCount(),
g_manager.GetTotalProfit(),
metrics.total_prevented_loss + metrics.total_captured_profit,
metrics.management_efficiency
));
}
}
//+------------------------------------------------------------------+
//| 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");
}
//+------------------------------------------------------------------+
//| 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;
}
}
//+------------------------------------------------------------------+