mql5/Experts/_Architecture/Market/BarSeries.mqh

168 lines
5 KiB
MQL5

2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
//| BarSeries.mqh |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
2026-08-14 16:18:08 +02:00
#property version "1.10"
2026-08-04 23:54:09 +02:00
class BarSeries
2026-08-14 16:18:08 +02:00
{
2026-08-04 23:54:09 +02:00
private:
2026-08-06 00:18:27 +02:00
string m_symbol;
ENUM_TIMEFRAMES m_tf;
MqlRates m_bars[];
int m_barsCount;
datetime m_lastBarOpen;
bool m_initialized;
2026-08-14 16:18:08 +02:00
bool m_asSeries; // true = index 0 is the most recent bar
2026-08-06 00:18:27 +02:00
2026-08-04 23:54:09 +02:00
public:
2026-08-14 16:18:08 +02:00
BarSeries() : m_symbol(""), m_tf(PERIOD_CURRENT), m_barsCount(0),
m_lastBarOpen(0), m_initialized(false), m_asSeries(true) {}
~BarSeries() {}
2026-08-06 00:18:27 +02:00
2026-08-14 16:18:08 +02:00
bool Initialize(string symbol, ENUM_TIMEFRAMES tf, int initialBars, bool asSeries = true);
bool Update(int barsCount = 3);
2026-08-06 00:18:27 +02:00
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; }
2026-08-14 16:18:08 +02:00
};
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
//| Initialize |
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
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.
2026-08-06 00:18:27 +02:00
ArrayResize(m_bars, initialBars);
2026-08-14 16:18:08 +02:00
ArraySetAsSeries(m_bars, m_asSeries);
2026-08-06 00:18:27 +02:00
2026-08-14 16:18:08 +02:00
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;
}
2026-08-06 00:18:27 +02:00
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
//| Update – refresh with the most recent barsCount candles |
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
2026-08-06 00:18:27 +02:00
bool BarSeries::Update(int barsCount = 3)
2026-08-14 16:18:08 +02:00
{
2026-08-06 00:18:27 +02:00
if(!m_initialized)
return false;
2026-08-14 16:18:08 +02:00
if(barsCount <= 0)
return false;
// Temporary array with the same series direction as m_bars
2026-08-06 00:18:27 +02:00
MqlRates rates[];
ArrayResize(rates, barsCount);
2026-08-14 16:18:08 +02:00
ArraySetAsSeries(rates, m_asSeries);
2026-08-06 00:18:27 +02:00
int copied = CopyRates(m_symbol, m_tf, 0, barsCount, rates);
2026-08-14 16:18:08 +02:00
if(copied != barsCount)
2026-08-06 00:18:27 +02:00
return false;
2026-08-14 16:18:08 +02:00
// Identify the latest bar time in the freshly copied data
datetime newLastBarOpen = (m_asSeries) ? rates[0].time : rates[copied-1].time;
2026-08-06 00:18:27 +02:00
2026-08-14 16:18:08 +02:00
// 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);
2026-08-06 00:18:27 +02:00
ArrayResize(m_bars, copied);
2026-08-14 16:18:08 +02:00
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;
2026-08-06 00:18:27 +02:00
return true;
2026-08-14 16:18:08 +02:00
}
2026-08-09 07:14:59 +02:00
2026-08-06 00:18:27 +02:00
//+------------------------------------------------------------------+
2026-08-14 16:18:08 +02:00
//| Accessor helpers |
2026-08-06 00:18:27 +02:00
//+------------------------------------------------------------------+
double BarSeries::Close(int pShift)
2026-08-14 16:18:08 +02:00
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
2026-08-06 00:18:27 +02:00
return m_bars[pShift].close;
2026-08-14 16:18:08 +02:00
}
2026-08-06 00:18:27 +02:00
double BarSeries::High(int pShift)
2026-08-14 16:18:08 +02:00
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
2026-08-06 00:18:27 +02:00
return m_bars[pShift].high;
2026-08-14 16:18:08 +02:00
}
2026-08-06 00:18:27 +02:00
double BarSeries::Low(int pShift)
2026-08-14 16:18:08 +02:00
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
2026-08-06 00:18:27 +02:00
return m_bars[pShift].low;
2026-08-14 16:18:08 +02:00
}
2026-08-06 00:18:27 +02:00
double BarSeries::Open(int pShift)
2026-08-14 16:18:08 +02:00
{
if(pShift < 0 || pShift >= m_barsCount) return 0.0;
2026-08-06 00:18:27 +02:00
return m_bars[pShift].open;
2026-08-14 16:18:08 +02:00
}
2026-08-06 00:18:27 +02:00
datetime BarSeries::Time(int pShift)
2026-08-14 16:18:08 +02:00
{
if(pShift < 0 || pShift >= m_barsCount) return 0;
2026-08-06 00:18:27 +02:00
return m_bars[pShift].time;
2026-08-14 16:18:08 +02:00
}
2026-08-06 00:18:27 +02:00
long BarSeries::TickVolume(int pShift)
2026-08-14 16:18:08 +02:00
{
if(pShift < 0 || pShift >= m_barsCount) return 0;
2026-08-06 00:18:27 +02:00
return m_bars[pShift].tick_volume;
2026-08-14 16:18:08 +02:00
}
2026-08-06 00:18:27 +02:00
long BarSeries::Volume(int pShift)
2026-08-14 16:18:08 +02:00
{
if(pShift < 0 || pShift >= m_barsCount) return 0;
2026-08-06 00:18:27 +02:00
return m_bars[pShift].real_volume;
2026-08-14 16:18:08 +02:00
}
//+------------------------------------------------------------------+