284 lines
9.6 KiB
MQL5
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;
| |
}
| |
//+------------------------------------------------------------------+
|