//+------------------------------------------------------------------+ //| 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" // 1. Sage Smoke – pale dry sage color bull01 = C'153,163,152'; // 2. Dusted Teal – soft, greyed teal color bull02 = C'118,138,135'; // 3. Faded Sky – muted stone blue color bull03 = C'125,139,154'; // 4. Lichen – dry, earthy olive‑grey color bull04 = C'133,142,119'; // 5. Patina Copper – dull verdigris color bull05 = C'111,135,125'; // 6. Ash Pine – cool, ashy green color bull06 = C'104,120,108'; // 7. Smoke Blue – powdery, low saturation color bull07 = C'130,143,158'; // 8. Silver Pine – grey‑green with a cool hint color bull08 = C'147,157,145'; // 9. Driftwood Green – soft, beach‑worn color bull09 = C'138,150,135'; //10. Pewter Mint – extremely muted mint color bull10 = C'122,135,127'; //11. Ash Rose – pale, dusty mauve‑pink color bear01 = C'172,153,153'; //12. Terra Cotta Ash – muted sun‑baked earth color bear02 = C'173,140,124'; //13. Faded Plum – low‑chroma dusty violet color bear03 = C'144,127,136'; //14. Dusty Coral – faded seashell pink color bear04 = C'169,143,136'; //15. Warm Stone – soft beige with rose undertone color bear05 = C'163,151,144'; //16. Antique Mauve – vintage, velvety grey‑mauve color bear06 = C'142,120,126'; //17. Sandstone Blush – subtle salmon‑brown color bear07 = C'158,130,122'; //18. Dusk Lilac – very muted lavender‑grey color bear08 = C'150,140,149'; //19. Rustic Rose – dry, almost earthy rose color bear09 = C'148,122,118'; //20. Burned Clay – dark, muted terracotta color bear10 = C'140,112,105'; //+------------------------------------------------------------------+ //| 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, int daysOffset = 1); 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);//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int DaysInMonth(int year, int month) { static int days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; if(month == 2) { // Leap year check if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) return 29; } return days[month - 1]; } }; datetime TimeHelpers::SubtractDays(datetime time, int days) { MqlDateTime dt; TimeToStruct(time, dt); dt.day -= days; // Normalize the date by moving back through months while(dt.day <= 0) { dt.mon--; if(dt.mon <= 0) { dt.mon = 12; dt.year--; } dt.day += DaysInMonth(dt.year, dt.mon); } dt.hour = 0; dt.min = 0; dt.sec = 0; return StructToTime(dt); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime TimeHelpers:: PreviousDayStart(datetime currentTime, int daysOffset = 1) { return SubtractDays(currentTime, daysOffset); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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; } } //+------------------------------------------------------------------+