Complete implementation of all 4 immediate recommendations

 COMPLETED FIXES:

1. Calibrate liquidity sweep detection parameters
   - Reduced MinSweepDistance from 5.0 to 3.0 pips
   - Reduced SwingLookback from 10 to 5 bars
   - Increased equal level tolerance from 2.0 to 3.0 pips
   - Relaxed confirmation criteria from 2x to 0.5x body size
   - Extended search ranges from 20 to 30 bars

2. Debug and fix bias calculation system
   - Fixed circular dependency in bias calculation
   - Allow calculation with limited data instead of failing
   - Improved error handling for invalid data scenarios

3. Review BOS detection algorithm sensitivity
   - Increased analysis range from SwingLookback*3 to SwingLookback*8
   - Extended search ranges from BOSConfirmationCandles*2 to BOSConfirmationCandles*4
   - Relaxed confirmation requirements from 2/3 to 1/3 candles
   - Extended validity period from 3x to 6x confirmation candles
   - Implemented more permissive swing point detection

4. Consider adjusting confluence requirements (allow 3/4 criteria vs. requiring all 4)
   - Added MinConfluenceCount parameter (default: 3)
   - Implemented ValidateFlexibleConfluence() function
   - Modified AnalyzeBullishSetup() and AnalyzeBearishSetup() to use flexible validation
   - Allows trade execution with 3/4 criteria instead of requiring all 4
   - Maintains proper sequence validation (Sweep → BOS → FVG → OB)
   - Includes detailed logging for confluence analysis

🎯 EXPECTED IMPACT:
- Should resolve zero trade execution issue
- More realistic detection parameters for current market conditions
- Flexible confluence system allows trades when 3/4 patterns align
- Maintains risk management while improving signal generation

Ready for testing with optimized parameters and flexible confluence system.
This commit is contained in:
rithsila
2025-09-28 12:07:16 +07:00
parent b76a7c8392
commit 59cd82e022
+267 -318
View File
@@ -49,11 +49,12 @@ input int MaxPositionsPerSymbol = 3; // Maximum positions
input group "=== Pattern Detection ===" input int OBLookback = 20; // Order Block lookback candles
input double MinFVGSize = 3.0; // Minimum FVG size in pips
input double MinSweepDistance = 5.0; // Minimum sweep distance in pips
input double MinSweepDistance = 3.0; // Minimum sweep distance in pips (reduced from 5.0)
input int BOSConfirmationCandles = 3; // BOS confirmation within candles
input int SwingLookback = 10; // Swing high/low lookback period
input int SwingLookback = 5; // Swing high/low lookback period (reduced from 10)
input double OBStrengthFilter = 0.5; // Order Block strength filter (0-1)
input bool RequireMultiTFConfirmation = true; // Require multi-timeframe confirmation
input int MinConfluenceCount = 3; // Minimum confluence criteria required (3/4 instead of 4/4)
input group "=== Fibonacci Settings ===" input bool EnableFibonacci = true; // Enable Fibonacci retracement analysis
input ENUM_FIBONACCI_MODE FibonacciMode = FIBONACCI_AS_FILTER; // Fibonacci integration mode
@@ -380,6 +381,7 @@ double g_fibonacci_percentages[5] = {23.6, 38.2, 50.0, 61.8, 78.6}; // Standard
//--- Function declarations
bool ConfirmBOS(string symbol, ENUM_TIMEFRAMES timeframe, int break_bar, bool is_bullish, double level);
bool ValidateFlexibleConfluence(string symbol, bool is_bullish, MarketStructureData &m1_data);
//--- Phase 4: Advanced Risk Management Function Declarations
bool InitializePhase4RiskManagement();
@@ -1798,303 +1800,28 @@ bool AnalyzeBullishSetup(string symbol)
ArraySize(m1_data.order_blocks), ArraySize(m1_data.fair_value_gaps),
ArraySize(m1_data.bos_events), ArraySize(m1_data.liquidity_sweeps)));
// Step 1: Find valid liquidity sweep (low sweep for bullish setup)
LogDebug(StringFormat("Step 1: Looking for valid low sweep (total sweeps: %d)", ArraySize(m1_data.liquidity_sweeps)));
LiquiditySweep valid_sweep;
bool sweep_found = false;
for (int i = 0; i < ArraySize(m1_data.liquidity_sweeps); i++)
{
LogDebug(StringFormat("Checking sweep %d: is_high_sweep=%s, confirmed=%s",
i, m1_data.liquidity_sweeps[i].is_high_sweep ? "true" : "false",
m1_data.liquidity_sweeps[i].confirmed ? "true" : "false"));
if (!m1_data.liquidity_sweeps[i].is_high_sweep &&
IsLiquiditySweepValid(symbol, PERIOD_M1, m1_data.liquidity_sweeps[i]))
{
valid_sweep = m1_data.liquidity_sweeps[i];
sweep_found = true;
LogDebug(StringFormat("Valid low sweep found at level %.5f", valid_sweep.level));
break;
}
}
if (!sweep_found)
{
LogDebug(StringFormat("BLOCKING CONDITION: No valid low sweep found for bullish setup on %s", symbol));
return false;
}
// Step 2: Find opposite direction BOS (bullish BOS after low sweep)
BreakOfStructure valid_bos;
bool bos_found = false;
for (int i = 0; i < ArraySize(m1_data.bos_events); i++)
{
if (m1_data.bos_events[i].is_bullish &&
m1_data.bos_events[i].confirmed &&
m1_data.bos_events[i].time > valid_sweep.time) // BOS must be after sweep
{
valid_bos = m1_data.bos_events[i];
bos_found = true;
break;
}
}
if (!bos_found)
{
LogDebug(StringFormat("No valid bullish BOS found after low sweep on %s", symbol));
return false;
}
// Step 3: Find valid FVG between BOS and current price
FairValueGap valid_fvg;
bool fvg_found = false;
for (int i = 0; i < ArraySize(m1_data.fair_value_gaps); i++)
{
if (m1_data.fair_value_gaps[i].is_bullish &&
IsFVGValid(symbol, PERIOD_M1, m1_data.fair_value_gaps[i]) &&
m1_data.fair_value_gaps[i].time > valid_bos.time) // FVG must be after BOS
{
valid_fvg = m1_data.fair_value_gaps[i];
fvg_found = true;
break;
}
}
if (!fvg_found)
{
LogDebug(StringFormat("No valid bullish FVG found after BOS on %s", symbol));
return false;
}
// Step 4: Find fresh bullish Order Block
OrderBlock valid_ob;
bool ob_found = false;
for (int i = 0; i < ArraySize(m1_data.order_blocks); i++)
{
if (m1_data.order_blocks[i].is_bullish &&
m1_data.order_blocks[i].is_fresh &&
m1_data.order_blocks[i].strength >= OBStrengthFilter &&
m1_data.order_blocks[i].time > valid_fvg.time) // OB must be after FVG
{
valid_ob = m1_data.order_blocks[i];
ob_found = true;
break;
}
}
if (!ob_found)
{
LogDebug(StringFormat("No valid fresh bullish OB found after FVG on %s", symbol));
return false;
}
// Step 5: Fibonacci validation (if enabled)
FibonacciRetracement valid_fibonacci;
bool fibonacci_valid = false;
if (EnableFibonacci)
{
LogDebug("Step 5: Checking Fibonacci validation for bullish setup");
// Find a suitable Fibonacci retracement for this setup
for (int i = 0; i < ArraySize(g_fibonacci_retracements); i++)
{
if (ValidateFibonacciSetup(symbol, true, g_fibonacci_retracements[i]))
{
valid_fibonacci = g_fibonacci_retracements[i];
fibonacci_valid = true;
LogDebug(StringFormat("Valid Fibonacci retracement found: %.5f to %.5f",
valid_fibonacci.swing_high, valid_fibonacci.swing_low));
break;
}
}
// Apply mode-based validation logic
if (!ShouldTakeTradeBasedOnMode(symbol, true, valid_ob, valid_fvg, valid_sweep,
fibonacci_valid ? valid_fibonacci : FibonacciRetracement(),
fibonacci_valid))
{
LogDebug(StringFormat("BLOCKING CONDITION: Mode-based validation failed for %s", symbol));
return false;
}
}
// Step 6: Check multi-timeframe alignment
if (RequireMultiTFConfirmation)
{
if (!IsMultiTimeframeAligned(symbol, true))
{
LogDebug(StringFormat("Multi-timeframe not aligned for bullish setup on %s", symbol));
return false;
}
}
// Step 7: Execute bullish trade
// Phase 5: Record pattern signal detection with Fibonacci info
string pattern_name = "OB+BOS+FVG+Sweep_Bullish";
if (EnableFibonacci && fibonacci_valid)
{
pattern_name = "OB+BOS+FVG+Sweep+Fib_Bullish";
}
RecordPatternSignal(pattern_name, true);
return ExecuteBullishTradeWithFibonacci(symbol, valid_ob, valid_fvg, valid_sweep,
fibonacci_valid ? valid_fibonacci : FibonacciRetracement());
// CRITICAL FIX: Use flexible confluence validation instead of requiring all 4 criteria
return ValidateFlexibleConfluence(symbol, true, m1_data);
}
bool AnalyzeBearishSetup(string symbol)
{
LogDebug(StringFormat("=== Analyzing Bearish Setup for %s ===", symbol));
// Get M1 timeframe data
MarketStructureData m1_data;
if (!GetTimeframeData(PERIOD_M1, m1_data) || !m1_data.is_valid)
{
LogDebug(StringFormat("M1 data not available or invalid for %s", symbol));
return false;
}
// Step 1: Find valid liquidity sweep (high sweep for bearish setup)
LiquiditySweep valid_sweep;
bool sweep_found = false;
LogDebug(StringFormat("M1 data available: OB=%d, FVG=%d, BOS=%d, Sweeps=%d",
ArraySize(m1_data.order_blocks), ArraySize(m1_data.fair_value_gaps),
ArraySize(m1_data.bos_events), ArraySize(m1_data.liquidity_sweeps)));
for (int i = 0; i < ArraySize(m1_data.liquidity_sweeps); i++)
{
if (m1_data.liquidity_sweeps[i].is_high_sweep &&
IsLiquiditySweepValid(symbol, PERIOD_M1, m1_data.liquidity_sweeps[i]))
{
valid_sweep = m1_data.liquidity_sweeps[i];
sweep_found = true;
break;
}
}
if (!sweep_found)
{
LogDebug(StringFormat("No valid high sweep found for bearish setup on %s", symbol));
return false;
}
// Step 2: Find opposite direction BOS (bearish BOS after high sweep)
BreakOfStructure valid_bos;
bool bos_found = false;
for (int i = 0; i < ArraySize(m1_data.bos_events); i++)
{
if (!m1_data.bos_events[i].is_bullish &&
m1_data.bos_events[i].confirmed &&
m1_data.bos_events[i].time > valid_sweep.time) // BOS must be after sweep
{
valid_bos = m1_data.bos_events[i];
bos_found = true;
break;
}
}
if (!bos_found)
{
LogDebug(StringFormat("No valid bearish BOS found after high sweep on %s", symbol));
return false;
}
// Step 3: Find valid FVG between BOS and current price
FairValueGap valid_fvg;
bool fvg_found = false;
for (int i = 0; i < ArraySize(m1_data.fair_value_gaps); i++)
{
if (!m1_data.fair_value_gaps[i].is_bullish &&
IsFVGValid(symbol, PERIOD_M1, m1_data.fair_value_gaps[i]) &&
m1_data.fair_value_gaps[i].time > valid_bos.time) // FVG must be after BOS
{
valid_fvg = m1_data.fair_value_gaps[i];
fvg_found = true;
break;
}
}
if (!fvg_found)
{
LogDebug(StringFormat("No valid bearish FVG found after BOS on %s", symbol));
return false;
}
// Step 4: Find fresh bearish Order Block
OrderBlock valid_ob;
bool ob_found = false;
for (int i = 0; i < ArraySize(m1_data.order_blocks); i++)
{
if (!m1_data.order_blocks[i].is_bullish &&
m1_data.order_blocks[i].is_fresh &&
m1_data.order_blocks[i].strength >= OBStrengthFilter &&
m1_data.order_blocks[i].time > valid_fvg.time) // OB must be after FVG
{
valid_ob = m1_data.order_blocks[i];
ob_found = true;
break;
}
}
if (!ob_found)
{
LogDebug(StringFormat("No valid fresh bearish OB found after FVG on %s", symbol));
return false;
}
// Step 5: Fibonacci validation (if enabled)
FibonacciRetracement valid_fibonacci;
bool fibonacci_valid = false;
if (EnableFibonacci)
{
LogDebug("Step 5: Checking Fibonacci validation for bearish setup");
// Find a suitable Fibonacci retracement for this setup
for (int i = 0; i < ArraySize(g_fibonacci_retracements); i++)
{
if (ValidateFibonacciSetup(symbol, false, g_fibonacci_retracements[i]))
{
valid_fibonacci = g_fibonacci_retracements[i];
fibonacci_valid = true;
LogDebug(StringFormat("Valid Fibonacci retracement found: %.5f to %.5f",
valid_fibonacci.swing_high, valid_fibonacci.swing_low));
break;
}
}
// Apply mode-based validation logic
if (!ShouldTakeTradeBasedOnMode(symbol, false, valid_ob, valid_fvg, valid_sweep,
fibonacci_valid ? valid_fibonacci : FibonacciRetracement(),
fibonacci_valid))
{
LogDebug(StringFormat("BLOCKING CONDITION: Mode-based validation failed for %s", symbol));
return false;
}
}
// Step 6: Check multi-timeframe alignment
if (RequireMultiTFConfirmation)
{
if (!IsMultiTimeframeAligned(symbol, false))
{
LogDebug(StringFormat("Multi-timeframe not aligned for bearish setup on %s", symbol));
return false;
}
}
// Step 7: Execute bearish trade
// Phase 5: Record pattern signal detection with Fibonacci info
string pattern_name = "OB+BOS+FVG+Sweep_Bearish";
if (EnableFibonacci && fibonacci_valid)
{
pattern_name = "OB+BOS+FVG+Sweep+Fib_Bearish";
}
RecordPatternSignal(pattern_name, true);
return ExecuteBearishTradeWithFibonacci(symbol, valid_ob, valid_fvg, valid_sweep,
fibonacci_valid ? valid_fibonacci : FibonacciRetracement());
// CRITICAL FIX: Use flexible confluence validation instead of requiring all 4 criteria
return ValidateFlexibleConfluence(symbol, false, m1_data);
}
//+------------------------------------------------------------------+
@@ -3147,7 +2874,7 @@ bool DetectBreakOfStructure(string symbol, ENUM_TIMEFRAMES timeframe, BreakOfStr
{
ArrayResize(bos_events, 0);
int bars_to_analyze = MathMin(SwingLookback * 3, iBars(symbol, timeframe) - 10);
int bars_to_analyze = MathMin(SwingLookback * 8, iBars(symbol, timeframe) - 10); // Increased from 3x to 8x
if (bars_to_analyze < 20)
return false;
@@ -3183,17 +2910,19 @@ void FindSwingPoints(string symbol, ENUM_TIMEFRAMES timeframe, int bars_to_analy
double current_low = iLow(symbol, timeframe, i);
datetime current_time = iTime(symbol, timeframe, i);
// Check for swing high
// Check for swing high (relaxed criteria - allow equal highs)
bool is_swing_high = true;
int higher_count = 0;
for (int j = 1; j <= SwingLookback; j++)
{
if (iHigh(symbol, timeframe, i - j) >= current_high ||
iHigh(symbol, timeframe, i + j) >= current_high)
if (iHigh(symbol, timeframe, i - j) > current_high ||
iHigh(symbol, timeframe, i + j) > current_high)
{
is_swing_high = false;
break;
higher_count++;
}
}
// Allow swing high if less than 2 bars are higher (more permissive)
is_swing_high = (higher_count < 2);
if (is_swing_high)
{
@@ -3203,17 +2932,19 @@ void FindSwingPoints(string symbol, ENUM_TIMEFRAMES timeframe, int bars_to_analy
swing_high_times[ArraySize(swing_high_times) - 1] = current_time;
}
// Check for swing low
// Check for swing low (relaxed criteria - allow equal lows)
bool is_swing_low = true;
int lower_count = 0;
for (int j = 1; j <= SwingLookback; j++)
{
if (iLow(symbol, timeframe, i - j) <= current_low ||
iLow(symbol, timeframe, i + j) <= current_low)
if (iLow(symbol, timeframe, i - j) < current_low ||
iLow(symbol, timeframe, i + j) < current_low)
{
is_swing_low = false;
break;
lower_count++;
}
}
// Allow swing low if less than 2 bars are lower (more permissive)
is_swing_low = (lower_count < 2);
if (is_swing_low)
{
@@ -3241,7 +2972,7 @@ void AnalyzeBOSPatterns(string symbol, ENUM_TIMEFRAMES timeframe,
if (start_bar < 0)
continue;
for (int j = 0; j < start_bar && j < BOSConfirmationCandles * 2; j++)
for (int j = 0; j < start_bar && j < BOSConfirmationCandles * 4; j++) // Increased search range
{
double current_high = iHigh(symbol, timeframe, j);
double current_close = iClose(symbol, timeframe, j);
@@ -3281,7 +3012,7 @@ void AnalyzeBOSPatterns(string symbol, ENUM_TIMEFRAMES timeframe,
if (start_bar < 0)
continue;
for (int j = 0; j < start_bar && j < BOSConfirmationCandles * 2; j++)
for (int j = 0; j < start_bar && j < BOSConfirmationCandles * 4; j++) // Increased search range
{
double current_low = iLow(symbol, timeframe, j);
double current_close = iClose(symbol, timeframe, j);
@@ -3332,8 +3063,8 @@ bool ConfirmBOS(string symbol, ENUM_TIMEFRAMES timeframe, int break_bar, bool is
}
}
// Require at least 2 out of 3 confirmation candles
return confirmation_count >= MathMax(2, BOSConfirmationCandles / 2);
// Require at least 1 out of 3 confirmation candles (relaxed from 2)
return confirmation_count >= MathMax(1, BOSConfirmationCandles / 3);
}
bool IsBOSValid(string symbol, ENUM_TIMEFRAMES timeframe, BreakOfStructure &bos)
@@ -3342,7 +3073,7 @@ bool IsBOSValid(string symbol, ENUM_TIMEFRAMES timeframe, BreakOfStructure &bos)
datetime current_time = iTime(symbol, timeframe, 0);
int time_diff = (int)((current_time - bos.time) / PeriodSeconds(timeframe));
if (time_diff > BOSConfirmationCandles * 3)
if (time_diff > BOSConfirmationCandles * 6) // Increased validity period from 3x to 6x
return false;
// Check if price is still respecting the BOS level
@@ -3558,8 +3289,8 @@ bool DetectLiquiditySweeps(string symbol, ENUM_TIMEFRAMES timeframe, LiquiditySw
if (equal_bar < 0)
continue;
// Look for sweep above this equal high
for (int j = 0; j < equal_bar && j < 20; j++)
// Look for sweep above this equal high (increased search range)
for (int j = 0; j < equal_bar && j < 30; j++)
{
double current_high = iHigh(symbol, timeframe, j);
double current_close = iClose(symbol, timeframe, j);
@@ -3600,8 +3331,8 @@ bool DetectLiquiditySweeps(string symbol, ENUM_TIMEFRAMES timeframe, LiquiditySw
if (equal_bar < 0)
continue;
// Look for sweep below this equal low
for (int j = 0; j < equal_bar && j < 20; j++)
// Look for sweep below this equal low (increased search range)
for (int j = 0; j < equal_bar && j < 30; j++)
{
double current_low = iLow(symbol, timeframe, j);
double current_close = iClose(symbol, timeframe, j);
@@ -3646,7 +3377,7 @@ void FindEqualHighsLows(string symbol, ENUM_TIMEFRAMES timeframe, int bars_to_an
ArrayResize(equal_low_times, 0);
double pip_value = CalculatePipValue(symbol);
double tolerance = 2.0 * pip_value; // 2 pip tolerance for "equal" levels
double tolerance = 3.0 * pip_value; // 3 pip tolerance for "equal" levels (increased from 2.0)
// Find swing points first
double swing_highs[];
@@ -3750,8 +3481,8 @@ bool ConfirmLiquiditySweep(string symbol, ENUM_TIMEFRAMES timeframe, int sweep_b
double wick_size = sweep_high - sweep_close;
double body_size = MathAbs(iClose(symbol, timeframe, sweep_bar) - iOpen(symbol, timeframe, sweep_bar));
// Wick should be at least 2x the body size
if (wick_size < body_size * 2)
// Wick should be at least 0.5x the body size (relaxed from 2x)
if (wick_size < body_size * 0.5)
return false;
// Close should be below the swept level
@@ -3764,8 +3495,8 @@ bool ConfirmLiquiditySweep(string symbol, ENUM_TIMEFRAMES timeframe, int sweep_b
double wick_size = sweep_close - sweep_low;
double body_size = MathAbs(iClose(symbol, timeframe, sweep_bar) - iOpen(symbol, timeframe, sweep_bar));
// Wick should be at least 2x the body size
if (wick_size < body_size * 2)
// Wick should be at least 0.5x the body size (relaxed from 2x)
if (wick_size < body_size * 0.5)
return false;
// Close should be above the swept level
@@ -3946,9 +3677,13 @@ bool UpdateTimeframeData(string symbol, MarketStructureData &mtf_data)
bool bos_success = DetectBreakOfStructure(symbol, mtf_data.timeframe, mtf_data.bos_events);
bool sweep_success = DetectLiquiditySweeps(symbol, mtf_data.timeframe, mtf_data.liquidity_sweeps);
// Consider update successful if at least pattern detection worked
// Consider update successful if at least pattern detection worked OR if we have sufficient bars
bool patterns_success = ob_success || fvg_success || bos_success || sweep_success;
// CRITICAL FIX: Allow timeframe to be valid even if no patterns detected, as long as we have data
bool has_sufficient_data = iBars(symbol, mtf_data.timeframe) >= 50;
bool update_success = patterns_success || has_sufficient_data;
// Phase 2: Update enhanced multi-timeframe data (always attempt, don't fail on bias calc issues)
// Calculate bias strength for this timeframe (don't fail if this doesn't work)
mtf_data.current_bias = CalculateBiasStrength(symbol, mtf_data.timeframe);
@@ -3981,9 +3716,9 @@ bool UpdateTimeframeData(string symbol, MarketStructureData &mtf_data)
// Update metadata
mtf_data.last_update = iTime(symbol, mtf_data.timeframe, 0);
mtf_data.is_valid = patterns_success;
mtf_data.is_valid = update_success; // Use the improved success criteria
if (patterns_success)
if (update_success)
{
LogDebug(StringFormat("%s analysis completed: OB=%d, FVG=%d, BOS=%d, Sweeps=%d, Bias=%.1f%% (%s), Phase=%s",
EnumToString(mtf_data.timeframe),
@@ -4002,7 +3737,7 @@ bool UpdateTimeframeData(string symbol, MarketStructureData &mtf_data)
}
}
return patterns_success;
return update_success;
}
void DrawPatternsOnChart(string symbol, MarketStructureData &mtf_data)
@@ -4345,13 +4080,21 @@ BiasStrength CalculateBiasStrength(string symbol, ENUM_TIMEFRAMES timeframe)
bias.pattern_score = 0.0;
MarketStructureData mtf_data;
if (!GetTimeframeData(timeframe, mtf_data) || !mtf_data.is_valid)
if (!GetTimeframeData(timeframe, mtf_data))
{
LogDebug(StringFormat("Cannot calculate bias strength - invalid data for %s %s",
LogDebug(StringFormat("Cannot calculate bias strength - no data available for %s %s",
symbol, EnumToString(timeframe)));
return bias;
}
// CRITICAL FIX: Allow bias calculation even if mtf_data.is_valid is false
// This prevents circular dependency where bias calc needs valid data but data validity depends on patterns
if (!mtf_data.is_valid)
{
LogDebug(StringFormat("Calculating bias with limited data for %s %s (patterns may be incomplete)",
symbol, EnumToString(timeframe)));
}
// Calculate BOS Score (0-40 points)
bias.bos_score = CalculateBOSScore(mtf_data.bos_events);
@@ -7432,3 +7175,209 @@ void LogFibonacciAnalysisStatus(string symbol)
TimeToString(fib.created_time)));
}
}
//+------------------------------------------------------------------+
//| Flexible Confluence Validation System |
//+------------------------------------------------------------------+
bool ValidateFlexibleConfluence(string symbol, bool is_bullish, MarketStructureData &m1_data)
{
LogDebug(StringFormat("=== Flexible Confluence Validation for %s %s Setup ===",
symbol, is_bullish ? "Bullish" : "Bearish"));
int confluence_count = 0;
string confluence_details = "";
// Criterion 1: Valid Liquidity Sweep
bool sweep_valid = false;
LiquiditySweep valid_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 && IsLiquiditySweepValid(symbol, PERIOD_M1, m1_data.liquidity_sweeps[i]))
{
valid_sweep = m1_data.liquidity_sweeps[i];
sweep_valid = true;
confluence_count++;
confluence_details += "✓ Liquidity Sweep ";
LogDebug(StringFormat("✓ Valid %s sweep found at %.5f",
is_bullish ? "low" : "high", valid_sweep.level));
break;
}
}
if (!sweep_valid)
{
confluence_details += "✗ Liquidity Sweep ";
LogDebug(StringFormat("✗ No valid %s sweep found", is_bullish ? "low" : "high"));
}
// Criterion 2: Valid Break of Structure
bool bos_valid = false;
BreakOfStructure valid_bos;
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 &&
IsBOSValid(symbol, PERIOD_M1, m1_data.bos_events[i]))
{
// If we have a sweep, BOS should be after sweep
if (sweep_valid && m1_data.bos_events[i].time <= valid_sweep.time)
continue;
valid_bos = m1_data.bos_events[i];
bos_valid = true;
confluence_count++;
confluence_details += "✓ Break of Structure ";
LogDebug(StringFormat("✓ Valid %s BOS found at %.5f",
is_bullish ? "bullish" : "bearish", valid_bos.level));
break;
}
}
if (!bos_valid)
{
confluence_details += "✗ Break of Structure ";
LogDebug(StringFormat("✗ No valid %s BOS found", is_bullish ? "bullish" : "bearish"));
}
// Criterion 3: Valid Fair Value Gap
bool fvg_valid = false;
FairValueGap valid_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]))
{
// If we have BOS, FVG should be after BOS
if (bos_valid && m1_data.fair_value_gaps[i].time <= valid_bos.time)
continue;
valid_fvg = m1_data.fair_value_gaps[i];
fvg_valid = true;
confluence_count++;
confluence_details += "✓ Fair Value Gap ";
LogDebug(StringFormat("✓ Valid %s FVG found: %.5f-%.5f",
is_bullish ? "bullish" : "bearish", valid_fvg.bottom, valid_fvg.top));
break;
}
}
if (!fvg_valid)
{
confluence_details += "✗ Fair Value Gap ";
LogDebug(StringFormat("✗ No valid %s FVG found", is_bullish ? "bullish" : "bearish"));
}
// Criterion 4: Valid Order Block
bool ob_valid = false;
OrderBlock valid_ob;
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 >= OBStrengthFilter)
{
// If we have FVG, OB should be after FVG
if (fvg_valid && m1_data.order_blocks[i].time <= valid_fvg.time)
continue;
valid_ob = m1_data.order_blocks[i];
ob_valid = true;
confluence_count++;
confluence_details += "✓ Order Block ";
LogDebug(StringFormat("✓ Valid %s OB found: %.5f-%.5f (strength: %.2f)",
is_bullish ? "bullish" : "bearish", valid_ob.low, valid_ob.high, valid_ob.strength));
break;
}
}
if (!ob_valid)
{
confluence_details += "✗ Order Block ";
LogDebug(StringFormat("✗ No valid %s OB found", is_bullish ? "bullish" : "bearish"));
}
// Check if we meet minimum confluence requirements
bool confluence_met = confluence_count >= MinConfluenceCount;
LogDebug(StringFormat("Confluence Summary: %d/4 criteria met (%s)", confluence_count, confluence_details));
LogDebug(StringFormat("Minimum required: %d/4 - Result: %s", MinConfluenceCount, confluence_met ? "PASS" : "FAIL"));
if (!confluence_met)
{
LogDebug(StringFormat("BLOCKING CONDITION: Insufficient confluence (%d/%d) for %s setup on %s",
confluence_count, MinConfluenceCount, is_bullish ? "bullish" : "bearish", symbol));
return false;
}
// Additional validations if confluence is met
// Multi-timeframe alignment check
if (RequireMultiTFConfirmation)
{
if (!IsMultiTimeframeAligned(symbol, is_bullish))
{
LogDebug(StringFormat("Multi-timeframe not aligned for %s setup on %s",
is_bullish ? "bullish" : "bearish", symbol));
return false;
}
}
// Fibonacci validation (if enabled)
FibonacciRetracement valid_fibonacci;
bool fibonacci_valid = false;
if (EnableFibonacci)
{
LogDebug("Checking Fibonacci validation for setup");
for (int i = 0; i < ArraySize(g_fibonacci_retracements); i++)
{
if (ValidateFibonacciSetup(symbol, is_bullish, g_fibonacci_retracements[i]))
{
valid_fibonacci = g_fibonacci_retracements[i];
fibonacci_valid = true;
LogDebug(StringFormat("Valid Fibonacci retracement found: %.5f to %.5f",
valid_fibonacci.swing_high, valid_fibonacci.swing_low));
break;
}
}
// Apply mode-based validation logic
if (!ShouldTakeTradeBasedOnMode(symbol, is_bullish, valid_ob, valid_fvg, valid_sweep,
fibonacci_valid ? valid_fibonacci : FibonacciRetracement(),
fibonacci_valid))
{
LogDebug(StringFormat("BLOCKING CONDITION: Mode-based validation failed for %s", symbol));
return false;
}
}
// Execute trade if all validations pass
LogDebug(StringFormat("All validations passed - executing %s trade", is_bullish ? "bullish" : "bearish"));
// Record pattern signal detection
string pattern_name = StringFormat("Flexible_%d_of_4_%s", confluence_count, is_bullish ? "Bullish" : "Bearish");
if (EnableFibonacci && fibonacci_valid)
{
pattern_name += "_Fib";
}
RecordPatternSignal(pattern_name, true);
// Execute the trade
if (is_bullish)
{
return ExecuteBullishTradeWithFibonacci(symbol, valid_ob, valid_fvg, valid_sweep,
fibonacci_valid ? valid_fibonacci : FibonacciRetracement());
}
else
{
return ExecuteBearishTradeWithFibonacci(symbol, valid_ob, valid_fvg, valid_sweep,
fibonacci_valid ? valid_fibonacci : FibonacciRetracement());
}
}