1
1
Fork 1
RSI-Stoch-MA-EA/Signalcoordinator.mqh
Sahr John a26cd4a17b
Einige Prüfungen sind fehlgeschlagen
Build and Deploy MT5 EA / build (push) Failing after 39s
Build and Deploy MT5 EA / deploy (push) Has been skipped
Add Signalcoordinator.mqh
2026-01-20 20:07:29 +00:00

658 Zeilen
Kein EOL
22 KiB
MQL5

//+------------------------------------------------------------------+
//| 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;
}
}