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

357 lines
11 KiB
MQL5

//+------------------------------------------------------------------+
//| 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"
#include "../Events/EventBus/EventBus.mqh"
#include "../Events/Events/NewData.mqh"
#include "../Configs/TfBarSeries.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class DataManager
{
private:
bool isSeries;
TimeHelpers timeHelper;
CArrayList<TfBarSeries*>* rawData;
EventBus* m_queue;
CArrayList<IndicatorConfig>* indConfigs;
void AddTfData(string symbol, ENUM_TIMEFRAMES tradeTf, ENUM_TIMEFRAMES tf, int barsToLoad,
ENUM_TIME_FETCH_TYPE fetchType, int fetchCount, bool relaunch);
int FindExist(const string symbol, ENUM_TIMEFRAMES tf);
public:
DataManager() { rawData = new CArrayList<TfBarSeries*>();}
~DataManager()
{
for(int i = 0; i < rawData.Size(); i++)
{
TfBarSeries* s = rawData.At(i);
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
}
delete s;
}
}
bool CheckAndRelaunch(int index);
int Initialize(EventBus* queue, CArrayList<SymbolConfig> &symbolConfigs, CArrayList<IndicatorConfig>* indConfigs, bool _isSeries = true);
void Update(int count =3);
CArrayList<TfBarSeries*>* GetRawData() { return rawData; }
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DataManager::AddTfData(string symbol, ENUM_TIMEFRAMES tradeTf, ENUM_TIMEFRAMES tf, int barsToLoad,
ENUM_TIME_FETCH_TYPE fetchType, int fetchCount, bool relaunch)
{
if(FindExist(symbol, tf) >= 0)
return;
TfBarSeries* tfSeries = new TfBarSeries();
tfSeries.tf = tf;
tfSeries.symbol = symbol;
tfSeries.tradeTf = tradeTf;
tfSeries.bar = new BarSeries();
tfSeries.bar.Initialize(symbol, tf, barsToLoad, isSeries);
for(int i = 0; i < indConfigs.Size(); i++)
{
IndicatorConfig c = indConfigs.At(i);
// Print(symbol," : ",c.location);
IndicatorSeries* indSeries = new IndicatorSeries();
indSeries.Initialize(symbol, tf, c.location, c.bufferCount, barsToLoad, c.params, isSeries);
tfSeries.AddIndicator(indSeries);
}
tfSeries.fetchType = fetchType;
tfSeries.fetchCount = fetchCount;
tfSeries.relaunchOnNewPeriod = relaunch;
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
}
}
rawData.Add(tfSeries);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int DataManager::FindExist(const string symbol, ENUM_TIMEFRAMES tf)
{
for(int i = 0; i < rawData.Size(); i++)
{
TfBarSeries* data = rawData.At(i); // pointer, not value
if(data.symbol == symbol && data.tf == tf)
return i;
}
return -1;
}
//+------------------------------------------------------------------+
//| Initialize |
//+------------------------------------------------------------------+
int DataManager::Initialize(EventBus* queue, CArrayList<SymbolConfig> &symbolConfigs, CArrayList<IndicatorConfig>* _indConfigs, bool _isSeries = true)
{
m_queue = queue;
indConfigs = _indConfigs;
isSeries = _isSeries;
for(int s = 0; s < symbolConfigs.Size(); s++)
{
SymbolConfig symbolCfg = symbolConfigs.At(s);
for(int t = 0; t < symbolCfg.tfConfigs.Size(); t++)
{
STimeframeConfig config = symbolCfg.tfConfigs.At(t);
ENUM_TIMEFRAMES tf = config.tf;
int shift = 1;
switch(config.fetchType)
{
case FETCH_FIRST_PREVIOUS_MONTH:
{
if(config.count < 1)
{
PrintFormat("Initialization failed: Count must be >= 1 for FETCH_FIRST_PREVIOUS_MONTH (%s, %s)",
symbolCfg.symbol, EnumToString(tf));
return INIT_FAILED;
}
shift = Bars(symbolCfg.symbol, tf, timeHelper.FirstOfPreviousMonths(TimeCurrent(), config.count), TimeCurrent());
break;
}
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());
break;
}
case FETCH_PREVIOUS_DAY:
{
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;
}
default:
{
if(config.count > 0)
shift = config.count;
break;
}
}
AddTfData(symbolCfg.symbol, symbolCfg.tradeTimeframe, tf, shift,
config.fetchType, config.count, config.relaunchOnNewPeriod);
}
}
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void DataManager::Update(int count =3)
{
for(int i = 0; i < rawData.Size(); i++)
{
TfBarSeries* series = rawData.At(i); // pointer
if(series.Update(count))
{
NewBarEvent* event = new NewBarEvent(series.symbol, series.tf, series.Time(series.TotalBars() - 1));
m_queue.Push(event);
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool DataManager::CheckAndRelaunch(int index)
{
if(index < 0 || index >= rawData.Size())
return false;
TfBarSeries* series = rawData.At(index);
if(series == NULL)
return false;
if(!series.relaunchOnNewPeriod)
return false;
if(TimeCurrent() < series.nextRelaunchTime)
return false;
int newShift = 1;
switch(series.fetchType)
{
case FETCH_FIRST_PREVIOUS_MONTH:
newShift = Bars(
series.symbol,
series.tf,
timeHelper.FirstOfPreviousMonths(
TimeCurrent(),
series.fetchCount
),
TimeCurrent()
);
break;
case FETCH_PREVIOUS_WEEK:
newShift = Bars(
series.symbol,
series.tf,
timeHelper.PreviousWeekStart(
TimeCurrent(),
series.fetchCount
),
TimeCurrent()
);
break;
case FETCH_PREVIOUS_DAY:
newShift = Bars(
series.symbol,
series.tf,
timeHelper.PreviousDayStart(TimeCurrent()),
TimeCurrent()
);
break;
default:
return false;
}
// ---------------------------------------------------------
// Destroy old data
// ---------------------------------------------------------
if(series.bar != NULL)
{
delete series.bar;
series.bar = NULL;
}
series.ClearIndicators();
// ---------------------------------------------------------
// Create fresh bar series
// ---------------------------------------------------------
series.bar = new BarSeries();
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
);
return true;
}
//+------------------------------------------------------------------+