mirror of
https://github.com/rithsila/MT5-EA-Sniper-Strategy.git
synced 2026-08-25 16:48:13 +00:00
Remove tests directory from git tracking and update .gitignore
- Added tests/, Tests/, TESTS/ to .gitignore - Removed tests directory from git tracking while keeping it locally - Tests directory contains logs, validation reports, and temporary test files - This prevents test artifacts from being committed to the repository
This commit is contained in:
@@ -0,0 +1,713 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user