//+------------------------------------------------------------------+ //| EMERGENCY ALGORITHMIC FIXES FOR SNIPER EA | //| Critical fixes for weekend test failures | //| - BOS Detection Algorithm Overhaul | //| - Liquidity Sweep Zone-Based Detection | //| - Historical Data Processing Fixes | //| - Memory Management Improvements | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| CRITICAL FIX #1: IMPROVED BOS DETECTION ALGORITHM | //+------------------------------------------------------------------+ // New structure for improved swing point detection struct SwingPointImproved { double price; datetime time; bool is_high; double strength; int detection_method; // 0=3-bar, 1=5-bar, 2=8-bar, 3=13-bar int confirmation_count; }; // Improved swing point detection with multiple timeframe validation bool FindSwingPointsImproved(string symbol, ENUM_TIMEFRAMES timeframe, int bars_to_analyze, double &swing_highs[], double &swing_lows[], datetime &swing_high_times[], datetime &swing_low_times[]) { ArrayResize(swing_highs, 0); ArrayResize(swing_lows, 0); ArrayResize(swing_high_times, 0); ArrayResize(swing_low_times, 0); // Use multiple lookback periods for better detection (Fibonacci-based) int lookback_periods[] = {3, 5, 8, 13}; double confidence_threshold = 0.6; // Require 60% of bars to confirm swing for (int p = 0; p < ArraySize(lookback_periods); p++) { int current_lookback = lookback_periods[p]; for (int i = current_lookback; i < bars_to_analyze - current_lookback; i++) { // More flexible swing detection - use percentage-based confirmation int higher_count = 0, lower_count = 0; int total_comparison_bars = current_lookback * 2; double current_high = iHigh(symbol, timeframe, i); double current_low = iLow(symbol, timeframe, i); // Check surrounding bars for (int j = i - current_lookback; j <= i + current_lookback; j++) { if (j != i && j >= 0 && j < iBars(symbol, timeframe)) { if (iHigh(symbol, timeframe, j) < current_high) higher_count++; if (iLow(symbol, timeframe, j) > current_low) lower_count++; } } // Calculate confidence levels double high_confidence = (double)higher_count / total_comparison_bars; double low_confidence = (double)lower_count / total_comparison_bars; // Add swing high if confidence threshold met if (high_confidence >= confidence_threshold) { if (!IsSwingPointDuplicate(swing_highs, swing_high_times, current_high, iTime(symbol, timeframe, i))) { ArrayResize(swing_highs, ArraySize(swing_highs) + 1); ArrayResize(swing_high_times, ArraySize(swing_high_times) + 1); swing_highs[ArraySize(swing_highs) - 1] = current_high; swing_high_times[ArraySize(swing_high_times) - 1] = iTime(symbol, timeframe, i); } } // Add swing low if confidence threshold met if (low_confidence >= confidence_threshold) { if (!IsSwingPointDuplicate(swing_lows, swing_low_times, current_low, iTime(symbol, timeframe, i))) { ArrayResize(swing_lows, ArraySize(swing_lows) + 1); ArrayResize(swing_low_times, ArraySize(swing_low_times) + 1); swing_lows[ArraySize(swing_lows) - 1] = current_low; swing_low_times[ArraySize(swing_low_times) - 1] = iTime(symbol, timeframe, i); } } } } Print(StringFormat("Improved swing detection found %d highs and %d lows for %s %s", ArraySize(swing_highs), ArraySize(swing_lows), symbol, EnumToString(timeframe))); return ArraySize(swing_highs) > 0 || ArraySize(swing_lows) > 0; } // Helper function to prevent duplicate swing points bool IsSwingPointDuplicate(double &existing_prices[], datetime &existing_times[], double new_price, datetime new_time) { double pip_value = 0.0001; // Default for most pairs double tolerance = 5.0 * pip_value; // 5-pip tolerance for duplicates for (int i = 0; i < ArraySize(existing_prices); i++) { if (MathAbs(existing_prices[i] - new_price) <= tolerance) return true; } return false; } //+------------------------------------------------------------------+ //| CRITICAL FIX #2: ZONE-BASED LIQUIDITY SWEEP DETECTION | //+------------------------------------------------------------------+ // New structure for liquidity zones struct LiquidityZone { double upper_bound; double lower_bound; double center_price; datetime formation_time; datetime sweep_time; bool is_high_zone; int touch_count; double zone_strength; bool is_swept; }; // Improved liquidity sweep detection using zones instead of exact levels bool DetectLiquiditySweepsImproved(string symbol, ENUM_TIMEFRAMES timeframe, LiquiditySweep &sweep_array[]) { ArrayResize(sweep_array, 0); int bars_to_analyze = MathMin(150, iBars(symbol, timeframe) - 10); // Increased analysis range if (bars_to_analyze < 30) return false; Print(StringFormat("Analyzing %d bars for improved liquidity sweeps on %s %s", bars_to_analyze, symbol, EnumToString(timeframe))); // Create liquidity zones instead of exact levels LiquidityZone zones[]; if (!CreateLiquidityZones(symbol, timeframe, bars_to_analyze, zones)) return false; // Detect sweeps of liquidity zones for (int i = 0; i < ArraySize(zones); i++) { if (DetectZoneSweep(symbol, timeframe, zones[i])) { LiquiditySweep sweep; sweep.level = zones[i].center_price; sweep.time = zones[i].sweep_time; sweep.is_high_sweep = zones[i].is_high_zone; sweep.confirmed = true; // Zone-based sweeps are auto-confirmed ArrayResize(sweep_array, ArraySize(sweep_array) + 1); sweep_array[ArraySize(sweep_array) - 1] = sweep; Print(StringFormat("Zone sweep detected: %s at %.5f (zone: %.5f-%.5f)", zones[i].is_high_zone ? "HIGH" : "LOW", zones[i].center_price, zones[i].lower_bound, zones[i].upper_bound)); } } Print(StringFormat("Found %d zone-based liquidity sweeps on %s %s", ArraySize(sweep_array), symbol, EnumToString(timeframe))); return ArraySize(sweep_array) > 0; } // Create liquidity zones from price clusters bool CreateLiquidityZones(string symbol, ENUM_TIMEFRAMES timeframe, int bars_to_analyze, LiquidityZone &zones[]) { ArrayResize(zones, 0); double pip_value = CalculatePipValue(symbol); double zone_width = 10.0 * pip_value; // 10-pip zones (increased from 3-pip exact levels) // Get recent significant highs and lows double recent_highs[], recent_lows[]; datetime high_times[], low_times[]; GetRecentSignificantLevels(symbol, timeframe, bars_to_analyze, recent_highs, recent_lows, high_times, low_times); // Create zones from clustered highs CreateZonesFromLevels(recent_highs, high_times, true, zone_width, zones); // Create zones from clustered lows CreateZonesFromLevels(recent_lows, low_times, false, zone_width, zones); Print(StringFormat("Created %d liquidity zones for %s %s", ArraySize(zones), symbol, EnumToString(timeframe))); return ArraySize(zones) > 0; } // Get significant price levels for zone creation void GetRecentSignificantLevels(string symbol, ENUM_TIMEFRAMES timeframe, int bars_to_analyze, double &highs[], double &lows[], datetime &high_times[], datetime &low_times[]) { ArrayResize(highs, 0); ArrayResize(lows, 0); ArrayResize(high_times, 0); ArrayResize(low_times, 0); // Use improved swing detection double swing_highs[], swing_lows[]; datetime swing_high_times[], swing_low_times[]; if (FindSwingPointsImproved(symbol, timeframe, bars_to_analyze, swing_highs, swing_lows, swing_high_times, swing_low_times)) { ArrayCopy(highs, swing_highs); ArrayCopy(lows, swing_lows); ArrayCopy(high_times, swing_high_times); ArrayCopy(low_times, swing_low_times); } } // Create zones from price level clusters void CreateZonesFromLevels(double &levels[], datetime ×[], bool is_high_zone, double zone_width, LiquidityZone &zones[]) { for (int i = 0; i < ArraySize(levels); i++) { double center_price = levels[i]; // Check if this level is already part of an existing zone bool already_in_zone = false; for (int j = 0; j < ArraySize(zones); j++) { if (center_price >= zones[j].lower_bound && center_price <= zones[j].upper_bound) { already_in_zone = true; zones[j].touch_count++; // Increase zone strength break; } } if (!already_in_zone) { // Create new zone LiquidityZone new_zone; new_zone.center_price = center_price; new_zone.upper_bound = center_price + (zone_width / 2); new_zone.lower_bound = center_price - (zone_width / 2); new_zone.formation_time = times[i]; new_zone.is_high_zone = is_high_zone; new_zone.touch_count = 1; new_zone.zone_strength = 1.0; new_zone.is_swept = false; ArrayResize(zones, ArraySize(zones) + 1); zones[ArraySize(zones) - 1] = new_zone; } } } // Detect if a liquidity zone has been swept bool DetectZoneSweep(string symbol, ENUM_TIMEFRAMES timeframe, LiquidityZone &zone) { if (zone.is_swept) return false; // Already swept int zone_bar = iBarShift(symbol, timeframe, zone.formation_time); if (zone_bar < 0) return false; // Look for price action that sweeps through the zone for (int i = 0; i < zone_bar && i < 50; i++) // Increased search range { double bar_high = iHigh(symbol, timeframe, i); double bar_low = iLow(symbol, timeframe, i); double bar_close = iClose(symbol, timeframe, i); if (zone.is_high_zone) { // Check for sweep above zone with rejection if (bar_high > zone.upper_bound && bar_close < zone.center_price) { zone.sweep_time = iTime(symbol, timeframe, i); zone.is_swept = true; return true; } } else { // Check for sweep below zone with rejection if (bar_low < zone.lower_bound && bar_close > zone.center_price) { zone.sweep_time = iTime(symbol, timeframe, i); zone.is_swept = true; return true; } } } return false; } //+------------------------------------------------------------------+ //| CRITICAL FIX #3: HISTORICAL DATA PROCESSING FIXES | //+------------------------------------------------------------------+ // Improved BOS validation using bar-based instead of time-based logic bool IsBOSValidImproved(string symbol, ENUM_TIMEFRAMES timeframe, BreakOfStructure &bos) { // Use bar shift instead of time difference for historical compatibility int bos_bar = iBarShift(symbol, timeframe, bos.time); if (bos_bar < 0) return false; // Check if BOS is within reasonable bar distance (not time distance) if (bos_bar > 50) // Increased from previous restrictive limits return false; // Validate price action relative to BOS level with buffer double current_price = iClose(symbol, timeframe, 0); double pip_value = CalculatePipValue(symbol); double bos_validation_buffer = 5.0 * pip_value; // 5-pip buffer for validation if (bos.is_bullish) { // For bullish BOS, current price should be above level (with buffer) return current_price > (bos.level - bos_validation_buffer); } else { // For bearish BOS, current price should be below level (with buffer) return current_price < (bos.level + bos_validation_buffer); } } // Improved liquidity sweep validation using bar-based logic bool IsLiquiditySweepValidImproved(string symbol, ENUM_TIMEFRAMES timeframe, LiquiditySweep &sweep) { if (!sweep.confirmed) return false; // Use bar-based validation instead of time-based int sweep_bar = iBarShift(symbol, timeframe, sweep.time); if (sweep_bar < 0 || sweep_bar > 30) // Within 30 bars instead of 10 time periods return false; // More flexible price position validation with buffer double current_price = iClose(symbol, timeframe, 0); double pip_value = CalculatePipValue(symbol); double validation_buffer = 8.0 * pip_value; // 8-pip buffer for flexibility if (sweep.is_high_sweep) { // For high sweep, price should be below swept level (with buffer) return current_price < (sweep.level + validation_buffer); } else { // For low sweep, price should be above swept level (with buffer) return current_price > (sweep.level - validation_buffer); } } //+------------------------------------------------------------------+ //| CRITICAL FIX #4: MEMORY MANAGEMENT AND ARRAY CLEANUP | //+------------------------------------------------------------------+ #define MAX_PATTERN_HISTORY 50 #define CLEANUP_FREQUENCY 25 struct PatternArrayManager { int cleanup_counter; datetime last_cleanup; bool cleanup_enabled; }; PatternArrayManager g_array_manager = {0, 0, true}; // Initialize array management system void InitializeArrayManager() { g_array_manager.cleanup_counter = 0; g_array_manager.last_cleanup = TimeCurrent(); g_array_manager.cleanup_enabled = true; Print("Pattern Array Manager initialized"); } // Main cleanup function for all pattern arrays void CleanupPatternArrays(MarketStructureData &mtf_data) { if (!g_array_manager.cleanup_enabled) return; g_array_manager.cleanup_counter++; if (g_array_manager.cleanup_counter >= CLEANUP_FREQUENCY) { Print(StringFormat("Performing pattern array cleanup (cycle %d)", g_array_manager.cleanup_counter)); // Clean up old patterns to prevent memory issues int ob_before = ArraySize(mtf_data.order_blocks); int fvg_before = ArraySize(mtf_data.fair_value_gaps); int bos_before = ArraySize(mtf_data.bos_events); int sweep_before = ArraySize(mtf_data.liquidity_sweeps); CleanupOldOrderBlocks(mtf_data.order_blocks); CleanupOldFVGs(mtf_data.fair_value_gaps); CleanupOldBOSEvents(mtf_data.bos_events); CleanupOldSweeps(mtf_data.liquidity_sweeps); Print(StringFormat("Cleanup completed: OB %d->%d, FVG %d->%d, BOS %d->%d, Sweeps %d->%d", ob_before, ArraySize(mtf_data.order_blocks), fvg_before, ArraySize(mtf_data.fair_value_gaps), bos_before, ArraySize(mtf_data.bos_events), sweep_before, ArraySize(mtf_data.liquidity_sweeps))); g_array_manager.cleanup_counter = 0; g_array_manager.last_cleanup = TimeCurrent(); } } // Cleanup old order blocks void CleanupOldOrderBlocks(OrderBlock &order_blocks[]) { if (ArraySize(order_blocks) <= MAX_PATTERN_HISTORY) return; // Keep only the most recent patterns int keep_count = MAX_PATTERN_HISTORY; OrderBlock temp_array[]; ArrayResize(temp_array, keep_count); // Copy most recent patterns for (int i = 0; i < keep_count; i++) { temp_array[i] = order_blocks[ArraySize(order_blocks) - keep_count + i]; } // Replace original array ArrayResize(order_blocks, keep_count); for (int i = 0; i < keep_count; i++) { order_blocks[i] = temp_array[i]; } } // Cleanup old FVGs void CleanupOldFVGs(FairValueGap &fvgs[]) { if (ArraySize(fvgs) <= MAX_PATTERN_HISTORY) return; int keep_count = MAX_PATTERN_HISTORY; FairValueGap temp_array[]; ArrayResize(temp_array, keep_count); for (int i = 0; i < keep_count; i++) { temp_array[i] = fvgs[ArraySize(fvgs) - keep_count + i]; } ArrayResize(fvgs, keep_count); for (int i = 0; i < keep_count; i++) { fvgs[i] = temp_array[i]; } } // Cleanup old BOS events void CleanupOldBOSEvents(BreakOfStructure &bos_events[]) { if (ArraySize(bos_events) <= MAX_PATTERN_HISTORY) return; int keep_count = MAX_PATTERN_HISTORY; BreakOfStructure temp_array[]; ArrayResize(temp_array, keep_count); for (int i = 0; i < keep_count; i++) { temp_array[i] = bos_events[ArraySize(bos_events) - keep_count + i]; } ArrayResize(bos_events, keep_count); for (int i = 0; i < keep_count; i++) { bos_events[i] = temp_array[i]; } } // Cleanup old liquidity sweeps void CleanupOldSweeps(LiquiditySweep &sweeps[]) { if (ArraySize(sweeps) <= MAX_PATTERN_HISTORY) return; int keep_count = MAX_PATTERN_HISTORY; LiquiditySweep temp_array[]; ArrayResize(temp_array, keep_count); for (int i = 0; i < keep_count; i++) { temp_array[i] = sweeps[ArraySize(sweeps) - keep_count + i]; } ArrayResize(sweeps, keep_count); for (int i = 0; i < keep_count; i++) { sweeps[i] = temp_array[i]; } } //+------------------------------------------------------------------+ //| CRITICAL FIX #5: IMPROVED CONFLUENCE VALIDATION | //+------------------------------------------------------------------+ struct PatternScore { double sweep_score; // 0-25 points double bos_score; // 0-25 points double fvg_score; // 0-25 points double ob_score; // 0-25 points double total_score; // Sum of all scores string score_breakdown; // Detailed breakdown for logging }; // Improved confluence validation using scoring system bool ValidateFlexibleConfluenceImproved(string symbol, bool is_bullish, MarketStructureData &m1_data) { Print(StringFormat("=== Improved Confluence Validation for %s %s Setup ===", symbol, is_bullish ? "Bullish" : "Bearish")); PatternScore scores; scores.sweep_score = CalculateSweepScore(symbol, is_bullish, m1_data); scores.bos_score = CalculateBOSScore(symbol, is_bullish, m1_data); scores.fvg_score = CalculateFVGScore(symbol, is_bullish, m1_data); scores.ob_score = CalculateOBScore(symbol, is_bullish, m1_data); scores.total_score = scores.sweep_score + scores.bos_score + scores.fvg_score + scores.ob_score; scores.score_breakdown = StringFormat("Sweep=%.1f, BOS=%.1f, FVG=%.1f, OB=%.1f", scores.sweep_score, scores.bos_score, scores.fvg_score, scores.ob_score); double required_score = 50.0; // Require 50% total score instead of 3/4 criteria Print(StringFormat("Pattern Scores: %s, Total=%.1f/100", scores.score_breakdown, scores.total_score)); if (scores.total_score >= required_score) { Print(StringFormat("Score-based confluence met (%.1f >= %.1f) - executing trade", scores.total_score, required_score)); return ExecuteTradeWithScores(symbol, is_bullish, scores, m1_data); } Print(StringFormat("Insufficient confluence score (%.1f < %.1f)", scores.total_score, required_score)); return false; } // Calculate sweep score (0-25 points) double CalculateSweepScore(string symbol, bool is_bullish, MarketStructureData &m1_data) { double score = 0.0; for (int i = 0; i < ArraySize(m1_data.liquidity_sweeps); i++) { bool sweep_direction_match = is_bullish ? !m1_data.liquidity_sweeps[i].is_high_sweep : m1_data.liquidity_sweeps[i].is_high_sweep; if (sweep_direction_match && IsLiquiditySweepValidImproved(symbol, PERIOD_M1, m1_data.liquidity_sweeps[i])) { score = 25.0; // Full points for valid sweep break; } } return score; } // Calculate BOS score (0-25 points) double CalculateBOSScore(string symbol, bool is_bullish, MarketStructureData &m1_data) { double score = 0.0; for (int i = 0; i < ArraySize(m1_data.bos_events); i++) { if (m1_data.bos_events[i].is_bullish == is_bullish && m1_data.bos_events[i].confirmed && IsBOSValidImproved(symbol, PERIOD_M1, m1_data.bos_events[i])) { score = 25.0; // Full points for valid BOS break; } } return score; } // Calculate FVG score (0-25 points) double CalculateFVGScore(string symbol, bool is_bullish, MarketStructureData &m1_data) { double score = 0.0; for (int i = 0; i < ArraySize(m1_data.fair_value_gaps); i++) { if (m1_data.fair_value_gaps[i].is_bullish == is_bullish && IsFVGValid(symbol, PERIOD_M1, m1_data.fair_value_gaps[i])) { score = 25.0; // Full points for valid FVG break; } } return score; } // Calculate OB score (0-25 points) double CalculateOBScore(string symbol, bool is_bullish, MarketStructureData &m1_data) { double score = 0.0; double best_strength = 0.0; for (int i = 0; i < ArraySize(m1_data.order_blocks); i++) { if (m1_data.order_blocks[i].is_bullish == is_bullish && m1_data.order_blocks[i].is_fresh && m1_data.order_blocks[i].strength > best_strength) { best_strength = m1_data.order_blocks[i].strength; } } if (best_strength > 0.0) { score = MathMin(25.0, best_strength * 12.5); // Scale strength to 0-25 points } return score; } // Execute trade with scoring information bool ExecuteTradeWithScores(string symbol, bool is_bullish, PatternScore &scores, MarketStructureData &m1_data) { Print(StringFormat("Executing %s trade for %s with score %.1f (%s)", is_bullish ? "bullish" : "bearish", symbol, scores.total_score, scores.score_breakdown)); // Find best patterns for trade execution OrderBlock best_ob; FairValueGap best_fvg; LiquiditySweep best_sweep; // Get best patterns based on scores if (scores.ob_score > 0) GetBestOrderBlock(symbol, is_bullish, m1_data, best_ob); if (scores.fvg_score > 0) GetBestFVG(symbol, is_bullish, m1_data, best_fvg); if (scores.sweep_score > 0) GetBestSweep(symbol, is_bullish, m1_data, best_sweep); // Execute trade using existing trade execution functions if (is_bullish) { return ExecuteBullishTradeWithFibonacci(symbol, best_ob, best_fvg, best_sweep, FibonacciRetracement()); } else { return ExecuteBearishTradeWithFibonacci(symbol, best_ob, best_fvg, best_sweep, FibonacciRetracement()); } } // Helper functions to get best patterns void GetBestOrderBlock(string symbol, bool is_bullish, MarketStructureData &m1_data, OrderBlock &best_ob) { double best_strength = 0.0; int best_index = -1; for (int i = 0; i < ArraySize(m1_data.order_blocks); i++) { if (m1_data.order_blocks[i].is_bullish == is_bullish && m1_data.order_blocks[i].is_fresh && m1_data.order_blocks[i].strength > best_strength) { best_strength = m1_data.order_blocks[i].strength; best_index = i; } } if (best_index >= 0) best_ob = m1_data.order_blocks[best_index]; } void GetBestFVG(string symbol, bool is_bullish, MarketStructureData &m1_data, FairValueGap &best_fvg) { for (int i = 0; i < ArraySize(m1_data.fair_value_gaps); i++) { if (m1_data.fair_value_gaps[i].is_bullish == is_bullish && IsFVGValid(symbol, PERIOD_M1, m1_data.fair_value_gaps[i])) { best_fvg = m1_data.fair_value_gaps[i]; break; // Take first valid FVG } } } void GetBestSweep(string symbol, bool is_bullish, MarketStructureData &m1_data, LiquiditySweep &best_sweep) { for (int i = 0; i < ArraySize(m1_data.liquidity_sweeps); i++) { bool sweep_direction_match = is_bullish ? !m1_data.liquidity_sweeps[i].is_high_sweep : m1_data.liquidity_sweeps[i].is_high_sweep; if (sweep_direction_match && IsLiquiditySweepValidImproved(symbol, PERIOD_M1, m1_data.liquidity_sweeps[i])) { best_sweep = m1_data.liquidity_sweeps[i]; break; // Take first valid sweep } } }