mql5/Experts/_Architecture/Runtime.mqh
younglubah-gmail 3e91e83c65
2026-08-14 16:18:08 +02:00

259 lines
8.7 KiB
MQL5

//+------------------------------------------------------------------+
//| Runtime.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Market/DataManager.mqh"
#include "Configs/EAConfig.mqh"
#include "Events/EventBus/EventBus.mqh"
#include "Events/LoadingListener.mqh"
#include "Analysers/IAnalyser.mqh"
#include "Strategies/AbstractStrategy.mqh"
#include "Trade/TradeExecutor.mqh"
#include "Trade/TradeManager.mqh"
#include "Trade/RiskManager.mqh"
#include "Trade/Trackers/OrderTracker.mqh"
#include "ProcessController.mqh"
//+------------------------------------------------------------------+
//| Helper struct for registration storage |
//+------------------------------------------------------------------+
class ListenerRegistration
{
public:
EventType eventType;
IEventListener* listener;
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class Re : public IEventListener
{
public:
virtual void OnEvent(AbstractEvent* event) override
{
if(event.GetType() != RISK_REJECTED)
return;
RiskRejectedEvent* sig = (RiskRejectedEvent*)event;
// Print("RiskRejected: ", sig.GetReason());
}
};
//+------------------------------------------------------------------+
//| Main runtime class |
//+------------------------------------------------------------------+
class Runtime final
{
private:
DataManager m_dataManager;
EventBus* m_eventBus;
ProcessController m_controller;
LoadingListener m_loader;
TimeHelpers m_timeHelper;
CTradeExecutor* executor;
TradeManager* tradeMgr;
RiskManager* riskMgr;
OrderTracker* orderTracker;
Re re;
CArrayList<ListenerRegistration*> m_registrations;
void SubscribeAll();
void UnsubscribeAll();
void ClearRegistrations();
public:
Runtime();
~Runtime();
int Initialize(EAConfig &eaConfig);
void Update(int count =3);
// Registration helpers
void AddListener(int eventType, IEventListener* listener);
void AddAnalyser(IAnalyser* analyser)
{
// analyser.Init(m_eventBus);
m_controller.AddChapter(analyser, m_eventBus);
}
void AddStrategy(AbstractStrategy* strategy);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
Runtime::Runtime()
{
m_eventBus = new EventBus();
tradeMgr = new TradeManager();
executor = new CTradeExecutor();
riskMgr = new RiskManager();
orderTracker = new OrderTracker();
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
Runtime::~Runtime()
{
UnsubscribeAll(); // automatic bulk unsubscribe
ClearRegistrations(); // free registration objects
delete m_eventBus;
delete tradeMgr;
delete executor;
delete orderTracker;
delete riskMgr;
}
//+------------------------------------------------------------------+
//| One‑time initialisation |
//+------------------------------------------------------------------+
int Runtime::Initialize(EAConfig &eaConfig)
{
if(!m_loader.Initialize())
return INIT_FAILED;
// --- Register all event listeners (subscription happens later) ---
AddListener(LOADING, &m_loader);
AddListener(RISK_REJECTED, &re);
AddListener(NEW_BAR, tradeMgr);
AddListener(EXECUTE_MARKET_ORDER, tradeMgr);
AddListener(EXECUTE_PENDING_ORDER, tradeMgr);
AddListener(SIGNAL, riskMgr);
AddListener(POSITION_OPENED, riskMgr);
AddListener(PENDING_ORDER_PLACED, orderTracker);
AddListener(ORDER_DELETED, orderTracker);
// --- Loading sequence -------------------------------------------
m_eventBus.Push(new LoadingEvent(START, 6, "Starting..."));
m_eventBus.Dispatch();
Sleep(500 * 4);
m_eventBus.Push(new LoadingEvent(UPDATE, "Initializing Data Manager..."));
m_eventBus.Dispatch();
m_dataManager.Initialize(m_eventBus, eaConfig.tfConfigs, eaConfig.indConfigs,eaConfig.asSeries);
Sleep(500);
m_eventBus.Push(new LoadingEvent(UPDATE, "Subscribing..."));
m_eventBus.Dispatch();
SubscribeAll(); // bulk subscribe
m_eventBus.Push(new LoadingEvent(UPDATE, "Initializing Trade Executor..."));
m_eventBus.Dispatch();
executor.SetMagic(eaConfig.magicNumber);
executor.SetDeviation(eaConfig.Slippage);
Sleep(500);
m_eventBus.Push(new LoadingEvent(UPDATE, "Initializing Systems..."));
m_eventBus.Dispatch();
m_controller.Initialize(m_eventBus, m_dataManager);
riskMgr.Initialize(m_eventBus, eaConfig);
tradeMgr.Initialize(m_eventBus, executor, eaConfig);
orderTracker.Initialize(m_eventBus);
Sleep(500);
m_eventBus.Push(new LoadingEvent(UPDATE, "Launching..."));
m_eventBus.Dispatch();
m_controller.Launch();
Sleep(500);
m_eventBus.Push(new LoadingEvent(UPDATE, "Finished"));
m_eventBus.Dispatch();
Sleep(125);
m_eventBus.Push(new LoadingEvent(CLOSE, ""));
m_eventBus.Dispatch();
riskMgr.SetLaunching(false);
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Add a listener to the registration list (does NOT subscribe yet) |
//+------------------------------------------------------------------+
void Runtime::AddListener(int eventType, IEventListener* listener)
{
ListenerRegistration* reg = new ListenerRegistration();
reg.eventType = eventType;
reg.listener = listener;
m_registrations.Add(reg);
}
//+------------------------------------------------------------------+
//| Convenience: adds a strategy, sets its EventBus, subscribes it |
//+------------------------------------------------------------------+
void Runtime::AddStrategy(AbstractStrategy* strategy)
{
strategy.SetEventBus(m_eventBus); // inject bus
AddListener(ANALYSIS, strategy); // register for ANALYSIS events
}
//+------------------------------------------------------------------+
//| Subscribe all registered listeners to the event bus |
//+------------------------------------------------------------------+
void Runtime::SubscribeAll()
{
for(int i = 0; i < m_registrations.Size(); i++)
{
ListenerRegistration* reg = m_registrations.At(i);
m_eventBus.Subscribe(reg.eventType, reg.listener);
}
}
//+------------------------------------------------------------------+
//| Unsubscribe all registered listeners |
//+------------------------------------------------------------------+
void Runtime::UnsubscribeAll()
{
for(int i = 0; i < m_registrations.Size(); i++)
{
ListenerRegistration* reg = m_registrations.At(i);
m_eventBus.Unsubscribe(reg.eventType, reg.listener);
}
}
//+------------------------------------------------------------------+
//| Delete all registration objects |
//+------------------------------------------------------------------+
void Runtime::ClearRegistrations()
{
for(int i = 0; i < m_registrations.Size(); i++)
delete m_registrations.At(i);
m_registrations.Clear();
}
//+------------------------------------------------------------------+
//| Per‑tick update |
//+------------------------------------------------------------------+
void Runtime::Update(int count =3)
{
m_dataManager.Update(count);
CArrayList<TfBarSeries*> rawData = m_dataManager.GetRawData();
for(int i = 0; i < rawData.Size(); i++)
if(m_dataManager.CheckAndRelaunch(i))
m_controller.RelaunchSeries(i);
m_controller.Update();
m_eventBus.Dispatch();
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+