mql5/Experts/Motivated/Utils/Barsbydate.mqh

393 lines
12 KiB
MQL5

2026-06-09 05:44:15 +02:00
//+------------------------------------------------------------------+
//| CBarsbydate.mqh |
//| Based on Price.mqh (Andrew Young) |
//+------------------------------------------------------------------+
#property strict
#property copyright "Andrew Young"
#property link "http://www.expertadvisorbook.com"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CBarsbydate
{
private:
int BarCount;
string symbol;
public:
MqlRates bar[];
CBarsbydate(void);
// --- Range loading ---
// Loads bars from [fromTime .. toTime] inclusive-ish (broker availability rules apply)
int UpdateRange(string pSymbol, ENUM_TIMEFRAMES pPeriod, datetime fromTime, datetime toTime);
// Convenience:
// useMonths=true -> monthsCount means months back
// useMonths=false -> monthsCount means candle count
int UpdateFromMonthsBack(string pSymbol, ENUM_TIMEFRAMES pPeriod, int monthsCount, bool useMonths = true);
// --- Accessors ---
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);
// --- Extract arrays ---
void GetCloses(double &closes[]);
void GetOpens(double &opens[]);
void GetHighs(double &highs[]);
void GetLows(double &lows[]);
void GetTimes(datetime &times[]);
void GetVolumes(long &volumes[]);
int GetBarCount();
int IndexByTime(datetime t);
double Point();
int Size()
{
return ArraySize(bar);
}
bool UpdateLastBar(const MqlRates &rate);
bool AppendBar(const MqlRates &rate);
private:
datetime FirstOfPreviousMonths(datetime currentTime, int monthsBack);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CBarsbydate::CBarsbydate(void)
{
BarCount = 0;
// IMPORTANT:
// index 0 = oldest, index BarCount - 1 = newest.
// DO NOT ArraySetAsSeries(bar, true).
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
datetime CBarsbydate::FirstOfPreviousMonths(datetime currentTime, int monthsBack)
{
MqlDateTime dt;
TimeToStruct(currentTime, dt);
dt.mon -= monthsBack;
while(dt.mon <= 0)
{
dt.mon += 12;
dt.year--;
}
dt.day = 1;
dt.hour = 0;
dt.min = 0;
dt.sec = 0;
return StructToTime(dt);
}
//+------------------------------------------------------------------+
//| Load bars by time range |
//| bar[0] oldest, bar[count-1] newest |
//+------------------------------------------------------------------+
int CBarsbydate::UpdateRange(string pSymbol, ENUM_TIMEFRAMES pPeriod, datetime fromTime, datetime toTime)
{
ArrayResize(bar, 0);
BarCount = 0;
symbol = pSymbol;
if(fromTime <= 0 || toTime <= 0 || toTime <= fromTime)
{
Print("CBarsbydate::UpdateRange invalid times. from=", TimeToString(fromTime),
" to=", TimeToString(toTime));
return 0;
}
MqlRates temp[];
ArraySetAsSeries(temp, false);
int copied = CopyRates(pSymbol, pPeriod, fromTime, toTime, temp);
if(copied <= 0)
{
Print("CBarsbydate::UpdateRange CopyRates failed. err=", GetLastError(),
" from=", TimeToString(fromTime), " to=", TimeToString(toTime));
return 0;
}
ArrayResize(bar, copied);
for(int i = 0; i < copied; i++)
bar[i] = temp[i];
BarCount = copied;
return copied;
}
//+------------------------------------------------------------------+
//| Convenience: |
//| useMonths=true -> monthsCount means months back |
//| useMonths=false -> monthsCount means candle count |
//+------------------------------------------------------------------+
int CBarsbydate::UpdateFromMonthsBack(string pSymbol, ENUM_TIMEFRAMES pPeriod, int monthsCount, bool useMonths = true)
{
symbol = pSymbol;
if(monthsCount <= 0)
{
Print("CBarsbydate::UpdateFromMonthsBack invalid monthsCount=", monthsCount);
ArrayResize(bar, 0);
BarCount = 0;
return 0;
}
ArrayResize(bar, 0);
BarCount = 0;
if(useMonths)
{
datetime toTime = TimeCurrent();
datetime fromTime = FirstOfPreviousMonths(toTime, monthsCount);
return UpdateRange(pSymbol, pPeriod, fromTime, toTime);
}
MqlRates temp[];
ArraySetAsSeries(temp, false);
int copied = CopyRates(pSymbol, pPeriod, 0, monthsCount, temp);
if(copied <= 0)
{
Print("CBarsbydate::UpdateFromMonthsBack CopyRates by count failed. err=", GetLastError(),
" count=", monthsCount);
return 0;
}
ArrayResize(bar, copied);
for(int i = 0; i < copied; i++)
bar[i] = temp[i];
BarCount = copied;
return copied;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CBarsbydate::Point()
{
return SymbolInfoDouble(symbol, SYMBOL_POINT);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CBarsbydate::GetBarCount(void)
{
return BarCount;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CBarsbydate::Close(int pShift)
{
if(pShift < 0 || pShift >= BarCount)
return 0.0;
return bar[pShift].close;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CBarsbydate::High(int pShift)
{
if(pShift < 0 || pShift >= BarCount)
return 0.0;
return bar[pShift].high;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CBarsbydate::Low(int pShift)
{
if(pShift < 0 || pShift >= BarCount)
return 0.0;
return bar[pShift].low;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double CBarsbydate::Open(int pShift)
{
if(pShift < 0 || pShift >= BarCount)
return 0.0;
return bar[pShift].open;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
datetime CBarsbydate::Time(int pShift)
{
if(pShift < 0 || pShift >= BarCount)
return 0;
return bar[pShift].time;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
long CBarsbydate::TickVolume(int pShift)
{
if(pShift < 0 || pShift >= BarCount)
return 0;
return bar[pShift].tick_volume;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
long CBarsbydate::Volume(int pShift)
{
if(pShift < 0 || pShift >= BarCount)
return 0;
return bar[pShift].real_volume;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBarsbydate::GetCloses(double &closes[])
{
ArrayResize(closes, BarCount);
for(int i = 0; i < BarCount; i++)
closes[i] = bar[i].close;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBarsbydate::GetOpens(double &opens[])
{
ArrayResize(opens, BarCount);
for(int i = 0; i < BarCount; i++)
opens[i] = bar[i].open;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBarsbydate::GetHighs(double &highs[])
{
ArrayResize(highs, BarCount);
for(int i = 0; i < BarCount; i++)
highs[i] = bar[i].high;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBarsbydate::GetLows(double &lows[])
{
ArrayResize(lows, BarCount);
for(int i = 0; i < BarCount; i++)
lows[i] = bar[i].low;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBarsbydate::GetTimes(datetime &times[])
{
ArrayResize(times, BarCount);
for(int i = 0; i < BarCount; i++)
times[i] = bar[i].time;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CBarsbydate::GetVolumes(long &volumes[])
{
ArrayResize(volumes, BarCount);
for(int i = 0; i < BarCount; i++)
volumes[i] = bar[i].tick_volume;
}
//+------------------------------------------------------------------+
//| Index by exact time match |
//| Returns index in bar[] (0 oldest) or -1 |
//+------------------------------------------------------------------+
int CBarsbydate::IndexByTime(datetime t)
{
if(t == 0 || BarCount == 0)
return -1;
for(int i = 0; i < BarCount; i++)
{
if(bar[i].time == t)
return i;
}
return -1;
}
//+------------------------------------------------------------------+
//| Replace current newest bar if time matches |
//+------------------------------------------------------------------+
bool CBarsbydate::UpdateLastBar(const MqlRates &rate)
{
if(BarCount <= 0)
return false;
int last = BarCount - 1;
if(bar[last].time != rate.time)
return false;
bar[last] = rate;
return true;
}
//+------------------------------------------------------------------+
//| Append a newer bar |
//+------------------------------------------------------------------+
bool CBarsbydate::AppendBar(const MqlRates &rate)
{
if(BarCount > 0)
{
int last = BarCount - 1;
if(rate.time < bar[last].time)
return false;
if(rate.time == bar[last].time)
{
bar[last] = rate;
return true;
}
}
int newSize = BarCount + 1;
int resized = ArrayResize(bar, newSize);
if(resized != newSize)
return false;
bar[newSize - 1] = rate;
BarCount = newSize;
return true;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+