mql5/Experts/Archive/PME_TestRunner_Diagnostic.mq5

550 righe
34 KiB
MQL5

2025-10-03 10:03:10 +01:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| PME_TestRunner_Diagnostic.mq5 |
//| Diagnostic Version to Identify Test Failures |
//+------------------------------------------------------------------+
#property copyright "PME Test Runner Diagnostic v1.01"
#property version "1.01"
#property description "Diagnostic testing system for ERMT PME"
// Include test suite and PME modules
#include "Modules_PME/DataTypes_PME.mqh"
#include "Modules_PME/Utilities_PME.mqh"
#include "Modules_PME/RiskManager_PME.mqh"
High-level summary TechnicalAnalysis_PME_Fixed.mqh (call it "Fixed") is oriented toward robust ATR handling and keeps indicator handles as class members with create/release helpers. It contains fallback logic for ATR creation and a manual ATR calculation if indicator creation fails. TechnicalAnalysis_PME_Optimised.mqh (call it "Optimised") provides a richer set of analysis methods (advanced exit checks, divergence, ADX trend strength, MACD retrieval, volatility ratio) and more conservative/confirmed exit logic. It is more feature-rich for exit decision-making but uses simpler ATR handling (no manual fallback) and often creates temporary indicator handles in getters. File / header differences Fixed header: "Fixed Version with Proper ATR Handling". Optimised header: "Optimized Technical Analysis for PME (v1.1) — [FIXED: Premature Exit Signals]". Optimised defines a local enum ENUM_SIGNAL_TYPE (includes SIGNAL_EXIT); Fixed relies on similar enums but the file you provided doesn't show a local definition for ENUM_SIGNAL_TYPE — the Fixed class uses ENUM_SIGNAL_TYPE and ENUM_MARKET_CONDITION in its API (assumed defined in included headers). Class design and indicator handle management Fixed: Class members: m_atr_handle, m_ma_handle, m_rsi_handle, m_sar_handle, m_macd_handle, m_bb_handle. Has CreateIndicators() and ReleaseIndicators() helper methods to create and clean up member indicator handles. Initialize() calls CreateIndicators() and returns true (even if some indicators fail). It logs warnings and does not fail initialization on missing indicators. GetATR prefers the member m_atr_handle when symbol == _Symbol, otherwise creates a temporary handle; if indicators fail, it contains a manual ATR calculation fallback (averaging TR). Optimised: Class members: same set, initialized in Initialize, released in destructor. Initialize() creates the indicators directly (no separate CreateIndicators function). It returns success boolean only if essential indicators were created (checks m_atr_handle, m_ma_handle, m_rsi_handle). GetATR creates a temporary handle every time (iATR(symbol,...)), copies the buffer and releases the handle — no manual ATR fallback. Destructor explicitly releases any member indicator handles. Implication: Fixed is more defensive about indicator creation and provides fallback ATR computation for resilience on limited indicator support or resource errors. Optimised is simpler/leaner but will return 0 if ATR creation fails (no manual fallback). ATR handling — biggest behavioral difference Fixed: CreateIndicators() includes multiple fallback attempts for ATR: tries _Symbol, NULL, then an alternate timeframe (PERIOD_M1). It logs each attempt and can still succeed in alternate ways. If CopyBuffer from a temporary handle fails, Fixed then computes ATR manually using True Range over past 14 bars (using iHigh/iLow/iClose). In GetATR, if the member handle is valid and symbol == _Symbol, it uses the cached handle and CopyBuffer for efficiency. Optimised: GetATR simply creates a handle with iATR(symbol,...), copies buffer, releases it; if handle invalid or copy fails, returns 0. Initialize creates m_atr_handle but GetATR doesn't use the member handle — it creates a new one every call. Implication: Fixed will be more robust in environments where indicator handles sometimes fail; Optimised is simpler and possibly slower (creating/releasing handles each call) but straightforward. Methods and API surface differences Methods present in Fixed but not (or different) in Optimised: Fixed: GetSignal(string) — Implements a simple scoring system using RSI, MA, SAR and returns ENUM_SIGNAL_TYPE (SIGNAL_BUY/SELL/NONE). Fixed: GetMarketCondition(), GetOptimalStop(), GetOptimalTarget(), FindKeyLevels() — present in both but implementations differ slightly. Methods present in Optimised (new/advanced) not in Fixed: CheckExitSignal(string, ENUM_ORDER_TYPE, double entry_price, double current_price) — multi-confirmation exit logic (requires multiple signals). CheckExitSignalAdvanced(...) — adds bars_in_trade and profit_points filters to avoid exiting early. IsStrongReversal(string, ENUM_ORDER_TYPE) — checks BB bands, RSI extremes and MA crosses to detect strong reversals. IsDivergence(string, ENUM_ORDER_TYPE) — simplified divergence detection using RSI history and price series. GetMACD(string, int &signal_line) — returns MACD value and signal line (signal_line scaled to int points in code). GetVolatilityRatio(), GetTrendStrength() (uses ADX). Optimised includes GetMomentum but with different calculation (percent change vs Fixed's ratio-based result). Fixed includes CreateIndicators() and ReleaseIndicators() which centralize handle management. Implication: Optimised introduces more sophisticated exit/confirmation logic, better for preventing premature exits (as comment indicated). Fixed focuses on indicator reliability. Exit logic and confirmation strategy Fixed's GetSignal is a straightforward scoring system (bull/bear scores) and returns simple signals. Optimised's CheckExitSignal/Advanced require multiple confirmations (SIGNALS_REQUIRED=2), use stricter thresholds (e.g., RSI > 80 / < 20), consider trade age and profit when allowing exits (bars_in_trade, profit_points), and include divergence and strong reversal filters. Implication: Optimised is conservative about exits (helps avoid chopping out of trades); Fixed provides basic signals that may produce earlier exits. Momentum and volatility calculations Fixed: GetMomentum returns (close_now / close_before) * 100 (so 100 means unchanged). GetVolatility returns ATR as percentage of price: (atr / price) * 100. Optimised: GetMomentum returns percent change: ((close_now - close_past) / close_past) * 100. GetVolatility returns ATR (not converted to percent) in one place and GetVolatilityRatio returns current_atr / avg_atr by averaging last 20 ATR values. Also has GetTrendStrength using ADX. Implication: Numeric scales differ (Fixed's momentum centers at 100; Optimised centers at 0). If other code consumes GetMomentum, that difference can cause misinterpretation. Resource usage and performance Fixed caches handles and uses member handles where possible; it also has code paths to manually compute ATR (no handle allocations). Optimised sometimes creates and destroys temporary handles per-call (e.g., GetATR, GetMA, GetMACD), which is simpler but creates overhead. However Optimised also stores member handles and could be modified to use them more consistently. Implication: Fixed may be slightly more efficient after initial CreateIndicators (and more robust), Optimised may be simpler to maintain but could be optimized to reuse handles instead of creating them per call. Error handling and logging Fixed logs detailed attempts and warns via m_utils when indicators fail; it tries fallbacks. Optimised logs errors when handles fail but doesn't attempt alternate timeframes or manual ATR fallback. It also logs initialization success only when core indicators are present. Implication: Fixed is built for resilience in constrained environments; Optimised expects typical environment and favors clearer failure signaling. Specific code/behavioral differences (notable snippets) ATR fallback (Fixed): Manual TR loop: for i = 1..14: compute high-low and compare with prev close to derive TR and average it. Multiple attempts to create ATR: iATR(_Symbol), iATR(NULL), iATR(_Symbol, PERIOD_M1). Exit condition thresholds (Optimised): RSI thresholds tightened: 80 (exit long) and 20 (exit short) vs Fixed uses 70/30 in signal scoring. Requires at least 2 confirmation signals before exiting. Divergence detection (Optimised): Uses CopyBuffer for 10 RSI historical values and CopyClose for price history; then compares bars offset (primitive but explicit). MACD: Optimised GetMACD returns macd_buffer[0] and scales signal_line to int points (signal_line = (int)(signal_buffer[0] * 100000)). Fixed does not implement this exact helper (but has m_macd_handle as a member). FindKeyLevels: Both include round numbers and ATR/MA/SAR levels. Minor differences in ordering and resizing logic, but functionally similar. Integration risks / things to watch for Different numeric semantics: GetMomentum scales differ: Fixed returns around 100 for unchanged, Optimised returns 0. Caller code must expect the right scale. ATR semantics: If other code expects non-zero ATR even when indicators fail, Fixed is safer due to manual fallback. Optimised may return 0 and downstream code must handle that. Handle reuse: Optimised often creates temporary indicator handles in getters — can be optimized or cause performance hits if called frequently (e.g., per-tick on many symbols). Enum/API mismatch: ENUM_SIGNAL_TYPE is declared inside Optimised; Fixed uses it — ensure consistent enum definitions and values across other included headers. Method names and signatures: Optimised added many methods; if you swap implementations between files, ensure callers exist or are adapted (e.g., CheckExitSignalAdvanced vs previous CheckExitSignal). Suggested next steps If you want the robustness of Fixed and the exit-safety of Optimised, merge the best of both: Use Fixed's ATR fallback logic inside Optimised's GetATR (or use member handle when valid). Keep Optimised's conservative CheckExitSignal and CheckExitSignalAdvanced. Harmonize GetMomentum scale (pick one and adjust callers). Prefer using member handles (create in Initialize / CreateIndicators) and use CopyBuffer on members to avoid creating/releasing handles each call.
2025-10-28 13:59:12 +00:00
#include "Modules_PME/TechnicalAnalysis_PME_Merged.mqh"
2025-10-03 10:03:10 +01:00
#include "Modules_PME/PositionManager_PME.mqh"
#include "Modules_PME/PME_TestSuite_Fixed.mqh"
//+------------------------------------------------------------------+
//| Input Parameters |
//+------------------------------------------------------------------+
input bool InpDiagnosticMode = true; // Diagnostic Mode
input bool InpTestComponents = true; // Test Component Creation
input bool InpTestInitialization = true; // Test Initialization
input bool InpTestBasicOperations = true; // Test Basic Operations
input bool InpCreateRealPositions = false; // Create Real Positions
//+------------------------------------------------------------------+
//| Global Variables |
//+------------------------------------------------------------------+
CUtilities* g_utils = NULL;
CRiskManager* g_risk = NULL;
CTechnicalAnalysis* g_tech = NULL;
CPositionManager* g_manager = NULL;
CPMETestSuite* g_test_suite = NULL;
int g_tests_run = 0;
int g_tests_passed = 0;
int g_tests_failed = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
Print("========================================");
Print(" PME DIAGNOSTIC TEST RUNNER v1.01");
Print("========================================");
Print("Starting diagnostic tests...\n");
// Run diagnostic tests
RunDiagnostics();
// Report results
GenerateDiagnosticReport();
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Run All Diagnostics |
//+------------------------------------------------------------------+
void RunDiagnostics()
{
Print("=== DIAGNOSTIC TEST SEQUENCE ===\n");
// Test 1: Component Creation
if(InpTestComponents)
{
Print("TEST 1: Component Creation");
if(TestComponentCreation())
{
RecordTest("Component Creation", true);
Print(" ' PASSED - All components created\n");
}
else
{
RecordTest("Component Creation", false);
Print(" ' FAILED - Component creation failed\n");
return; // Stop here if components can't be created
}
}
// Test 2: Component Initialization
if(InpTestInitialization)
{
Print("TEST 2: Component Initialization");
if(TestComponentInitialization())
{
RecordTest("Component Initialization", true);
Print(" ' PASSED - All components initialized\n");
}
else
{
RecordTest("Component Initialization", false);
Print(" ' FAILED - Initialization failed\n");
return; // Stop here if initialization fails
}
}
// Test 3: Basic Operations
if(InpTestBasicOperations)
{
Print("TEST 3: Basic Operations");
if(TestBasicOperations())
{
RecordTest("Basic Operations", true);
Print(" ' PASSED - Basic operations work\n");
}
else
{
RecordTest("Basic Operations", false);
Print(" ' FAILED - Basic operations failed\n");
}
}
// Test 4: Position Management (without creating real positions)
Print("TEST 4: Position Management Functions");
if(TestPositionManagementFunctions())
{
RecordTest("Position Management", true);
Print(" ' PASSED - Position management functions work\n");
}
else
{
RecordTest("Position Management", false);
Print(" ' FAILED - Position management functions failed\n");
}
// Test 5: Technical Indicators
Print("TEST 5: Technical Indicators");
if(TestTechnicalIndicators())
{
RecordTest("Technical Indicators", true);
Print(" ' PASSED - Indicators work\n");
}
else
{
RecordTest("Technical Indicators", false);
Print(" ' FAILED - Indicators failed\n");
}
}
//+------------------------------------------------------------------+
//| Test Component Creation |
//+------------------------------------------------------------------+
bool TestComponentCreation()
{
bool all_created = true;
// Test Utilities
Print(" Creating CUtilities...");
g_utils = new CUtilities();
if(g_utils == NULL)
{
Print(" ' Failed to create CUtilities");
all_created = false;
}
else
{
Print(" ' CUtilities created");
}
// Test RiskManager
Print(" Creating CRiskManager...");
g_risk = new CRiskManager();
if(g_risk == NULL)
{
Print(" ' Failed to create CRiskManager");
all_created = false;
}
else
{
Print(" ' CRiskManager created");
}
// Test TechnicalAnalysis
Print(" Creating CTechnicalAnalysis...");
g_tech = new CTechnicalAnalysis();
if(g_tech == NULL)
{
Print(" ' Failed to create CTechnicalAnalysis");
all_created = false;
}
else
{
Print(" ' CTechnicalAnalysis created");
}
// Test PositionManager
Print(" Creating CPositionManager...");
g_manager = new CPositionManager();
if(g_manager == NULL)
{
Print(" ' Failed to create CPositionManager");
all_created = false;
}
else
{
Print(" ' CPositionManager created");
}
// Test TestSuite
Print(" Creating CPMETestSuite...");
g_test_suite = new CPMETestSuite();
if(g_test_suite == NULL)
{
Print(" ' Failed to create CPMETestSuite");
all_created = false;
}
else
{
Print(" ' CPMETestSuite created");
}
return all_created;
}
//+------------------------------------------------------------------+
//| Test Component Initialization |
//+------------------------------------------------------------------+
bool TestComponentInitialization()
{
bool all_initialized = true;
// Initialize Utilities
Print(" Initializing Utilities...");
if(g_utils != NULL)
{
if(g_utils.Initialize(LOG_INFO, false))
{
Print(" ' Utilities initialized");
}
else
{
Print(" ' Utilities initialization failed");
all_initialized = false;
}
}
else
{
Print(" ' Utilities is NULL");
all_initialized = false;
}
// Initialize RiskManager
Print(" Initializing RiskManager...");
if(g_risk != NULL && g_utils != NULL)
{
if(g_risk.Initialize(g_utils, 2.0, 6.0, 20.0))
{
Print(" ' RiskManager initialized");
}
else
{
Print(" ' RiskManager initialization failed");
all_initialized = false;
}
}
else
{
Print(" ' RiskManager or dependencies are NULL");
all_initialized = false;
}
// Initialize TechnicalAnalysis
Print(" Initializing TechnicalAnalysis...");
if(g_tech != NULL && g_utils != NULL)
{
if(g_tech.Initialize(g_utils))
{
Print(" ' TechnicalAnalysis initialized");
}
else
{
Print(" ' TechnicalAnalysis initialization failed");
Print(" Note: This often fails if indicators can't be created");
all_initialized = false;
}
}
else
{
Print(" ' TechnicalAnalysis or dependencies are NULL");
all_initialized = false;
}
// Initialize PositionManager
Print(" Initializing PositionManager...");
if(g_manager != NULL && g_utils != NULL && g_risk != NULL && g_tech != NULL)
{
if(g_manager.Initialize(g_utils, g_risk, g_tech, 999999))
{
Print(" ' PositionManager initialized");
}
else
{
Print(" ' PositionManager initialization failed");
all_initialized = false;
}
}
else
{
Print(" ' PositionManager or dependencies are NULL");
all_initialized = false;
}
// Initialize TestSuite
Print(" Initializing TestSuite...");
if(g_test_suite != NULL && g_manager != NULL && g_utils != NULL)
{
if(g_test_suite.Initialize(g_manager, g_utils))
{
Print(" ' TestSuite initialized");
}
else
{
Print(" ' TestSuite initialization failed");
all_initialized = false;
}
}
else
{
Print(" ' TestSuite or dependencies are NULL");
all_initialized = false;
}
return all_initialized;
}
//+------------------------------------------------------------------+
//| Test Basic Operations |
//+------------------------------------------------------------------+
bool TestBasicOperations()
{
bool all_passed = true;
// Test logging
Print(" Testing logging...");
if(g_utils != NULL)
{
g_utils.Log("Test log message", LOG_INFO);
Print(" ' Logging works");
}
else
{
Print(" ' Utils not available");
all_passed = false;
}
// Test risk calculations
Print(" Testing risk calculations...");
if(g_risk != NULL)
{
double daily_loss = g_risk.GetDailyLoss();
double drawdown = g_risk.GetDrawdown();
Print(StringFormat(" Daily Loss: %.2f%%, Drawdown: %.2f%%", daily_loss, drawdown));
if(daily_loss >= 0 && drawdown >= 0)
{
Print(" ' Risk calculations work");
}
else
{
Print(" ' Risk calculations returned invalid values");
all_passed = false;
}
}
else
{
Print(" ' RiskManager not available");
all_passed = false;
}
// Test position scanning
Print(" Testing position scanning...");
if(g_manager != NULL)
{
g_manager.ScanForPositions();
int count = g_manager.GetManagedCount();
Print(StringFormat(" Found %d positions", count));
Print(" ' Position scanning works");
}
else
{
Print(" ' PositionManager not available");
all_passed = false;
}
return all_passed;
}
//+------------------------------------------------------------------+
//| Test Position Management Functions |
//+------------------------------------------------------------------+
bool TestPositionManagementFunctions()
{
if(g_manager == NULL) return false;
bool all_passed = true;
// Test configuration
Print(" Testing configuration...");
ManagementConfig config;
config.breakeven_enabled = true;
config.breakeven_trigger = 20;
config.trailing_method = TRAIL_ATR;
g_manager.SetConfiguration(config);
Print(" ' Configuration set");
// Test metrics
Print(" Testing metrics...");
SessionMetrics metrics;
g_manager.GetSessionMetrics(metrics);
Print(StringFormat(" Session started: %s", TimeToString(metrics.session_start)));
Print(" ' Metrics accessible");
// Test risk assessment
Print(" Testing risk assessment...");
RiskAssessment assessment = g_manager.AssessPortfolioRisk();
Print(StringFormat(" Risk level: %d", assessment.level));
Print(" ' Risk assessment works");
return all_passed;
}
//+------------------------------------------------------------------+
//| Test Technical Indicators |
//+------------------------------------------------------------------+
bool TestTechnicalIndicators()
{
if(g_tech == NULL) return false;
bool all_passed = true;
// Test ATR
Print(" Testing ATR...");
double atr = g_tech.GetATR(_Symbol);
if(atr > 0)
{
Print(StringFormat(" ATR: %.5f", atr));
Print(" ' ATR works");
}
else
{
Print(" ' ATR returned 0");
all_passed = false;
}
// Test RSI
Print(" Testing RSI...");
double rsi = g_tech.GetRSI(_Symbol);
if(rsi > 0 && rsi < 100)
{
Print(StringFormat(" RSI: %.2f", rsi));
Print(" ' RSI works");
}
else
{
Print(" ' RSI returned invalid value");
all_passed = false;
}
// Test Market Condition
Print(" Testing market condition...");
ENUM_MARKET_CONDITION condition = g_tech.GetMarketCondition(_Symbol);
Print(StringFormat(" Market: %s", EnumToString(condition)));
Print(" ' Market condition works");
return all_passed;
}
//+------------------------------------------------------------------+
//| Record Test Result |
//+------------------------------------------------------------------+
void RecordTest(string test_name, bool passed)
{
g_tests_run++;
if(passed)
g_tests_passed++;
else
g_tests_failed++;
}
//+------------------------------------------------------------------+
//| Generate Diagnostic Report |
//+------------------------------------------------------------------+
void GenerateDiagnosticReport()
{
Print("\n========================================");
Print(" DIAGNOSTIC REPORT");
Print("========================================");
Print(StringFormat("Tests Run: %d", g_tests_run));
Print(StringFormat("Tests Passed: %d", g_tests_passed));
Print(StringFormat("Tests Failed: %d", g_tests_failed));
Print(StringFormat("Success Rate: %.1f%%",
g_tests_run > 0 ? (double)g_tests_passed / g_tests_run * 100 : 0));
Print("\n--- Diagnostic Summary ---");
if(g_tests_failed == 0)
{
Print("' ALL DIAGNOSTIC TESTS PASSED");
Print("The PME system appears to be functioning correctly.");
Print("Try running the full test suite with real position testing.");
}
else
{
Print("L' DIAGNOSTIC TESTS FAILED");
Print("\nLikely Issues:");
if(g_tech == NULL || !TestTechnicalIndicators())
{
Print("" Technical indicators failing - Check chart has enough history");
Print("" Try switching to a major pair (EURUSD) with H1 timeframe");
}
if(g_manager == NULL)
{
Print("" Position manager not initializing - Check dependencies");
}
Print("\nRecommended Actions:");
Print("1. Ensure chart has at least 100 bars of history");
Print("2. Switch to EURUSD H1 timeframe");
Print("3. Check Expert Advisors are enabled");
Print("4. Verify AutoTrading is ON");
}
Print("========================================\n");
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
// Cleanup
if(g_test_suite != NULL) { delete g_test_suite; g_test_suite = NULL; }
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_utils != NULL) { delete g_utils; g_utils = NULL; }
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Not used in diagnostic mode
}
//+------------------------------------------------------------------+