194 lines
16 KiB
MQL5
194 lines
16 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| TimeSummer.mq5 |
|
|
//| Copyright 2021, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\..\Include\PRTF.mqh"
|
|
#include "..\..\Include\DateTime.mqh"
|
|
|
|
#include <TimeZoneInfo.mqh>
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Server time zone and DST information |
|
|
//+------------------------------------------------------------------+
|
|
struct ServerTime
|
|
{
|
|
int offsetGMT; // time zone offset in seconds against UTC/GMT
|
|
int offsetDST; // DST correction in seconds (included in offsetGMT)
|
|
bool supportDST; // DST changes are detected in the quotes
|
|
string description; // textual explanation of result
|
|
};
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Estimate server time zone and DST mode from H1 quotes history |
|
|
//+------------------------------------------------------------------+
|
|
ServerTime ServerTimeZone(const string symbol = NULL)
|
|
{
|
|
const int year = 365 * 24 * 60 * 60;
|
|
datetime array[];
|
|
if(PRTF(CopyTime(symbol, PERIOD_H1, TimeCurrent() - year, TimeCurrent(), array)) > 0)
|
|
{
|
|
// approx. 6000 bars should be acquired here
|
|
const int n = ArraySize(array);
|
|
PrintFormat("Got %d H1 bars, ~%d days", n, n / 24);
|
|
int hours[24] = {};
|
|
int current = 0;
|
|
for(int i = 0; i < n; ++i)
|
|
{
|
|
const ENUM_DAY_OF_WEEK weekday = TimeDayOfWeek(array[i]);
|
|
// skip all days except Sunday and Monday
|
|
if(weekday > MONDAY) continue;
|
|
// lets analyze the first H1 bar of the trading week
|
|
// find out an hour for the first bar after weekend
|
|
current = _TimeHour();
|
|
// collect stats for opening hours
|
|
hours[current]++;
|
|
// now skip 2 days to check next week
|
|
i += 48;
|
|
}
|
|
Print("Week opening hours stats:");
|
|
ArrayPrint(hours);
|
|
if(hours[current] <= 52 / 4)
|
|
{
|
|
// TODO: refine results using previous weeks
|
|
Print("Extraordinary week detected");
|
|
}
|
|
// find most often time shift
|
|
int max = ArrayMaximum(hours);
|
|
// now check if a secondary time shift was also happened
|
|
hours[max] = 0;
|
|
int sub = ArrayMaximum(hours);
|
|
// result variable init
|
|
ServerTime st = {};
|
|
int DST = 0;
|
|
// winter/summer periods are not equal!
|
|
// summer time can be 8 months per year
|
|
// 52 is the full year in weeks
|
|
if(hours[sub] > 52 / 4) // DST is supported
|
|
{
|
|
if(current == max || current == sub)
|
|
{
|
|
if(current == MathMin(max, sub))
|
|
DST = fabs(max - sub); // DST is enabled now
|
|
}
|
|
st.supportDST = true;
|
|
}
|
|
current += 2 + DST; // +2 to get UTC offset
|
|
// NB. when DST is enabled, time is shifted forward in the time zone,
|
|
// but for outside it is looked like the time is shifted back
|
|
// (everything in this time zone is happened earlier for others)
|
|
// so to get standard time of the zone we need to add DST
|
|
current %= 24;
|
|
// time zones are in the range [UTC-12,UTC+12]
|
|
if(current > 12) current = current - 24;
|
|
current += DST; // if DST is enabled it's shown in offsetGMT according to MT5 rules
|
|
st.description = StringFormat("Server time offset: UTC%+d, including DST%+d", current, DST);
|
|
st.offsetGMT = -current * 3600;
|
|
st.offsetDST = -DST * 3600;
|
|
return st;
|
|
}
|
|
ServerTime empty = {-INT_MAX, -INT_MAX, false};
|
|
return empty;
|
|
}
|
|
|
|
|
|
#define HOUR 3600
|
|
#define DAY (24 * HOUR)
|
|
#define WEEK 7
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
datetime GetBarTime(const datetime time, const bool NextBar = false, string Symb = NULL, const ENUM_TIMEFRAMES TimeFrame = PERIOD_M1)
|
|
{
|
|
if (Symb == NULL)
|
|
Symb = _Symbol;
|
|
return(iTime(Symb, TimeFrame, iBarShift(Symb, TimeFrame, time) - (NextBar ? 1 : 0)));
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
datetime GetTimeDayOfWeek(const int Shift = 0, const ENUM_DAY_OF_WEEK Day = SUNDAY)
|
|
{
|
|
const datetime Res = TimeCurrent() / DAY * DAY;
|
|
return(Res - (((WEEK + (TimeDayOfWeek(Res) - Day)) % WEEK) + Shift * WEEK) * DAY);
|
|
}
|
|
// Аналог по серверному времени - https://www.mql5.com/ru/docs/dateandtime/timegmtoffset
|
|
// Работает для FOREX-символов, когда M1-история доступна за ближайшую неделю
|
|
int TimeServerGMTOffset( void )
|
|
{
|
|
const datetime Sunday = GetTimeDayOfWeek();
|
|
return(((int)MathRound((double)MathMin(Sunday - DAY - GetBarTime(Sunday), Sunday + DAY - GetBarTime(Sunday, true)) / HOUR) - 3) * HOUR);
|
|
}
|
|
// Аналог по серверному времени - https://www.mql5.com/ru/docs/dateandtime/timegmt
|
|
// Работает для FOREX-символов, когда M1-история доступна за ближайшую неделю
|
|
datetime TimeServerGMT(void)
|
|
{
|
|
return(TimeCurrent() + TimeServerGMTOffset());
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Script program start function |
|
|
//+------------------------------------------------------------------+
|
|
void OnStart()
|
|
{
|
|
//PRTF(TimeLocal());
|
|
PRTF(TimeCurrent());
|
|
//PRTF(TimeTradeServer());
|
|
PRTF(TimeGMT());
|
|
PRTF(TimeGMTOffset());
|
|
PRTF(TimeDaylightSavings());
|
|
ServerTime st = ServerTimeZone();
|
|
Print(st.description);
|
|
Print("ServerGMTOffset: ", st.offsetGMT);
|
|
Print("ServerTimeDaylightSavings: ", st.offsetDST);
|
|
Print("\n\n");
|
|
//---
|
|
//PRTF(TimeLocal());
|
|
PRTF(TimeCurrent());
|
|
//PRTF(TimeTradeServer());
|
|
PRTF(TimeGMT());
|
|
PRTF(TimeServerGMT());
|
|
Print("\n\n");
|
|
CTimeZoneInfo my_time(ZONE_ID_BROKER);
|
|
ENUM_ZONE_ID id = ZONE_ID_UTC;
|
|
PRTF(my_time.GetCurrentTimeForPlace(ZONE_ID_BROKER));
|
|
PRTF(my_time.GetCurrentTimeForPlace(ZONE_ID_UTC));
|
|
PRTF(my_time.GetCurrentTimeForPlace(ZONE_ID_LOCAL));
|
|
PRTF(my_time.ConvertTimeForPlace(TimeGMT(), ZONE_ID_UTC, ZONE_ID_BROKER));
|
|
PRTF(my_time.TimeLocal());
|
|
PRTF(my_time.TimeUTC());
|
|
PRTF(my_time.IsDaylightSavingTime(TimeCurrent() - PeriodSeconds(PERIOD_MN1) * 7, ZONE_ID_BROKER));
|
|
PRTF(my_time.IsDaylightSavingTime(TimeCurrent() - PeriodSeconds(PERIOD_MN1) * 7, ZONE_ID_UTC));
|
|
|
|
|
|
//datetime localtime = CTimeZoneInfo::GetCurrentTimeForPlace(id);
|
|
//datetime converted = CTimeZoneInfo::ConvertTimeForPlace(localtime, id, ZONE_ID_BROKER);
|
|
//PrintFormat("%-49s | %s", CTimeZoneInfo::FormatTimeForPlace(localtime, id), CTimeZoneInfo::FormatTimeForPlace(converted, ZONE_ID_BROKER));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
/*
|
|
example output MQ Demo
|
|
(WARNING: TimeGMT != ServerGMT,
|
|
because TimeGMT() - TimeCurrent() gives 3 hours difference,
|
|
whereas ServerGMTOffset is 2 hours difference;
|
|
probably DST is enabled all year round)
|
|
|
|
TimeLocal()=2021.09.09 22:06:17 / ok
|
|
TimeCurrent()=2021.09.09 22:06:10 / ok
|
|
TimeTradeServer()=2021.09.09 22:06:17 / ok
|
|
TimeGMT()=2021.09.09 19:06:17 / ok
|
|
TimeGMTOffset()=-10800 / ok
|
|
TimeDaylightSavings()=0 / ok
|
|
CopyTime(symbol,PERIOD_H1,TimeCurrent()-year,TimeCurrent(),array)=6207 / ok
|
|
Got 6207 H1 bars, ~258 days
|
|
Week opening hours stats:
|
|
52 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
Server time offset: UTC+2, including DST+0
|
|
ServerGMTOffset: -7200
|
|
ServerTimeDaylightSavings: 0
|
|
|
|
*/
|
|
//+------------------------------------------------------------------+
|