mql5/Experts/_Architecture/Market/TimeHelpers.mqh

332 lines
9.9 KiB
MQL5

2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
//| 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"
2026-08-09 07:14:59 +02:00
#include "../Configs/SymbolConfig.mqh"
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
2026-08-09 07:14:59 +02:00
//| TimePrice.mqh |
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
2026-08-09 07:14:59 +02:00
struct TimePrice
2026-08-04 23:54:09 +02:00
{
2026-08-09 07:14:59 +02:00
int i;
datetime x;
double y;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-08-04 23:54:09 +02:00
2026-08-09 07:14:59 +02:00
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;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
2026-08-04 23:54:09 +02:00
2026-08-09 07:14:59 +02:00
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;
}
2026-08-14 16:18:08 +02:00
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;
}
2026-08-06 00:18:27 +02:00
};
2026-08-09 07:14:59 +02:00
//+------------------------------------------------------------------+
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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);
2026-08-09 07:14:59 +02:00
// Inside class TimeHelpers, add:
2026-08-14 16:18:08 +02:00
datetime NextRelaunchTime(datetime currentTime, ENUM_TIME_FETCH_TYPE fetchType, int count);
2026-08-04 23:54:09 +02:00
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
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;
2026-08-06 00:18:27 +02:00
lastDay.min = 1;
2026-08-04 23:54:09 +02:00
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
}
//+------------------------------------------------------------------+
2026-08-09 07:14:59 +02:00
//| |
2026-08-04 23:54:09 +02:00
//+------------------------------------------------------------------+
2026-08-09 07:14:59 +02:00
datetime TimeHelpers::NextRelaunchTime(
datetime currentTime,
ENUM_TIME_FETCH_TYPE fetchType,
int count)
2026-08-14 16:18:08 +02:00
{
2026-08-09 07:14:59 +02:00
MqlDateTime dt;
TimeToStruct(currentTime, dt);
2026-08-14 16:18:08 +02:00
// Prevent invalid values
2026-08-10 20:23:58 +02:00
if(count < 1)
count = 1;
2026-08-09 07:14:59 +02:00
dt.hour = 0;
dt.min = 0;
dt.sec = 0;
2026-08-10 20:23:58 +02:00
datetime baseTime = StructToTime(dt);
2026-08-09 07:14:59 +02:00
switch(fetchType)
2026-08-14 16:18:08 +02:00
{
2026-08-10 20:23:58 +02:00
//============================================================
// PREVIOUS DAY
// count = 1 → tomorrow
// count = 2 → 2 days from today
// count = 3 → 3 days from today
//============================================================
2026-08-09 07:14:59 +02:00
case FETCH_PREVIOUS_DAY:
2026-08-14 16:18:08 +02:00
{
2026-08-10 20:23:58 +02:00
return baseTime + (count * 86400);
2026-08-14 16:18:08 +02:00
}
2026-08-09 07:14:59 +02:00
2026-08-10 20:23:58 +02:00
//============================================================
// PREVIOUS WEEK
// count = 1 → next Monday
// count = 2 → Monday after next
// count = 3 → 3 Mondays from now
//============================================================
2026-08-09 07:14:59 +02:00
case FETCH_PREVIOUS_WEEK:
2026-08-14 16:18:08 +02:00
{
2026-08-09 07:14:59 +02:00
int dow = dt.day_of_week == 0 ? 7 : dt.day_of_week;
2026-08-10 20:23:58 +02:00
// Days until next Monday
int daysUntilMonday = 8 - dow;
// Additional complete weeks
int additionalWeeks = (count - 1) * 7;
return baseTime
+ (daysUntilMonday + additionalWeeks) * 86400;
2026-08-14 16:18:08 +02:00
}
2026-08-09 07:14:59 +02:00
2026-08-10 20:23:58 +02:00
//============================================================
// 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
//============================================================
2026-08-09 07:14:59 +02:00
case FETCH_FIRST_PREVIOUS_MONTH:
2026-08-14 16:18:08 +02:00
{
2026-08-09 07:14:59 +02:00
dt.day = 1;
2026-08-10 20:23:58 +02:00
dt.mon += count;
while(dt.mon > 12)
2026-08-14 16:18:08 +02:00
{
2026-08-10 20:23:58 +02:00
dt.mon -= 12;
2026-08-09 07:14:59 +02:00
dt.year++;
2026-08-14 16:18:08 +02:00
}
2026-08-09 07:14:59 +02:00
return StructToTime(dt);
2026-08-14 16:18:08 +02:00
}
2026-08-09 07:14:59 +02:00
2026-08-10 20:23:58 +02:00
//============================================================
2026-08-09 07:14:59 +02:00
default:
return 0;
2026-08-14 16:18:08 +02:00
}
}
//+------------------------------------------------------------------+