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

168 lines
No EOL
5 KiB
MQL5

//+------------------------------------------------------------------+
//| BarSeries.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.10"
class BarSeries
{
private:
string m_symbol;
ENUM_TIMEFRAMES m_tf;
MqlRates m_bars[];
int m_barsCount;
datetime m_lastBarOpen;
bool m_initialized;
bool m_asSeries; // true = index 0 is the most recent bar
public:
BarSeries() : m_symbol(""), m_tf(PERIOD_CURRENT), m_barsCount(0),
m_lastBarOpen(0), m_initialized(false), m_asSeries(true) {}
~BarSeries() {}
bool Initialize(string symbol, ENUM_TIMEFRAMES tf, int initialBars, bool asSeries = true);
bool Update(int barsCount = 3);
double Close(int pShift);
double High(int pShift);
double Low(int pShift);
double Open(int pShift);
datetime Time(int pShift);
long TickVolume(int pShift);
long Volume(int pShift);
const MqlRates operator[](int index) const { return m_bars[index]; }
int Size() const { return m_barsCount; }
datetime LastBarOpen() const { return m_lastBarOpen; }
};
//+------------------------------------------------------------------+
//| Initialize |
//+------------------------------------------------------------------+
bool BarSeries::Initialize(string symbol, ENUM_TIMEFRAMES tf,
int initialBars, bool asSeries)
{
m_symbol = symbol;
m_tf = tf;
m_asSeries = asSeries;
// Reset state
m_initialized = false;
m_barsCount = 0;
m_lastBarOpen = 0;
ArrayFree(m_bars);
if(initialBars <= 0)
return false;
// Resize and set the series flag BEFORE copying so that CopyRates
// fills the array in the desired direction.
ArrayResize(m_bars, initialBars);
ArraySetAsSeries(m_bars, m_asSeries);
int copied = CopyRates(m_symbol, m_tf, 0, initialBars, m_bars);
if(copied <= 0)
{
ArrayFree(m_bars);
return false;
}
m_barsCount = copied;
// With the series flag set, the latest bar is always at index 0
// if m_asSeries == true, otherwise at index copied-1.
m_lastBarOpen = (m_asSeries) ? m_bars[0].time : m_bars[copied-1].time;
m_initialized = true;
return true;
}
//+------------------------------------------------------------------+
//| Update – refresh with the most recent barsCount candles |
//+------------------------------------------------------------------+
bool BarSeries::Update(int barsCount = 3)
{
if(!m_initialized)
return false;
if(barsCount <= 0)
return false;
// Temporary array with the same series direction as m_bars
MqlRates rates[];
ArrayResize(rates, barsCount);
ArraySetAsSeries(rates, m_asSeries);
int copied = CopyRates(m_symbol, m_tf, 0, barsCount, rates);
if(copied != barsCount)
return false;
// Identify the latest bar time in the freshly copied data
datetime newLastBarOpen = (m_asSeries) ? rates[0].time : rates[copied-1].time;
// If the latest bar hasn't changed, no new bar has formed
if(newLastBarOpen == m_lastBarOpen)
return false;
// Replace internal buffer, preserving series flag
ArrayFree(m_bars);
ArrayResize(m_bars, copied);
ArraySetAsSeries(m_bars, m_asSeries);
// Copy element by element – safest with series flags
for(int i = 0; i < copied; i++)
m_bars[i] = rates[i];
m_barsCount = copied;
m_lastBarOpen = newLastBarOpen;
return true;
}
//+------------------------------------------------------------------+
//| Accessor helpers |
//+------------------------------------------------------------------+
double BarSeries::Close(int pShift)
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
return m_bars[pShift].close;
}
double BarSeries::High(int pShift)
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
return m_bars[pShift].high;
}
double BarSeries::Low(int pShift)
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
return m_bars[pShift].low;
}
double BarSeries::Open(int pShift)
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
return m_bars[pShift].open;
}
datetime BarSeries::Time(int pShift)
{
if(pShift < 0 || pShift >= m_barsCount) return 0;
return m_bars[pShift].time;
}
long BarSeries::TickVolume(int pShift)
{
if(pShift < 0 || pShift >= m_barsCount) return 0;
return m_bars[pShift].tick_volume;
}
long BarSeries::Volume(int pShift)
{
if(pShift < 0 || pShift >= m_barsCount) return 0;
return m_bars[pShift].real_volume;
}
//+------------------------------------------------------------------+