373 lines
11 KiB
MQL5
373 lines
11 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"
| |
| |
// 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;
| |
}
| |
}
| |
//+------------------------------------------------------------------+
|