mql5/Experts/_Architecture/Market/DataManager.mqh

357 lines
11 KiB
MQL5

2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
//| DataManager.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 "TimeHelpers.mqh"
#include "BarSeries.mqh"
#include "IndicatorSeries.mqh"
2026-08-06 00:18:27 +02:00
#include "../Events/EventBus/EventBus.mqh"
2026-08-14 16:18:08 +02:00
#include "../Events/Events/NewData.mqh"
2026-08-09 07:14:59 +02:00
#include "../Configs/TfBarSeries.mqh"
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class DataManager
{
private:
2026-08-14 16:18:08 +02:00
bool isSeries;
2026-08-04 23:54:09 +02:00
TimeHelpers timeHelper;
2026-08-14 16:18:08 +02:00
CArrayList<TfBarSeries*>* rawData;
2026-08-10 20:23:58 +02:00
EventBus* m_queue;
2026-08-14 16:18:08 +02:00
CArrayList<IndicatorConfig>* indConfigs;
2026-08-04 23:54:09 +02:00
2026-08-14 16:18:08 +02:00
void AddTfData(string symbol, ENUM_TIMEFRAMES tradeTf, ENUM_TIMEFRAMES tf, int barsToLoad,
2026-08-09 07:14:59 +02:00
ENUM_TIME_FETCH_TYPE fetchType, int fetchCount, bool relaunch);
2026-08-06 00:18:27 +02:00
int FindExist(const string symbol, ENUM_TIMEFRAMES tf);
2026-08-14 16:18:08 +02:00
2026-08-04 23:54:09 +02:00
public:
2026-08-14 16:18:08 +02:00
DataManager() { rawData = new CArrayList<TfBarSeries*>();}
2026-08-06 00:18:27 +02:00
~DataManager()
{
for(int i = 0; i < rawData.Size(); i++)
{
2026-08-09 07:14:59 +02:00
TfBarSeries* s = rawData.At(i);
2026-08-14 16:18:08 +02:00
if(s.bar)
delete s.bar;
if(s.indicators)
{
for(int c = 0; c < s.IndicatorCount(); c++)
delete s.GetIndicator(c);
delete s.indicators; // <-- add this
}
2026-08-10 20:23:58 +02:00
delete s;
2026-08-06 00:18:27 +02:00
}
}
2026-08-04 23:54:09 +02:00
2026-08-09 07:14:59 +02:00
bool CheckAndRelaunch(int index);
2026-08-14 16:18:08 +02:00
int Initialize(EventBus* queue, CArrayList<SymbolConfig> &symbolConfigs, CArrayList<IndicatorConfig>* indConfigs, bool _isSeries = true);
void Update(int count =3);
CArrayList<TfBarSeries*>* GetRawData() { return rawData; }
2026-08-04 23:54:09 +02:00
};
2026-08-06 00:18:27 +02:00
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
void DataManager::AddTfData(string symbol, ENUM_TIMEFRAMES tradeTf, ENUM_TIMEFRAMES tf, int barsToLoad,
2026-08-09 07:14:59 +02:00
ENUM_TIME_FETCH_TYPE fetchType, int fetchCount, bool relaunch)
2026-08-04 23:54:09 +02:00
{
2026-08-06 00:18:27 +02:00
if(FindExist(symbol, tf) >= 0)
return;
2026-08-14 16:18:08 +02:00
2026-08-06 00:18:27 +02:00
2026-08-09 07:14:59 +02:00
TfBarSeries* tfSeries = new TfBarSeries();
2026-08-06 00:18:27 +02:00
tfSeries.tf = tf;
tfSeries.symbol = symbol;
2026-08-14 16:18:08 +02:00
tfSeries.tradeTf = tradeTf;
2026-08-06 00:18:27 +02:00
tfSeries.bar = new BarSeries();
2026-08-14 16:18:08 +02:00
tfSeries.bar.Initialize(symbol, tf, barsToLoad, isSeries);
2026-08-06 00:18:27 +02:00
2026-08-14 16:18:08 +02:00
for(int i = 0; i < indConfigs.Size(); i++)
{
IndicatorConfig c = indConfigs.At(i);
2026-08-06 00:18:27 +02:00
2026-08-14 16:18:08 +02:00
// Print(symbol," : ",c.location);
IndicatorSeries* indSeries = new IndicatorSeries();
indSeries.Initialize(symbol, tf, c.location, c.bufferCount, barsToLoad, c.params, isSeries);
tfSeries.AddIndicator(indSeries);
}
2026-08-06 00:18:27 +02:00
2026-08-09 07:14:59 +02:00
tfSeries.fetchType = fetchType;
tfSeries.fetchCount = fetchCount;
tfSeries.relaunchOnNewPeriod = relaunch;
2026-08-10 20:23:58 +02:00
if(relaunch)
{
tfSeries.nextRelaunchTime = timeHelper.NextRelaunchTime(TimeCurrent(), fetchType, fetchCount);
if(tfSeries.nextRelaunchTime <= TimeCurrent())
{
Print("Error: nextRelaunchTime is not in the future");
tfSeries.relaunchOnNewPeriod = false; // disable to avoid loop
}
2026-08-14 16:18:08 +02:00
}
2026-08-06 00:18:27 +02:00
rawData.Add(tfSeries);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
int DataManager::FindExist(const string symbol, ENUM_TIMEFRAMES tf)
2026-08-06 00:18:27 +02:00
{
for(int i = 0; i < rawData.Size(); i++)
2026-08-04 23:54:09 +02:00
{
2026-08-14 16:18:08 +02:00
TfBarSeries* data = rawData.At(i); // pointer, not value
if(data.symbol == symbol && data.tf == tf)
2026-08-06 00:18:27 +02:00
return i;
}
return -1;
}
2026-08-14 16:18:08 +02:00
2026-08-06 00:18:27 +02:00
//+------------------------------------------------------------------+
//| Initialize |
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
int DataManager::Initialize(EventBus* queue, CArrayList<SymbolConfig> &symbolConfigs, CArrayList<IndicatorConfig>* _indConfigs, bool _isSeries = true)
2026-08-06 00:18:27 +02:00
{
m_queue = queue;
2026-08-14 16:18:08 +02:00
indConfigs = _indConfigs;
isSeries = _isSeries;
2026-08-04 23:54:09 +02:00
2026-08-10 20:23:58 +02:00
for(int s = 0; s < symbolConfigs.Size(); s++)
2026-08-06 00:18:27 +02:00
{
2026-08-10 20:23:58 +02:00
SymbolConfig symbolCfg = symbolConfigs.At(s);
2026-08-06 00:18:27 +02:00
2026-08-14 16:18:08 +02:00
2026-08-06 00:18:27 +02:00
for(int t = 0; t < symbolCfg.tfConfigs.Size(); t++)
2026-08-04 23:54:09 +02:00
{
2026-08-06 00:18:27 +02:00
STimeframeConfig config = symbolCfg.tfConfigs.At(t);
2026-08-14 16:18:08 +02:00
2026-08-06 00:18:27 +02:00
ENUM_TIMEFRAMES tf = config.tf;
int shift = 1;
2026-08-04 23:54:09 +02:00
2026-08-06 00:18:27 +02:00
switch(config.fetchType)
{
case FETCH_FIRST_PREVIOUS_MONTH:
2026-08-04 23:54:09 +02:00
{
2026-08-06 00:18:27 +02:00
if(config.count < 1)
{
PrintFormat("Initialization failed: Count must be >= 1 for FETCH_FIRST_PREVIOUS_MONTH (%s, %s)",
symbolCfg.symbol, EnumToString(tf));
2026-08-04 23:54:09 +02:00
2026-08-06 00:18:27 +02:00
return INIT_FAILED;
}
2026-08-04 23:54:09 +02:00
2026-08-06 00:18:27 +02:00
shift = Bars(symbolCfg.symbol, tf, timeHelper.FirstOfPreviousMonths(TimeCurrent(), config.count), TimeCurrent());
2026-08-04 23:54:09 +02:00
2026-08-06 00:18:27 +02:00
break;
2026-08-04 23:54:09 +02:00
}
2026-08-06 00:18:27 +02:00
case FETCH_PREVIOUS_WEEK:
{
if(config.count < 1)
{
PrintFormat("Initialization failed: Count must be >= 1 for FETCH_PREVIOUS_WEEK (%s, %s)", symbolCfg.symbol, EnumToString(tf));
return INIT_FAILED;
}
shift = Bars(symbolCfg.symbol, tf, timeHelper.PreviousWeekStart(TimeCurrent(), config.count), TimeCurrent());
2026-08-04 23:54:09 +02:00
2026-08-06 00:18:27 +02:00
break;
}
2026-08-04 23:54:09 +02:00
2026-08-06 00:18:27 +02:00
case FETCH_PREVIOUS_DAY:
2026-08-04 23:54:09 +02:00
{
2026-08-06 00:18:27 +02:00
if(tf >= PERIOD_D1)
{
PrintFormat(
"Initialization failed: FETCH_PREVIOUS_DAY cannot be used on %s (%s)",
symbolCfg.symbol,
EnumToString(tf));
return INIT_FAILED;
}
shift = Bars(
symbolCfg.symbol,
tf,
timeHelper.PreviousDayStart(TimeCurrent()),
TimeCurrent());
break;
2026-08-04 23:54:09 +02:00
}
2026-08-06 00:18:27 +02:00
default:
{
if(config.count > 0)
shift = config.count;
break;
}
}
2026-08-14 16:18:08 +02:00
AddTfData(symbolCfg.symbol, symbolCfg.tradeTimeframe, tf, shift,
2026-08-09 07:14:59 +02:00
config.fetchType, config.count, config.relaunchOnNewPeriod);
2026-08-04 23:54:09 +02:00
}
}
2026-08-06 00:18:27 +02:00
2026-08-04 23:54:09 +02:00
return INIT_SUCCEEDED;
}
2026-08-09 07:14:59 +02:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
void DataManager::Update(int count =3)
2026-08-09 07:14:59 +02:00
{
2026-08-14 16:18:08 +02:00
for(int i = 0; i < rawData.Size(); i++)
2026-08-09 07:14:59 +02:00
{
2026-08-14 16:18:08 +02:00
TfBarSeries* series = rawData.At(i); // pointer
if(series.Update(count))
2026-08-09 07:14:59 +02:00
{
2026-08-14 16:18:08 +02:00
NewBarEvent* event = new NewBarEvent(series.symbol, series.tf, series.Time(series.TotalBars() - 1));
m_queue.Push(event);
2026-08-09 07:14:59 +02:00
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool DataManager::CheckAndRelaunch(int index)
{
2026-08-14 16:18:08 +02:00
if(index < 0 || index >= rawData.Size())
return false;
TfBarSeries* series = rawData.At(index);
if(series == NULL)
return false;
2026-08-09 07:14:59 +02:00
if(!series.relaunchOnNewPeriod)
return false;
2026-08-14 16:18:08 +02:00
2026-08-09 07:14:59 +02:00
if(TimeCurrent() < series.nextRelaunchTime)
return false;
int newShift = 1;
2026-08-14 16:18:08 +02:00
2026-08-09 07:14:59 +02:00
switch(series.fetchType)
{
case FETCH_FIRST_PREVIOUS_MONTH:
2026-08-14 16:18:08 +02:00
newShift = Bars(
series.symbol,
series.tf,
timeHelper.FirstOfPreviousMonths(
TimeCurrent(),
series.fetchCount
),
TimeCurrent()
);
2026-08-09 07:14:59 +02:00
break;
2026-08-14 16:18:08 +02:00
2026-08-09 07:14:59 +02:00
case FETCH_PREVIOUS_WEEK:
2026-08-14 16:18:08 +02:00
newShift = Bars(
series.symbol,
series.tf,
timeHelper.PreviousWeekStart(
TimeCurrent(),
series.fetchCount
),
TimeCurrent()
);
2026-08-09 07:14:59 +02:00
break;
2026-08-14 16:18:08 +02:00
2026-08-09 07:14:59 +02:00
case FETCH_PREVIOUS_DAY:
2026-08-14 16:18:08 +02:00
newShift = Bars(
series.symbol,
series.tf,
timeHelper.PreviousDayStart(TimeCurrent()),
TimeCurrent()
);
2026-08-09 07:14:59 +02:00
break;
2026-08-14 16:18:08 +02:00
2026-08-09 07:14:59 +02:00
default:
return false;
}
2026-08-14 16:18:08 +02:00
// ---------------------------------------------------------
// Destroy old data
// ---------------------------------------------------------
if(series.bar != NULL)
{
delete series.bar;
series.bar = NULL;
}
series.ClearIndicators();
// ---------------------------------------------------------
// Create fresh bar series
// ---------------------------------------------------------
2026-08-09 07:14:59 +02:00
series.bar = new BarSeries();
2026-08-10 20:23:58 +02:00
2026-08-14 16:18:08 +02:00
if(!series.bar.Initialize(
series.symbol,
series.tf,
newShift,isSeries
))
{
delete series.bar;
series.bar = NULL;
return false;
}
// ---------------------------------------------------------
// Create fresh indicators
// ---------------------------------------------------------
for(int i = 0; i < indConfigs.Size(); i++)
{
IndicatorConfig c = indConfigs.At(i);
IndicatorSeries* indSeries = new IndicatorSeries();
if(!indSeries.Initialize(
series.symbol,
series.tf,
c.location,
c.bufferCount,
newShift,
c.params,isSeries
))
{
delete indSeries;
continue;
}
series.AddIndicator(indSeries);
}
// ---------------------------------------------------------
// Schedule next relaunch
// ---------------------------------------------------------
series.nextRelaunchTime =
timeHelper.NextRelaunchTime(
TimeCurrent(),
series.fetchType,
series.fetchCount
);
2026-08-09 07:14:59 +02:00
return true;
}
//+------------------------------------------------------------------+