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;
| |||
}
| |||
}
| |||
//+------------------------------------------------------------------+
|