//+------------------------------------------------------------------+ //| SignalCoordinator.mqh | //| Smart Signal Coordination & Conflict Prevention | //| Coordinates: MA, MFIB, FIB, Stoch, Candlesticks | //| Prevents conflicting trades within 5-min timeframes | //| Balances BULL/BEAR signals across all modes and states | //+------------------------------------------------------------------+ //================ SIGNAL STRUCTURES ==================// struct CoordinatedSignal { string source; // "ma", "mfib", "fib", "stoch", "candle" string action; // "reject", "reclaim", "break" string direction; // "bullish" or "bearish" string signal_type; // "WARN" or "PRAISE" double strength; // 0-100 string location; // Where it happened datetime timestamp; // When it happened double price; // At what price bool at_key_level; // True if at MFIB/FIB/major MA }; struct SignalCluster { CoordinatedSignal signals[20]; // Max 20 signals in cluster int count; string consensus_direction; // "bullish", "bearish", "neutral" string consensus_type; // "WARN" or "PRAISE" double combined_strength; double conflict_score; // 0-100 datetime cluster_time; }; //================ GLOBAL COORDINATOR STATE ==================// CoordinatedSignal SignalHistory[100]; int SignalHistoryCount = 0; SignalCluster CurrentCluster; datetime LastClusterTime = 0; // Signal balance tracking int BullWarnCount = 0; int BullPraiseCount = 0; int BearWarnCount = 0; int BearPraiseCount = 0; // Conflict prevention datetime LastTradeTime = 0; string LastTradeDirection = ""; int ConflictPreventionSeconds = 300; // 5 minutes //================ SIGNAL COORDINATOR FUNCTIONS ==================// //+------------------------------------------------------------------+ //| Initialize Signal Coordinator | //+------------------------------------------------------------------+ void InitializeSignalCoordinator() { ArrayInitialize(SignalHistory, 0); SignalHistoryCount = 0; CurrentCluster.count = 0; BullWarnCount = 0; BullPraiseCount = 0; BearWarnCount = 0; BearPraiseCount = 0; Print("✅ Signal Coordinator initialized"); } //+------------------------------------------------------------------+ //| Add Signal to Coordinator | //+------------------------------------------------------------------+ bool AddCoordinatedSignal(string source, string action, string direction, string signal_type, double strength, string location, double price, bool at_key_level) { // Create signal CoordinatedSignal signal; signal.source = source; signal.action = action; signal.direction = direction; signal.signal_type = signal_type; signal.strength = strength; signal.location = location; signal.timestamp = TimeCurrent(); signal.price = price; signal.at_key_level = at_key_level; // Check for conflicts if(HasConflict(signal)) { Print("⚠️ Signal REJECTED due to conflict: ", signal.source, " ", signal.direction, " ", signal.signal_type); return false; } // Add to history if(SignalHistoryCount < ArraySize(SignalHistory)) { SignalHistory[SignalHistoryCount] = signal; SignalHistoryCount++; } // Add to current cluster if(CurrentCluster.count < ArraySize(CurrentCluster.signals)) { CurrentCluster.signals[CurrentCluster.count] = signal; CurrentCluster.count++; } // Update balance counters UpdateBalanceCounters(signal); Print("✅ Signal ADDED: ", signal.source, " ", signal.action, " at ", signal.location, " - ", signal.direction, " ", signal.signal_type); return true; } //+------------------------------------------------------------------+ //| Check for Signal Conflicts (within 5 min window) | //+------------------------------------------------------------------+ bool HasConflict(CoordinatedSignal &new_signal) { datetime current_time = TimeCurrent(); // Check recent signals (last 5 minutes) for(int i = SignalHistoryCount - 1; i >= 0 && i >= SignalHistoryCount - 20; i--) { if(current_time - SignalHistory[i].timestamp > ConflictPreventionSeconds) break; // Same source within 1 minute = skip (duplicate) if(SignalHistory[i].source == new_signal.source && current_time - SignalHistory[i].timestamp < 60) { return true; } // Opposite direction with strong signal = conflict if(SignalHistory[i].direction != new_signal.direction && SignalHistory[i].strength >= 70 && new_signal.strength >= 70) { Print("⚠️ CONFLICT: Strong ", SignalHistory[i].direction, " vs ", new_signal.direction, " within 5 min"); return true; } } return false; } //+------------------------------------------------------------------+ //| Update Balance Counters | //+------------------------------------------------------------------+ void UpdateBalanceCounters(CoordinatedSignal &signal) { if(signal.direction == "bullish" && signal.signal_type == "WARN") BullWarnCount++; else if(signal.direction == "bullish" && signal.signal_type == "PRAISE") BullPraiseCount++; else if(signal.direction == "bearish" && signal.signal_type == "WARN") BearWarnCount++; else if(signal.direction == "bearish" && signal.signal_type == "PRAISE") BearPraiseCount++; } //+------------------------------------------------------------------+ //| Generate Signals from Moving Averages (BALANCED) | //+------------------------------------------------------------------+ void GenerateMASignals() { double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); // BULLISH MA SIGNALS // Price above MA20 = PRAISE (bullish continuation) if(current_price > MA_20_Value) { AddCoordinatedSignal("ma", "reclaim", "bullish", "PRAISE", 65, "ma_20", current_price, false); } // Price reclaims MA50 = WARN (potential bounce) if(current_price > MA_50_Value && SymbolInfoDouble(_Symbol, SYMBOL_BID) < MA_50_Value) { AddCoordinatedSignal("ma", "reclaim", "bullish", "WARN", 70, "ma_50", MA_50_Value, true); } // Price above MA140 = PRAISE (strong trend continuation) if(current_price > MA_140_Value) { AddCoordinatedSignal("ma", "reclaim", "bullish", "PRAISE", 75, "ma_140", current_price, true); } // Price above MA230 = PRAISE (major trend) if(current_price > MA_230_Value) { AddCoordinatedSignal("ma", "reclaim", "bullish", "PRAISE", 80, "ma_230", current_price, true); } // BEARISH MA SIGNALS // Price below MA20 = PRAISE (bearish continuation) if(current_price < MA_20_Value) { AddCoordinatedSignal("ma", "break", "bearish", "PRAISE", 65, "ma_20", current_price, false); } // Price rejects MA50 = WARN (potential rejection) if(current_price < MA_50_Value && SymbolInfoDouble(_Symbol, SYMBOL_ASK) > MA_50_Value) { AddCoordinatedSignal("ma", "reject", "bearish", "WARN", 70, "ma_50", MA_50_Value, true); } // Price below MA140 = PRAISE (strong bearish trend) if(current_price < MA_140_Value) { AddCoordinatedSignal("ma", "break", "bearish", "PRAISE", 75, "ma_140", current_price, true); } } //+------------------------------------------------------------------+ //| Generate Signals from MFIB Levels (BALANCED) | //+------------------------------------------------------------------+ void GenerateMFIBSignals() { double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); double tolerance = SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 50; static double prev_price = 0; if(prev_price == 0) prev_price = current_price; // Check each MFIB level // MFIB 0.236 (Support) if(MathAbs(current_price - MFIB_236) < tolerance) { if(prev_price < MFIB_236 && current_price >= MFIB_236) { // Reclaim = PRAISE (bullish continuation) AddCoordinatedSignal("mfib", "reclaim", "bullish", "PRAISE", 85, "mfib_236", MFIB_236, true); } else if(prev_price > MFIB_236 && current_price <= MFIB_236) { // At support = WARN (potential bounce) AddCoordinatedSignal("mfib", "reject", "bullish", "WARN", 90, "mfib_236", MFIB_236, true); } } // MFIB 0.382 (Support) if(MathAbs(current_price - MFIB_382) < tolerance) { if(prev_price < MFIB_382 && current_price >= MFIB_382) { AddCoordinatedSignal("mfib", "reclaim", "bullish", "PRAISE", 85, "mfib_382", MFIB_382, true); } else if(prev_price > MFIB_382) { AddCoordinatedSignal("mfib", "reject", "bullish", "WARN", 90, "mfib_382", MFIB_382, true); } } // MFIB 0.618 (Resistance) if(MathAbs(current_price - MFIB_618) < tolerance) { if(prev_price < MFIB_618) { // At resistance = WARN (potential rejection) AddCoordinatedSignal("mfib", "reject", "bearish", "WARN", 90, "mfib_618", MFIB_618, true); } else if(prev_price > MFIB_618 && current_price <= MFIB_618) { // Break below = PRAISE (bearish continuation) AddCoordinatedSignal("mfib", "break", "bearish", "PRAISE", 85, "mfib_618", MFIB_618, true); } } // MFIB 0.786 (Resistance) if(MathAbs(current_price - MFIB_786) < tolerance) { if(prev_price < MFIB_786) { AddCoordinatedSignal("mfib", "reject", "bearish", "WARN", 90, "mfib_786", MFIB_786, true); } else if(prev_price > MFIB_786 && current_price <= MFIB_786) { AddCoordinatedSignal("mfib", "break", "bearish", "PRAISE", 85, "mfib_786", MFIB_786, true); } } prev_price = current_price; } //+------------------------------------------------------------------+ //| Generate Signals from Regular FIB Levels (BALANCED) | //+------------------------------------------------------------------+ void GenerateFIBSignals() { double current_price = SymbolInfoDouble(_Symbol, SYMBOL_BID); double tolerance = SymbolInfoDouble(_Symbol, SYMBOL_POINT) * 50; static double prev_fib_price = 0; if(prev_fib_price == 0) prev_fib_price = current_price; // Similar to MFIB but with slightly lower strength values // 0.236, 0.382 = Support levels // 0.618, 0.786 = Resistance levels // FIB 0.236 if(MathAbs(current_price - FIB_236) < tolerance) { if(prev_fib_price < FIB_236 && current_price >= FIB_236) AddCoordinatedSignal("fib", "reclaim", "bullish", "PRAISE", 75, "fib_236", FIB_236, true); else if(prev_fib_price > FIB_236) AddCoordinatedSignal("fib", "reject", "bullish", "WARN", 80, "fib_236", FIB_236, true); } // FIB 0.618 if(MathAbs(current_price - FIB_618) < tolerance) { if(prev_fib_price < FIB_618) AddCoordinatedSignal("fib", "reject", "bearish", "WARN", 80, "fib_618", FIB_618, true); else if(prev_fib_price > FIB_618 && current_price <= FIB_618) AddCoordinatedSignal("fib", "break", "bearish", "PRAISE", 75, "fib_618", FIB_618, true); } prev_fib_price = current_price; } //+------------------------------------------------------------------+ //| Generate Signals from Stochastic (BALANCED) | //+------------------------------------------------------------------+ void GenerateStochSignals() { // Get current stoch values (from Indicators.mqh) double main_line = StochBuffer_Main[0]; double signal_line = StochBuffer_Signal[0]; // BULLISH STOCH SIGNALS // Oversold (<20) = WARN (potential bullish reversal) if(main_line < 20) { AddCoordinatedSignal("stoch", "reject", "bullish", "WARN", 70, "oversold", main_line, false); } // Crossing up in lower half = PRAISE (bullish momentum building) if(main_line > signal_line && main_line < 50 && main_line > 30) { AddCoordinatedSignal("stoch", "reclaim", "bullish", "PRAISE", 65, "midpoint", main_line, false); } // BEARISH STOCH SIGNALS // Overbought (>80) = WARN (potential bearish reversal) if(main_line > 80) { AddCoordinatedSignal("stoch", "reject", "bearish", "WARN", 70, "overbought", main_line, false); } // Crossing down in upper half = PRAISE (bearish momentum building) if(main_line < signal_line && main_line > 50 && main_line < 70) { AddCoordinatedSignal("stoch", "break", "bearish", "PRAISE", 65, "midpoint", main_line, false); } } //+------------------------------------------------------------------+ //| Generate Signals from Candlestick Patterns (BALANCED) | //+------------------------------------------------------------------+ void GenerateCandleSignals() { // Loop through active patterns detected for(int i = 0; i < PatternCount; i++) { PatternSignal pattern = ActivePatterns[i]; string direction = ""; string action = ""; // Determine direction and action from pattern type if(pattern.type == PATTERN_REVERSAL_BULLISH) { direction = "bullish"; action = "reject"; // Rejecting from support } else if(pattern.type == PATTERN_REVERSAL_BEARISH) { direction = "bearish"; action = "reject"; // Rejecting from resistance } else if(pattern.type == PATTERN_CONTINUATION_BULL) { direction = "bullish"; action = "reclaim"; // Continuing upward } else if(pattern.type == PATTERN_CONTINUATION_BEAR) { direction = "bearish"; action = "break"; // Continuing downward } if(direction != "") { AddCoordinatedSignal("candle", action, direction, pattern.signal_label, pattern.adjusted_strength, pattern.location, pattern.pattern_price, pattern.at_key_level); } } } //+------------------------------------------------------------------+ //| Build Current Signal Cluster | //+------------------------------------------------------------------+ void BuildSignalCluster() { if(CurrentCluster.count == 0) { CurrentCluster.consensus_direction = "neutral"; CurrentCluster.consensus_type = ""; CurrentCluster.combined_strength = 0; CurrentCluster.conflict_score = 0; return; } // Count directions int bullish_count = 0; int bearish_count = 0; int warn_count = 0; int praise_count = 0; double total_strength = 0; for(int i = 0; i < CurrentCluster.count; i++) { if(CurrentCluster.signals[i].direction == "bullish") bullish_count++; else if(CurrentCluster.signals[i].direction == "bearish") bearish_count++; if(CurrentCluster.signals[i].signal_type == "WARN") warn_count++; else if(CurrentCluster.signals[i].signal_type == "PRAISE") praise_count++; total_strength += CurrentCluster.signals[i].strength; } // Determine consensus (need 60% agreement) double bull_pct = (double)bullish_count / CurrentCluster.count; double bear_pct = (double)bearish_count / CurrentCluster.count; if(bull_pct >= 0.6) CurrentCluster.consensus_direction = "bullish"; else if(bear_pct >= 0.6) CurrentCluster.consensus_direction = "bearish"; else CurrentCluster.consensus_direction = "neutral"; // Determine consensus type if(warn_count > praise_count) CurrentCluster.consensus_type = "WARN"; else CurrentCluster.consensus_type = "PRAISE"; // Calculate combined strength (weighted average) CurrentCluster.combined_strength = total_strength / CurrentCluster.count; // Calculate conflict score int min_dir = MathMin(bullish_count, bearish_count); double dir_conflict = (double)min_dir / CurrentCluster.count; int min_type = MathMin(warn_count, praise_count); double type_conflict = (double)min_type / CurrentCluster.count; CurrentCluster.conflict_score = ((dir_conflict * 0.7) + (type_conflict * 0.3)) * 100; CurrentCluster.cluster_time = TimeCurrent(); } //+------------------------------------------------------------------+ //| Should Trade Based on Cluster (AI-ready decision) | //+------------------------------------------------------------------+ bool ShouldTradeFromCluster(SignalCluster &cluster, double &multiplier) { // Don't trade if high conflict if(cluster.conflict_score > 40) { Print("❌ Trade REJECTED: High conflict score: ", cluster.conflict_score); return false; } // Don't trade if neutral if(cluster.consensus_direction == "neutral") { Print("❌ Trade REJECTED: No directional consensus"); return false; } // Don't trade if too soon after last trade (same direction) if(TimeCurrent() - LastTradeTime < ConflictPreventionSeconds) { if(LastTradeDirection == cluster.consensus_direction) { Print("❌ Trade REJECTED: Too soon after last ", LastTradeDirection, " trade"); return false; } } // Calculate multiplier based on strength and conflict multiplier = 1.0; // Strength adjustments if(cluster.combined_strength >= 85) multiplier += 0.3; // Very strong else if(cluster.combined_strength >= 75) multiplier += 0.2; // Strong else if(cluster.combined_strength >= 65) multiplier += 0.1; // Moderate else if(cluster.combined_strength < 50) multiplier -= 0.2; // Weak - be defensive // Conflict adjustments if(cluster.conflict_score > 30) multiplier -= 0.2; else if(cluster.conflict_score > 20) multiplier -= 0.1; // Ensure multiplier stays in reasonable range multiplier = MathMax(0.5, MathMin(multiplier, 2.0)); Print("✅ Trade APPROVED: ", cluster.consensus_direction, " ", cluster.consensus_type, " | Strength: ", cluster.combined_strength, " | Multiplier: ", multiplier); return true; } //+------------------------------------------------------------------+ //| Get Signal Balance Report | //+------------------------------------------------------------------+ string GetSignalBalanceReport() { int total_bull = BullWarnCount + BullPraiseCount; int total_bear = BearWarnCount + BearPraiseCount; int total = total_bull + total_bear; if(total == 0) return "No signals yet"; double bull_pct = (double)total_bull / total * 100; double bear_pct = (double)total_bear / total * 100; string report = StringFormat( "Signal Balance:\n" + "Bull: %.1f%% (%d warns, %d praise)\n" + "Bear: %.1f%% (%d warns, %d praise)\n" + "Status: %s", bull_pct, BullWarnCount, BullPraiseCount, bear_pct, BearWarnCount, BearPraiseCount, (bull_pct >= 40 && bull_pct <= 60) ? "BALANCED ✅" : "IMBALANCED ⚠️" ); return report; } //+------------------------------------------------------------------+ //| Reset Cluster (call every 5 minutes or after trade) | //+------------------------------------------------------------------+ void ResetSignalCluster() { CurrentCluster.count = 0; CurrentCluster.consensus_direction = "neutral"; CurrentCluster.consensus_type = ""; CurrentCluster.combined_strength = 0; CurrentCluster.conflict_score = 0; } //+------------------------------------------------------------------+ //| Cleanup Old Signals (call periodically) | //+------------------------------------------------------------------+ void CleanupOldSignals() { datetime cutoff = TimeCurrent() - (ConflictPreventionSeconds * 2); int new_count = 0; for(int i = 0; i < SignalHistoryCount; i++) { if(SignalHistory[i].timestamp > cutoff) { if(new_count != i) SignalHistory[new_count] = SignalHistory[i]; new_count++; } } SignalHistoryCount = new_count; } //+------------------------------------------------------------------+ //| Update Last Trade Info (call after opening trade) | //+------------------------------------------------------------------+ void UpdateLastTradeInfo(string direction) { LastTradeTime = TimeCurrent(); LastTradeDirection = direction; } //+------------------------------------------------------------------+ //| Master Signal Coordination Function - Call Every Tick | //+------------------------------------------------------------------+ void CoordinateAllSignals() { // Step 1: Generate signals from all sources GenerateMASignals(); GenerateMFIBSignals(); GenerateFIBSignals(); GenerateStochSignals(); GenerateCandleSignals(); // From CandlePatterns.mqh // Step 2: Build signal cluster BuildSignalCluster(); // Step 3: Cleanup old signals (every 100 ticks) static int cleanup_counter = 0; cleanup_counter++; if(cleanup_counter >= 100) { CleanupOldSignals(); cleanup_counter = 0; } }