mql5/Experts/Advisors/DualEA/Include/EventBus.mqh

301 lines
8.8 KiB
MQL5
Raw Permalink Normal View History

2025-09-24 17:58:57 -04:00
//+------------------------------------------------------------------+
//| EventBus.mqh - Unified Event System for Cross-Component Communication |
//+------------------------------------------------------------------+
#ifndef __EVENTBUS_MQH__
#define __EVENTBUS_MQH__
#include <Arrays/ArrayString.mqh>
// Event types enumeration
enum EVENT_TYPE
{
EVENT_GATE_PROCESSED, // Gate processing completed
EVENT_SIGNAL_GENERATED, // New trading signal generated
EVENT_INSIGHTS_UPDATED, // Insights data updated
EVENT_TRADE_EXECUTED, // Trade execution completed
EVENT_SYSTEM_STATUS, // System status change
EVENT_CONFIG_CHANGED, // Configuration updated
EVENT_ERROR_OCCURRED, // Error event
EVENT_PERFORMANCE_METRIC // Performance metric update
};
// Event data structure
struct EventData
{
EVENT_TYPE type;
string source;
string data;
datetime timestamp;
int priority; // 0=low, 1=normal, 2=high, 3=critical
EventData()
{
type = EVENT_SYSTEM_STATUS;
source = "";
data = "";
timestamp = TimeCurrent();
priority = 1;
}
};
// Event subscriber interface
class IEventSubscriber
{
public:
virtual ~IEventSubscriber() {}
virtual void OnEvent(const EventData& event) = 0;
virtual string GetSubscriberName() = 0;
};
// Simple event subscriber for function callbacks
class CFunctionSubscriber : public IEventSubscriber
{
private:
string m_name;
public:
CFunctionSubscriber(const string& name) : m_name(name) {}
void OnEvent(const EventData& event) override
{
// Default implementation - can be overridden
Print("[", m_name, "] Received event: ", EnumToString(event.type), " from ", event.source);
}
string GetSubscriberName() override { return m_name; }
};
// Event bus singleton
class CEventBus
{
private:
static CEventBus* instance;
IEventSubscriber* subscribers[EVENT_PERFORMANCE_METRIC + 1][10]; // Max 10 subscribers per event type
int subscriber_counts[EVENT_PERFORMANCE_METRIC + 1];
EventData event_history[100]; // Keep last 100 events
int history_index;
bool verbose_logging;
CEventBus()
{
// Initialize subscriber arrays
for(int i = 0; i <= EVENT_PERFORMANCE_METRIC; i++)
{
subscriber_counts[i] = 0;
for(int j = 0; j < 10; j++)
subscribers[i][j] = NULL;
}
history_index = 0;
verbose_logging = false;
}
public:
static CEventBus* GetInstance()
{
if(instance == NULL)
instance = new CEventBus();
return instance;
}
static void Cleanup()
{
if(instance != NULL)
{
delete instance;
instance = NULL;
}
}
// Subscribe to events
bool Subscribe(EVENT_TYPE event_type, IEventSubscriber* subscriber)
{
if(subscriber == NULL || event_type < 0 || event_type > EVENT_PERFORMANCE_METRIC)
return false;
int count = subscriber_counts[event_type];
if(count >= 10) // Max subscribers reached
{
Print("EventBus: Maximum subscribers reached for event type ", EnumToString(event_type));
return false;
}
subscribers[event_type][count] = subscriber;
subscriber_counts[event_type]++;
if(verbose_logging)
Print("EventBus: Subscriber '", subscriber.GetSubscriberName(),
"' registered for ", EnumToString(event_type));
return true;
}
// Unsubscribe from events
bool Unsubscribe(EVENT_TYPE event_type, IEventSubscriber* subscriber)
{
if(subscriber == NULL || event_type < 0 || event_type > EVENT_PERFORMANCE_METRIC)
return false;
int count = subscriber_counts[event_type];
for(int i = 0; i < count; i++)
{
if(subscribers[event_type][i] == subscriber)
{
// Shift remaining subscribers
for(int j = i; j < count - 1; j++)
subscribers[event_type][j] = subscribers[event_type][j + 1];
subscribers[event_type][count - 1] = NULL;
subscriber_counts[event_type]--;
if(verbose_logging)
Print("EventBus: Subscriber '", subscriber.GetSubscriberName(),
"' unregistered from ", EnumToString(event_type));
return true;
}
}
return false;
}
// Publish event to all subscribers
void Publish(EVENT_TYPE event_type, const string& source, const string& data, int priority = 1)
{
EventData event;
event.type = event_type;
event.source = source;
event.data = data;
event.timestamp = TimeCurrent();
event.priority = priority;
// Store in history
event_history[history_index] = event;
history_index = (history_index + 1) % 100;
// Log event if verbose
if(verbose_logging || priority >= 2) // Always log high priority events
{
Print("EventBus: [", source, "] ", EnumToString(event_type), " - ", data);
}
// Notify all subscribers
int count = subscriber_counts[event_type];
for(int i = 0; i < count; i++)
{
if(subscribers[event_type][i] != NULL)
{
subscribers[event_type][i].OnEvent(event);
}
}
}
// Convenience methods for common events
void PublishGateEvent(const string& gate_name, bool passed, const string& reason)
{
2025-09-24 22:41:55 -04:00
string data = StringFormat("%s|%s|%s", gate_name, (passed ? "PASS" : "FAIL"), reason);
2025-09-24 17:58:57 -04:00
Publish(EVENT_GATE_PROCESSED, "GateManager", data, 1);
}
void PublishSignalEvent(const string& signal_id, const string& symbol, double confidence)
{
2025-09-24 22:41:55 -04:00
string data = StringFormat("%s|%s|%s", signal_id, symbol, DoubleToString(confidence, 3));
2025-09-24 17:58:57 -04:00
Publish(EVENT_SIGNAL_GENERATED, "SignalGenerator", data, 1);
}
void PublishInsightsEvent(const string& action, const string& details)
{
2025-09-24 22:41:55 -04:00
string data = StringFormat("%s|%s", action, details);
Publish(EVENT_INSIGHTS_UPDATED, "InsightsManager", data, 1);
2025-09-24 17:58:57 -04:00
}
void PublishTradeEvent(const string& trade_id, const string& action, double result)
{
2025-09-24 22:41:55 -04:00
string data = StringFormat("%s|%s|%s", trade_id, action, DoubleToString(result, 2));
2025-09-24 17:58:57 -04:00
Publish(EVENT_TRADE_EXECUTED, "TradeManager", data, 2);
}
void PublishSystemEvent(const string& component, const string& status)
{
Publish(EVENT_SYSTEM_STATUS, component, status, 1);
}
void PublishErrorEvent(const string& component, const string& error_msg)
{
Publish(EVENT_ERROR_OCCURRED, component, error_msg, 3);
}
void PublishPerformanceEvent(const string& metric_name, double value)
{
string data = metric_name + "|" + DoubleToString(value, 4);
Publish(EVENT_PERFORMANCE_METRIC, "SystemMonitor", data, 1);
}
// Configuration
void SetVerboseLogging(bool enabled) { verbose_logging = enabled; }
bool IsVerboseLogging() { return verbose_logging; }
// Event history access
EventData GetLastEvent(EVENT_TYPE event_type)
{
// Search backwards through history for the last event of this type
for(int i = 0; i < 100; i++)
{
int index = (history_index - 1 - i + 100) % 100;
if(event_history[index].type == event_type && event_history[index].timestamp > 0)
return event_history[index];
}
EventData empty;
return empty;
}
int GetEventCount(EVENT_TYPE event_type)
{
int count = 0;
for(int i = 0; i < 100; i++)
{
if(event_history[i].type == event_type && event_history[i].timestamp > 0)
count++;
}
return count;
}
// Debug information
void PrintSubscriberInfo()
{
Print("=== EventBus Subscriber Information ===");
for(int i = 0; i <= EVENT_PERFORMANCE_METRIC; i++)
{
if(subscriber_counts[i] > 0)
{
Print("Event Type ", EnumToString((EVENT_TYPE)i), ": ", subscriber_counts[i], " subscribers");
for(int j = 0; j < subscriber_counts[i]; j++)
{
if(subscribers[i][j] != NULL)
Print(" - ", subscribers[i][j].GetSubscriberName());
}
}
}
}
void PrintEventHistory(int count = 10)
{
Print("=== EventBus Recent Events (last ", count, ") ===");
for(int i = 0; i < MathMin(count, 100); i++)
{
int index = (history_index - 1 - i + 100) % 100;
EventData event = event_history[index];
if(event.timestamp > 0)
{
Print("[", TimeToString(event.timestamp), "] ",
event.source, " -> ", EnumToString(event.type), ": ", event.data);
}
}
}
};
// Static instance declaration
static CEventBus* CEventBus::instance = NULL;
#endif