//+------------------------------------------------------------------+ //| TimeHelpers.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 "../Configs/SymbolConfig.mqh" //+------------------------------------------------------------------+ //| TimePrice.mqh | //+------------------------------------------------------------------+ struct TimePrice { int i; datetime x; double y; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Reset() { x = 0; y = 0.0; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Set(datetime timeValue, double priceValue) { x = timeValue; y = priceValue; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Set(int index, datetime timeValue, double priceValue) { i = index; x = timeValue; y = priceValue; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Set(TimePrice &tp) { Set(tp.i, tp.x, tp.y); } bool Ok() { return x > 0 && y > 0.0; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ TimePrice CenterCoord(TimePrice &p2) { if(!Ok() && !p2.Ok()) { return p2; } if(!Ok()) return p2; if(!p2.Ok()) return *this; TimePrice tp; datetime tx = x + (p2.x - x) / 2; double py = (y + p2.y) / 2.0; tp.Set(tx, py); return tp; } string ToString() { return "Time: " + TimeToString(x) + " | Price: " + DoubleToString(y); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ TimePrice Min(TimePrice &p2) { TimePrice tp; if(y <= p2.y) tp.Set(i, x, y); else tp.Set(p2.i, p2.x, p2.y); return tp; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ TimePrice Max(TimePrice &p2) { TimePrice tp; if(y >= p2.y) tp.Set(i, x, y); else tp.Set(p2.i, p2.x, p2.y); return tp; } TimePrice MaxT(TimePrice &p2) { TimePrice tp; if(x >= p2.x) tp.Set(i, x, y); else tp.Set(p2.i, p2.x, p2.y); return tp; } }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class TimeHelpers { private: datetime SubtractDays(datetime time, int days); public: TimeHelpers() {} ~TimeHelpers() {} datetime PreviousDayStart(datetime currentTime); datetime PreviousWeekStart(datetime currentTime, int weekOffset = 1); datetime FirstOfPreviousMonths(datetime currentTime, int monthsBack = 1); // Inside class TimeHelpers, add: datetime NextRelaunchTime(datetime currentTime, ENUM_TIME_FETCH_TYPE fetchType, int count); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime TimeHelpers:: SubtractDays(datetime time, int days) { MqlDateTime dt; TimeToStruct(time, dt); dt.day -= days; while(dt.day <= 0) { dt.mon--; if(dt.mon <= 0) { dt.mon = 12; dt.year--; } // Get days in the previous month MqlDateTime lastDay; lastDay.year = dt.year; lastDay.mon = dt.mon; lastDay.day = 1; lastDay.hour = 0; lastDay.min = 1; lastDay.sec = 0; datetime firstOfMonth = StructToTime(lastDay); datetime lastOfPrevMonth = firstOfMonth - 1; TimeToStruct(lastOfPrevMonth, lastDay); dt.day += lastDay.day; // add days of previous month } dt.hour = 0; dt.min = 0; dt.sec = 0; return StructToTime(dt); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime TimeHelpers:: PreviousDayStart(datetime currentTime) { return SubtractDays(currentTime, 1); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime TimeHelpers::PreviousWeekStart(datetime currentTime, int weekOffset = 1) { MqlDateTime dt; TimeToStruct(currentTime, dt); int dow = dt.day_of_week; // 0=Sunday, 1=Monday, ..., 6=Saturday int offsetToMonday; if(dow == 0) offsetToMonday = 6; // Sunday -> go back 6 days to Monday else offsetToMonday = dow - 1; // Monday=0, Tuesday=1, ... // total days to subtract: offset to Monday of current week + 7 * weekOffset int totalDays = offsetToMonday + 7 * weekOffset; return SubtractDays(currentTime, totalDays); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime TimeHelpers::FirstOfPreviousMonths(datetime currentTime, int monthsBack) { MqlDateTime dt; TimeToStruct(currentTime, dt); // 1. Go to the first day of the current month (00:00) datetime firstCurrent = SubtractDays(currentTime, dt.day - 1); // 2. Subtract monthsBack months by subtracting full months day by day for(int i = 0; i < monthsBack; i++) { // Get the last day of the previous month = firstCurrent - 1 second datetime lastPrev = firstCurrent - 1; TimeToStruct(lastPrev, dt); int daysInPrevMonth = dt.day; // day-of-month gives days count firstCurrent = SubtractDays(firstCurrent, daysInPrevMonth); } return firstCurrent; // already at 00:00 } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime TimeHelpers::NextRelaunchTime( datetime currentTime, ENUM_TIME_FETCH_TYPE fetchType, int count) { MqlDateTime dt; TimeToStruct(currentTime, dt); // Prevent invalid values if(count < 1) count = 1; dt.hour = 0; dt.min = 0; dt.sec = 0; datetime baseTime = StructToTime(dt); switch(fetchType) { //============================================================ // PREVIOUS DAY // count = 1 → tomorrow // count = 2 → 2 days from today // count = 3 → 3 days from today //============================================================ case FETCH_PREVIOUS_DAY: { return baseTime + (count * 86400); } //============================================================ // PREVIOUS WEEK // count = 1 → next Monday // count = 2 → Monday after next // count = 3 → 3 Mondays from now //============================================================ case FETCH_PREVIOUS_WEEK: { int dow = dt.day_of_week == 0 ? 7 : dt.day_of_week; // Days until next Monday int daysUntilMonday = 8 - dow; // Additional complete weeks int additionalWeeks = (count - 1) * 7; return baseTime + (daysUntilMonday + additionalWeeks) * 86400; } //============================================================ // FIRST PREVIOUS MONTH // count = 1 → first day of next month // count = 2 → first day two months from now // count = 3 → first day three months from now //============================================================ case FETCH_FIRST_PREVIOUS_MONTH: { dt.day = 1; dt.mon += count; while(dt.mon > 12) { dt.mon -= 12; dt.year++; } return StructToTime(dt); } //============================================================ default: return 0; } } //+------------------------------------------------------------------+