2026-03-04 17:09:32 +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;
|
2026-03-15 02:46:38 +02:00 | | | string symbol;
|
2026-03-04 17:09:32 +02:00 | | |
|
| | | 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: from 1st of month N months back -> now
|
| | | int UpdateFromMonthsBack(string pSymbol, ENUM_TIMEFRAMES pPeriod, int monthsBack);
|
| | |
|
| | | // --- 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 ×[]);
|
| | | void GetVolumes(long &volumes[]);
|
| | |
|
| | | int GetBarCount();
|
| | | int IndexByTime(datetime t);
|
2026-03-15 02:46:38 +02:00 | | | double Point();
|
| | | int Size() {
|
| | | return ArraySize(bar);
|
| | | }
|
2026-03-04 17:09:32 +02:00 | | |
|
| | | private:
|
| | | datetime FirstOfPreviousMonths(datetime currentTime, int monthsBack);
|
| | | };
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CBarsbydate::CBarsbydate(void) {
|
| | | BarCount = 0;
|
| | |
|
| | | // IMPORTANT: you said no series for this project:
|
| | | // index 0 = oldest, index BarCount-1 = newest.
|
| | | // So 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;
|
2026-03-15 02:46:38 +02:00 | | | symbol = pSymbol;
|
2026-03-04 17:09:32 +02:00 | | |
|
| | | if(fromTime <= 0 || toTime <= 0 || toTime <= fromTime) {
|
| | | Print("CBarsbydate::UpdateRange invalid times. from=", TimeToString(fromTime),
|
| | | " to=", TimeToString(toTime));
|
| | | return 0;
|
| | | }
|
| | |
|
| | | int copied = CopyRates(pSymbol, pPeriod, fromTime, toTime, bar);
|
| | | if(copied <= 0) {
|
| | | Print("CBarsbydate::UpdateRange CopyRates failed. err=", GetLastError(),
|
| | | " from=", TimeToString(fromTime), " to=", TimeToString(toTime));
|
| | | return 0;
|
| | | }
|
| | |
|
| | | BarCount = copied;
|
| | | return copied;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Convenience: from 1st of month N months back -> now |
|
| | | //+------------------------------------------------------------------+
|
| | | int CBarsbydate::UpdateFromMonthsBack(string pSymbol, ENUM_TIMEFRAMES pPeriod, int monthsBack) {
|
| | | datetime toTime = TimeCurrent();
|
| | | datetime fromTime = FirstOfPreviousMonths(toTime, monthsBack);
|
| | | return UpdateRange(pSymbol, pPeriod, fromTime, toTime);
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-03-15 02:46:38 +02:00 | | | double CBarsbydate::Point() {
|
| | | return SymbolInfoDouble(symbol, SYMBOL_POINT);
|
2026-03-04 17:09:32 +02:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | 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 ×[]) {
|
| | | 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;
|
| | | }
|
| | | //+------------------------------------------------------------------+
|