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
1518 lines
No EOL
61 KiB
MQL5
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;
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+ |