mql5/Experts/_FrameWork/Market/DataManager.mqh
younglubah-gmail a4b935d8d8
2026-09-30 09:06:59 +02:00

284 lines
9.6 KiB
MQL5

//+------------------------------------------------------------------+
//| DataManager.mqh |
//| Copyright 2026, Concrete Goonies |
//| https://concrete-goonies.web.app |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Concrete Goonies"
#property link "https://concrete-goonies.web.app"
#property version "1.00"
#include "TimeHelpers.mqh"
#include "../Events/EventBus/EventBus.mqh"
#include "../Configs/EAConfig.mqh"
#include "TimeFrameDataSeries.mqh"
#include "../Events/Events/NewBarEvent.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class DataManager
{
private:
EventBus* eventBus;
CArrayList<TimeFrameDataSeries*>* rawData;
EAConfig configs;
TimeHelpers* timeHelper;
int FindExist(const string symbol, ENUM_TIMEFRAMES tf);
void AddTfData(string symbol, ENUM_TIMEFRAMES tf, int barsToLoad, ENUM_TIME_FETCH_TYPE fetchType, int fetchCount, bool relaunch);
int GetCandleCount(TimeFrameDataSeries* series, datetime time);
int GetCandleCount(SymbolConfig &symbolCfg, STimeframeConfig &tfConfig);
public:
DataManager(EventBus* p_eventBus);
~DataManager();
void Update(int count = 3);
int Initialize(EAConfig &c);
bool CheckAndRelaunch(int index);
CArrayList<TimeFrameDataSeries*>* GetRawData() { return rawData; }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
DataManager::DataManager(EventBus* p_eventBus) : eventBus(p_eventBus)
{
rawData = new CArrayList<TimeFrameDataSeries*>();
timeHelper = new TimeHelpers();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
DataManager::~DataManager()
{
for(int s = 0; s < rawData.Size(); s++)
delete rawData.At(s);
delete rawData;
delete timeHelper;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int DataManager::Initialize(EAConfig &c)
{
configs = c;
for(int s = 0; s < configs.symbolConfigs.Size(); s++)
{
SymbolConfig symbolCfg = configs.symbolConfigs.At(s);
for(int t = 0; t < symbolCfg.tfConfigs.Size(); t++)
{
STimeframeConfig tfConfig = symbolCfg.tfConfigs.At(t);
ENUM_TIMEFRAMES tf = tfConfig.tf;
int shift = GetCandleCount(symbolCfg, tfConfig);
AddTfData(symbolCfg.symbol, tf, shift, tfConfig.fetchType, tfConfig.count, tfConfig.relaunchOnNewPeriod);
}
}
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DataManager::Update(int count = 3)
{
for(int i = 0; i < rawData.Size(); i++)
{
TimeFrameDataSeries* series = rawData.At(i);
if(!series.isReset)
if(series.Update(count))
{
NewBarEvent* event = new NewBarEvent(series.symbol, series.tf, series.Time(!configs.asSeries ? series.TotalBars() - 1 : 0), count);
eventBus.Push(event);
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool DataManager::CheckAndRelaunch(int index)
{
if(index < 0 || index >= rawData.Size())
return false;
TimeFrameDataSeries* series = rawData.At(index);
if(series == NULL)
return false;
if(!series.relaunchOnNewPeriod)
return false;
string symbol = series.symbol;
ENUM_TIMEFRAMES tf = series.tf;
datetime t = iTime(symbol, tf, 0);
if(t < series.nextRelaunchTime)
return false;
int shift = GetCandleCount(series, t);
series.isReset = true;
series.bar.Initialize(symbol, tf, shift, configs.asSeries);
series.Update(shift);
/*/for(int i = 0; i < series.indicators.Size(); i++)
series.indicators.At(i).Initialize(symbol, tf, series.indicators.At(i).m_name, series.indicators.At(i).m_buffersCount, shift, configs.asSeries);
*/
series.nextRelaunchTime = timeHelper.NextRelaunchTime(t, series.fetchType, series.fetchCount);
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int DataManager::GetCandleCount(TimeFrameDataSeries* series, datetime time)
{
// Print(EnumToString(series.fetchType));
int newShift = 21;
switch(series.fetchType)
{
case FETCH_FIRST_PREVIOUS_MONTH:
newShift = Bars(series.symbol, series.tf, timeHelper.FirstOfPreviousMonths(time, series.fetchCount), time);
//Print(timeHelper.PreviousDayStart(time), ", FETCH_FIRST_PREVIOUS_MONTH", time);
break;
case FETCH_PREVIOUS_WEEK:
newShift = Bars(series.symbol, series.tf, timeHelper.PreviousWeekStart(time, series.fetchCount), time);
break;
case FETCH_PREVIOUS_DAY:
newShift = Bars(series.symbol, series.tf, timeHelper.PreviousDayStart(time), time);
break;
}
return newShift;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int DataManager::GetCandleCount(SymbolConfig &symbolCfg, STimeframeConfig &tfConfig)
{
ENUM_TIMEFRAMES tf = tfConfig.tf;
int shift = 1;
string symbol = symbolCfg.symbol;
datetime t = iTime(symbol, tf, 0);
switch(tfConfig.fetchType)
{
case FETCH_FIRST_PREVIOUS_MONTH:
{
if(tfConfig.count < 1)
{
PrintFormat("Initialization failed: Count must be >= 1 for FETCH_FIRST_PREVIOUS_MONTH (%s, %s)", symbol, EnumToString(tf));
return INIT_FAILED;
}
shift = Bars(symbol, tf, timeHelper.FirstOfPreviousMonths(t, tfConfig.count), t);
break;
}
case FETCH_PREVIOUS_WEEK:
{
if(tfConfig.count < 1)
{
PrintFormat("Initialization failed: Count must be >= 1 for FETCH_PREVIOUS_WEEK (%s, %s)", symbol, EnumToString(tf));
return INIT_FAILED;
}
shift = Bars(symbol, tf, timeHelper.PreviousWeekStart(t, tfConfig.count), t);
break;
}
case FETCH_PREVIOUS_DAY:
{
if(tf >= PERIOD_D1)
{
PrintFormat("Initialization failed: FETCH_PREVIOUS_DAY cannot be used on %s (%s)", symbol, EnumToString(tf));
return INIT_FAILED;
}
shift = Bars(symbol, tf, timeHelper.PreviousDayStart(t,tfConfig.count), t);
break;
}
default:
{
if(tfConfig.count > 0)
shift = tfConfig.count;
break;
}
}
return shift;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DataManager::AddTfData(string symbol, ENUM_TIMEFRAMES tf, int barsToLoad, ENUM_TIME_FETCH_TYPE fetchType, int fetchCount, bool relaunch)
{
if(FindExist(symbol, tf) >= 0)
return;
TimeFrameDataSeries* tfSeries = new TimeFrameDataSeries();
tfSeries.tf = tf;
tfSeries.symbol = symbol;
tfSeries.bar = new Candles();
tfSeries.bar.Initialize(symbol, tf, barsToLoad, configs.asSeries);
for(int i = 0; i < configs.indConfigs.Size(); i++)
{
IndicatorConfig c = configs.indConfigs.At(i);
Indicator* indSeries = new Indicator();
indSeries.Initialize(symbol, tf, c.location, c.bufferCount, barsToLoad, c.params, configs.asSeries);
tfSeries.AddIndicator(indSeries);
}
tfSeries.fetchType = fetchType;
tfSeries.fetchCount = fetchCount;
tfSeries.relaunchOnNewPeriod = relaunch;
if(relaunch)
{
datetime t = iTime(symbol, tf, 0);
tfSeries.nextRelaunchTime = timeHelper.NextRelaunchTime(t, fetchType, fetchCount);
if(tfSeries.nextRelaunchTime <= t)
{
Print("Error: nextRelaunchTime is not in the future");
tfSeries.relaunchOnNewPeriod = false; // disable to avoid loop
}
}
rawData.Add(tfSeries);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int DataManager::FindExist(const string symbol, ENUM_TIMEFRAMES tf)
{
for(int i = 0; i < rawData.Size(); i++)
{
TimeFrameDataSeries* data = rawData.At(i); // pointer, not value
if(data.symbol == symbol && data.tf == tf)
return i;
}
return -1;
}
//+------------------------------------------------------------------+