mql5/Experts/_FrameWork/Market/TimeHelpers.mqh

373 lines
11 KiB
MQL5

2026-09-30 09:06:59 +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"
#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;
}
}
//+------------------------------------------------------------------+