//+------------------------------------------------------------------+ //| ProcessController.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" // ProcessController.mqh #include "Market/DataManager.mqh" #include "Analysers/IAnalyser.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class ProcessController final { private: DataManager* m_data; IAnalyser* m_chapters[]; int m_chapterCount; EventBus* m_eventBus; // Time‑based tracking – one entry per symbol/tf (same order as rawData) datetime m_lastProcessedTime[]; int m_seriesCount; // Launch progress (used only during initial replay) int m_launchProgress[]; // bar index for each series void RunAllChapters(TfBarSeries &series, int barIndex) { for(int c = 0; c < m_chapterCount; c++) m_chapters[c].ProcessBar(series, barIndex); } public: ProcessController() : m_data(NULL), m_chapterCount(0), m_seriesCount(0) {} void Initialize(EventBus* eventBus, DataManager &dm) { m_eventBus = eventBus; m_data = &dm; } void AddChapter(IAnalyser* chapter, EventBus* _eventBus) { int sz = ArraySize(m_chapters); ArrayResize(m_chapters, sz + 1); chapter.Init(_eventBus); m_chapters[sz] = chapter; m_chapterCount = sz + 1; } //--------------------------------------------------------------- // Launch – replay all historical bars through every chapter //--------------------------------------------------------------- void ProcessController::Launch() { if(m_data == NULL) return; CArrayList* rawData = m_data.GetRawData(); // pointer to list int totalSeries = rawData.Size(); ArrayResize(m_launchProgress, totalSeries); ArrayResize(m_lastProcessedTime, totalSeries); for(int i = 0; i < totalSeries; i++) { m_launchProgress[i] = 0; m_lastProcessedTime[i] = 0; } m_seriesCount = totalSeries; for(int i = 0; i < totalSeries; i++) { TfBarSeries* series = rawData.At(i); // pointer int total = series.TotalBars(); for(int barIdx = 0; barIdx < total; barIdx++) RunAllChapters(*series, barIdx); if(total > 0) m_lastProcessedTime[i] = series.Time(total - 1); } } //--------------------------------------------------------------- // Update – process only newly arrived bars using time comparison //--------------------------------------------------------------- void Update() { if(m_data == NULL) return; CArrayList* rawData = m_data.GetRawData(); int totalSeries = rawData.Size(); if(totalSeries > m_seriesCount) { ArrayResize(m_lastProcessedTime, totalSeries); for(int i = m_seriesCount; i < totalSeries; i++) m_lastProcessedTime[i] = 0; m_seriesCount = totalSeries; } for(int i = 0; i < totalSeries; i++) { TfBarSeries* series = rawData.At(i); int total = series.TotalBars(); if(total == 0) continue; datetime latestBarTime = series.Time(total - 1); if(latestBarTime <= m_lastProcessedTime[i]) continue; for(int barIdx = 0; barIdx < total; barIdx++) if(series.Time(barIdx) > m_lastProcessedTime[i]) RunAllChapters(*series, barIdx); m_lastProcessedTime[i] = latestBarTime; } } void RelaunchSeries(int index); }; void ProcessController::RelaunchSeries(int index) { TfBarSeries* series = m_data.GetRawData().At(index); // pointer for(int c = 0; c < m_chapterCount; c++) m_chapters[c].Reset(series.symbol, series.tf); m_lastProcessedTime[index] = 0; int total = series.TotalBars(); for(int barIdx = 0; barIdx < total; barIdx++) RunAllChapters(*series, barIdx); if(total > 0) m_lastProcessedTime[index] = series.Time(total - 1); }