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
|