332 lines
9.9 KiB
MQL5
332 lines
9.9 KiB
MQL5
//+------------------------------------------------------------------+
| |
//| 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;
| |
}
| |
}
| |
//+------------------------------------------------------------------+
|