Работаем со временем (Часть 2): Функции
Глобальные переменные
Вместо того, чтобы обращаться к брокеру, который скорее всего даст недостаточно полный ответ (а кто захочет объяснять, куда пропал торговый час?), мы сами посмотрим, по какому времени приходят от них котировки в те недели, когда переводят часы. Но конечно же, это мы будем делать не вручную — пусть за нас работает программа.
В этой статье мы продолжим работать с include-файлом DealingWithTime.mqh, с которым работали в первой части. В этом файле до функций и после макро-подстановок идут необходимые переменные, которые объявлены как глобальные переменные:
//--- глобальные переменные для смены времени int DST_USD=0, // фактическое смещение времени для США DST_EUR=0, // фактическое смещение времени для Европы DST_AUD=0, // фактическое смещение времени для Австралии DST_RUS=0; // D'2014.10.26 02:00', -10800,
Эти переменные DST_USD, DST_EUR, и т.д. будут принимать фактическое значение смещения времени в соответствующих странах и регионах — США, Европа и т.д. Значения переменных будут заполняться функциями. В нормальное зимнее время значения равны нулю: время в этот период не смещается.
Далее у нас идут переменные с датой предстоящего перевода часов. Они указывают, когда нужно будет рассчитывать новые значения переменных, чтобы не проводить ненужные расчеты до этого и не тратить вычислительные ресурсы:
datetime nxtSwitch_USD, // дата следующего перехода nxtSwitch_EUR, // дата следующего перехода nxtSwitch_AUD, // дата следующего перехода nxtSwitch_RUB = D'2014.10.26 02:00'; // для России по-другому :(
Тут есть небольшое отличие в настройках для России, мы рассмотрим ее чуть позже.
Данная структура и ее глобальная переменная являются сердцем всей программы. :)
struct _OffsetBroker { int USwinEUwin, // US=Winter & EU=Winter USsumEUsum, // US=Summer & EU=Summer USsumEUwin, // US=Summer & EU=Winter actOffset, // фактическое смещение времени брокера secFxWiWi, // продолжительность работы рынка в сек secFxSuSu, // продолжительность работы рынка в сек secFxSuWi, // продолжительность работы рынка в сек actSecFX; // фактическая продолжительность работы рынка в сек bool set; // вес установили? }; _OffsetBroker OffsetBroker;
Задаем значения смещения у брокера для трех соответствующих периодов, а также продолжительность работы рынка в эти периоды. Также пишем фактическое значение продолжительности и проверяем, установлены ли все необходимые значения. Название глобальной переменной — OffsetBroker, мы встретим ее несколько раз.
Основная функция для определения перевода часов у брокера
С помощью функции
setBokerOffset();
советник, индикатор или скрипт сможет самостоятельно определить, когда у брокера происходит перевод часов и как. Она добавлена в начало кода в приложенном скрипте, после функции Start(). Она определяет эти значения у брокера для соответствующих периодов (летнее время, зимнее время и промежуточное время), на основе которых определяются все остальные значения времени. Эта функция, как и все другие, что мы рассматривали в первой статье, содержатся в файле. После объявления переменных, инициализации и обнуления соответствующих глобальных переменных:
datetime dateEUR,dateUSD,dateAUD,dateNxt, // дата переходя для EU, AU и US arrTme[]; // массив для копирования времени int b; OffsetBroker.USsumEUwin = OffsetBroker.USsumEUsum = OffsetBroker.USwinEUwin = INT_MIN; nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0; // сбросить переменные
получаем выходные, когда переводят часы:
//--- переход на зимнее время в Австралии, Европе и США в 2020 if(IS_DEBUG_MODE) Print("\n2nd half-year 2020 for ",AccountInfoString(ACCOUNT_COMPANY), "DebugMode: ",IS_DEBUG_MODE); nextDST("EUR", D'2020.06.21 14:00'); // EUR: получаем DST и устанавливаем дату след перехода b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_EUR,1,arrTme); // получаем время последнего бара H1 перед переводом часов в Европе dateEUR = arrTme[0]; // последний час работы в пятницу перед выходными nextDST("USD", D'2020.06.21 14:00'); // USD: получаем DST и устанавливаем дату след перехода b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_USD,1,arrTme); // получаем время последнего бара H1 перед переводом часов в США dateUSD = arrTme[0]; // последний час работы в пятницу перед выходными nextDST("AUD", D'2020.06.21 14:00'); // AUD: получаем DST и устанавливаем дату след перехода b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_AUD,1,arrTme); // получаем время последнего бара H1 перед переводом часов в Австралии dateAUD = arrTme[0]; // последний час работы в пятницу перед выходными dateNxt = fmax(nxtSwitch_EUR,nxtSwitch_USD)+WeekInSec; // получаем след выходные b = CopyTime("EURUSD",PERIOD_H1,dateNxt,1,arrTme); // получаем время последнего бара H1 перед выходными dateNxt = arrTme[0]; // последний час работы в пятницу перед выходными
Для простоты большая часть выполняется автоматически в режиме отладки: if(IS_DEBUG_MODE). Таким образом, если запустить скрипт в режиме отладки (F5), можно посмотреть все детали, а если запустить его прямо на графике, будут показано только самое важное.
Для всех трех часовых поясов вызов функции, например nextDST("EUR", D'2020.06.21 14:00'), сначала рассчитывает соответствующие разницы во времени для Европы, а потом — следующих перевод часов. Июнь попадает на летнее время, а следующий переход будет на зимнее время. Следующей строкой получаем время открытия последнего часового бара H1 в пятницу, предшествующую этим выходным — это будет основа для наших расчетов. См. пункт 4 предположений в конце первой статьи:
4. Если отсутствует какие-либо часы между 17:00 в пятницу и 17:00 в воскресенье, тогда будет не хватать котировок воскресенья до получения самой первой котировки, а не последних котировок пятницы.
Я решил использовать время H1 и EURUSD. У этого символа, пожалуй, самая длинная история котировок. Поэтому, если торговля на рынке закрывается в 17:00 по Нью-Йорку, последний рабочий час (или последняя часовая свеча) открывается в 16:00. Именно этот час нас и интересует. Получается, что первый час после выходных — 17:00 воскресенья в Нью-Йорке. Для полноты картины также определим смену часов в Австралии, однако использовать его не будем. Далее, в первые выходные после смены часов, определяем время следующего перевода часов.
Затем используется функция chckFriday(...) для расчета смещения времени брокера в соответствии с выбранным периодом. Расчет происходит основе времени 16:00 по Нью-Йорку. Функция также включена в include-файл.
chckFriday(dateEUR,"EUR"); // функция определения смещения брокера для указанной пятницы chckFriday(dateUSD,"USD"); // функция определения смещения брокера для указанной пятницы chckFriday(dateNxt,"NXT"); // функция определения смещения брокера для указанной пятницы
По тому же принципу рассчитываются оставшиеся смены часов для второго полугодия, которые нам, собственно, не нужны, и которые можно закомментировать:
if(IS_DEBUG_MODE) Print("\n1st half-year 2021 for ",AccountInfoString(ACCOUNT_COMPANY), "DebugMode: ",IS_DEBUG_MODE); nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0; nextDST("AUD", D'2021.01.21 14:00'); // AUD: получаем DST и устанавливаем дату след перехода b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_AUD,1,arrTme); // получаем время последнего бара H1 перед переводом часов в Европе dateAUD = arrTme[0]; // последний час работы в пятницу перед выходными ... chckFriday(dateUSD,"USD"); // функция определения смещения брокера для указанной пятницы chckFriday(dateEUR,"EUR"); // функция определения смещения брокера для указанной пятницы chckFriday(dateNxt,"NXT"); // функция определения смещения брокера для указанной пятницы
Наконец после того, как определили сдвиг времени брокера и присвоили значения соответствующим полям, значения перевода часов (nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0) обнуляются для последующего использования. И хотя перерасчет должен быть только в том случае, если в ходе истории "случались" выходные с переводом часов, все же лучше сбросить заранее, чтобы потом не забыть. Затем проверяем, заданы ли все необходимые переменные. Результат выводится в журнал экспертов:
nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0; // сбросим все переменные if(OffsetBroker.USsumEUwin != INT_MIN && OffsetBroker.USsumEUsum != INT_MIN && OffsetBroker.USwinEUwin != INT_MIN ) OffsetBroker.set = true; else OffsetBroker.set = false; if(OffsetBroker.set) Print("\nTime Offset of ",AccountInfoString(ACCOUNT_COMPANY),": ", "\nUS=Winter & EU=Winter (USwinEUwin) = ",OffsetBroker.USwinEUwin, "\nUS=Summer & EU=Summer (USsumEUsum) = ",OffsetBroker.USsumEUsum, "\nUS=Summer & EU=Winter (USsumEUwin) = ",OffsetBroker.USsumEUwin, "\n"); else Print(__FILE__,"[",__LINE__,"] Assigning the broker offset went wrong - somehow."); return(OffsetBroker.set);
Если все хорошо, появится запись наподобие такой:
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200
Любой пользователь сможет использовать эти значения для входных переменных вместо того, чтобы добавлять функции до начала работы самого советника в тестере стратегий или в реальном времени на графике. Пример я покажу в конце статьи.
Определение и установка сдвига времени брокера
Давайте поближе посмотрим на функцию chckFriday(...). Она определяет сдвиг времени брокера в разные периоды и назначает значение соответствующему полю глобальной переменной OffsetBroker на основе структуры _OffsetBroker. В структуре три поля:
int USwinEUwin, // US=Winter & EU=Winter USsumEUsum, // US=Summer & EU=Summer USsumEUwin, // US=Summer & EU=Winter
Им назначаются значения сдвига времени брокера в соответствующие периоды. Это периоды:
- Одинаковое время для обоих регионов — или зимнее (стандартное), или летнее.
- В США уже (еще) летнее время, а в Европе еще (уже) зимнее.
Обратной ситуации, когда в США уже (еще) зимнее, а в Европе еще (уже) летнее, не существует. Возникает вопрос: почему нет четвертой категории и что с Австралией?
Вот правила перехода:
- Европа: последнее воскресенье октября и последнее воскресенье марта
- США: первое воскресенье ноября и второе воскресенье марта
- Австралия: первое воскресенье ноября и последнее воскресенье марта
Итак, что с первым вопросом. Европа переходит на зимнее время на одну-две недели раньше США: там в США еще летнее время, а в Европе уже зимнее, поэтому значение присваивается полю USsumEUwin переменной OffsetBroker. Затем весной США раньше переходит на летнее время. Получается, в США уже неделю-две летнее время, а в Европе еще зимнее. Значение так же присваивается полю USsumEUwin переменной OffsetBroker. Так что обратной ситуации, когда в Европе летнее время, а в США еще зимнее, не существует. Это фактически устраняет необходимость расчета смещения времени брокера для обоих периодов перевода часов, осенью и весной. Тем не менее мы производим расчет, просто для полноты и контроля.
Что касается второго вопроса. Австралия переводит часы в ноябре одновременно с США, а весной переводит часы как Европа. То есть нет новых выходных дней, в которые совершался бы переход. Однако часы в Австралии переводят вперед на 1 час, когда в Европе и США зима, потому что Рождество и Новый год там приходятся на лето.
Располагая временем перевода часов для определенного периода, можно также посчитать длительность работы форекс-рынка в соответствующие недели: эти значения хранятся в полях secFxWiWiВи, secFxSuSu и secFxSuWi, а текущее фактическое значение — в ActSecFX. В разделе "Применение" в конце статьи показано, что с этим делать.
Чтобы присвоить значения, их надо сначала рассчитать. После объявления переменных и сброса глобальных переменных рассчитываются значения смещения в Европе и США для выбранного времени брокера tB:
//+------------------------------------------------------------------+ //| вспомогательная функция для определения смещения времени брокера | //+------------------------------------------------------------------+ int chckFriday( datetime tB, // время брокера: последний час пятницы string cmt="" // текст для начала строки ) { int hNY, hGMT, hTC, hDiff; nxtSwitch_AUD = nxtSwitch_USD = nxtSwitch_EUR = 0; // сбрасываем nextDST("EUR",tB); // получаем смещение в Европе указанного времени tB nextDST("USD",tB); // получаем смещение в США указанного времени tB
Здесь tB — это начало последнего часа в пятницу, когда в Нью-Йорке 16:00. Это основа дальнейших расчетов, для этого времени мы можем рассчитать GMT:
tGMT = tNY + (NYShift + DST_USD)
то есть, сдвиг времени брокера по GMT. Вот как определяется сдвиг: от последнего часа в пятницу по времени tB отнимаем количество секунд, прошедших с начала дня SoB(tB). Получаем 00:00 дня, а затем добавляем количество секунд до времени 16:00 (16*3600). Так получаем время по Нью-Йорку, на основе которого рассчитываем время GMT: NYShift + DST_USD. Теперь можно легко определить смещение времени брокера от GMT, а полученное значение записать в соответствующее поле переменной OffsetBroker.
В функции расчеты идут в часах, а не секундах, с макроподстановкой HoD() (Hour of Day, час суток), чтобы было удобнее работать:
hNY = HoD(tB - SoD(tB) + 16*3600); // получаем час по Нью-Йорку hGMT = HoD(tB - SoD(tB) + 16*3600 + NYShift + DST_USD); // получаем час по GMT hTC = HoD(tB); // получаем час заданного времени hDiff = hGMT - HoD(tB); // разница между GMT и временем брокера
Не так и сложно.
Следующая часть добавлена для проверки. Он проверяет, чтобы не возникла невозможная ситуация, когда в США лето, а в Европе зима:
if(DST_USD==0 && DST_EUR!=0) // такого быть не должно Alert(__LINE__," ",TOSTR(DST_USD),TOSTR(DST_EUR)," USwin && EUsum");
Теперь можем использовать найденную разницу и продолжительность работы рынка:
//--- установим смещение брокера для различных временных ситуаций: if(DST_USD+DST_EUR==0) // оба значения в зимнем времени { OffsetBroker.actOffset = OffsetBroker.USwinEUwin = hDiff*3600; OffsetBroker.actSecFX = OffsetBroker.secFxWiWi = SoW(tB); } else if(DST_USD == DST_EUR) // оба в летнем времени { OffsetBroker.actOffset = OffsetBroker.USsumEUsum = hDiff*3600; OffsetBroker.actSecFX = OffsetBroker.secFxSuSu = SoW(tB); } else if(DST_USD!=0 && DST_EUR==0) // US:лето EU:зима { OffsetBroker.actOffset = OffsetBroker.USsumEUwin = hDiff*3600; OffsetBroker.actSecFX = OffsetBroker.secFxSuWi = SoW(tB); }
Далее записываем в журнал все найденные значения и возвращаем последнее фактическое смещение:
//--- по кругу рассчитываем NY->GMT->Broker->GMT->NY <= последнее NY должно быть всегда 16!! Print(cmt,": ",DoWs(tB),TimeToString(tB),": ",TOSTR(hNY),TOSTR(hGMT),TOSTR(hTC),TOSTR(hDiff), " BrokerTime => GMT: ",TimeToString(tB+OffsetBroker.actOffset), " => tNY: ",TimeToString((tB + OffsetBroker.actOffset)-(NYShift + DST_USD)), " End-FX after: ",OffsetBroker.actSecFX/3600,"h" ); return(OffsetBroker.actOffset);
Выглядит это следующим образом:
EUR: Fr.2020.10.23 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End FX in: 143h
USD: Fr.2020.10.30 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End FX in: 142h
NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End FX in: 143h
Давайте посмотрим, что же тут выводится. Сначала Европа переводит часы 25 октября. Через неделю, 1 ноября, часы переводят в США. В период между двумя этими датами последний час пятницы на сервере MetaQuotes начинается в 22:00, а не в 23:00, а заканчивается неделя этой свечой, то есть через 142часа вместо обычных 143. 143 или 142 часа? В неделе на рынке форекс 120 часов: 5*24=120? Секунды недели (SoW(), Seconds of Week) и похожие функции работают с календарной неделей, которая начинается в воскресенье в 00:00. Но с воскресенья 00:00 по пятницу 23:00 теперь 6* 24-1 = 143 часа. На основе это значения для любого заданного момента недели можно рассчитать оставшееся времени работы ранка до конца недели.
На основе этих трех строчек также проверяется логика и расчеты. Также можно определить местное время по Гринвичу (GMT). Слева направо: таймстамп брокера, расчетное время по Нью-Йорку, hNY: 16, час по Гринвичу на основе времени в Нью-Йорке, час времени брокера и сдвиг: -2 или -3. Во второй части расчет GMT от времени брокера (tB+OffsetBroker.actOffset), а затем на основе GMT - снова время в Нью-Йорке ((tB + OffsetBroker.actOffset)-(NYShift + DST_USD)). Значение для Нью-Йорка всегда должно получаться tNY=16:00. Ниже выполняется вторая проверка для рандомного времени в истории и для других брокеров.
Расчет выходных, когда переводят часы
Прежде чем перейти к работе со временем на истории EURUSD, давайте посмотрим на основополагающую функцию расчетов - nextDST(...).
Функция вызывается с параметром zone для часового пояса "USD", "EUR" или "AUD" (хотя по факту AUD нам и не нужно) и параметром t - текущее время, обычно это текущее время брокера TimeCurrent(). Сначала проверяем, нужен ли вообще пересчет (в данном примере для EUR):
void nextDST(string zone, datetime t) { if((zone == "EUR") && t < nxtSwitch_EUR) { if(IS_DEBUG_MODE) Print("no change as time < nxtSwitch_EUR"); return; } ...
Здесь становится понятно, почему так важно сбрасывать значения nxtSwitch_EUR в начале теста — в противном случае никаких пересчетов может не выполняться на протяжении всего теста.
После объявления переменной и инициализации подходим к сути функции. Эта функция не моя. Некоторое время назад я где-то в интернете нашел алгоритм, определяющий определенный день в месяце. Он используется для определения летнего или зимнего времени для выбранного момента. Сам по себе алгоритм несложный:
- Определяем день месяца - воскресенье, когда переводят часы.
- На основе него создаем дату.
- Находим ближайшее следующее воскресенье, когда будут переводить часы.
- Устанавливаем сдвиг, 0h или -1h, и воскресенье следующего перевода часов.
Магия этого алгоритма заключается в строке кода, которая определяет день месяца, когда переводят часы. В Европе это последнее воскресенье марта, рассчитывается так (как я уже сказала, идея формулы не моя):
d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7)); // найдем последнее воскресенье марта - переход на летнее в ЕвропеВ результате для 2021 года последнее воскресенье марта выводится как d=25:
31 - MOD(ROUNDDOWN(5*2021/4);7) = 25.
Затем формируется временная метка дня перевода часов в Европе: 25 марта 2021 г., последнее воскресенье марта:
spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // преобразуем в datetime
Все даты рассчитываются аналогичным образом.
Далее идет большой раздел кода, в котором определяется текущий переход на летнее или зимнее время и следующая дата перехода в Европе для выбранной даты. В итоге нам нужно найти три периода в году: перед первым переходом, между первым и вторым, после второго перехода. Следующий переход будет уже в следующем году, и это необходимо учитывать:
if(zone == "EUR") { d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7)); // найдем последнее воскресенье марта - переход на летнее в Европе spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // преобразуем в datetime if(t < spr) { DST_EUR = 0; // нет смещения nxtSwitch_EUR = spr; // время следующего перевода часов if(IS_DEBUG_MODE) Print(zone,"-DST for ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR)," nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR)); return; } d = (int)(31 - MathMod((1 + MathFloor(5*y/4)), 7)); // determine the last Sunday in October for the EU switch aut = StringToTime(""+(string)y+".10."+(string)d+" 03:00"); // преобразуем в datetime if(t < aut) { DST_EUR =-3600; // = +1h => 09:00 London time = GMT+05h+DST_EU = GMT+0+1 = GMT+1; nxtSwitch_EUR = aut; // время след перехода if(IS_DEBUG_MODE) Print(zone,"-DST for ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR)," nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR)); return; } y++; // пересчитываем переход весной для след года d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7)); // найдем последнее воскресенье марта - переход на летнее в Европе spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // преобразуем в datetime if(t < spr) { DST_EUR = 0; // нет смещения nxtSwitch_EUR = spr; // время следующего перевода часов if(IS_DEBUG_MODE) Print(zone,"-DST for ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR)," nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR)); return; } Print("ERROR for ",zone," @ ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR)," nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR)," winter: ",TimeToString(aut)," spring: ",TimeToString(spr)); return; }
Показаны все три периода в одном году:
- Перед переходом на летнее время в марте.
- До перехода на зимнее время в октябре/ноябре.
- Зимнее время до перехода на летнее в следующем году.
Периоды рассчитываются для EUR, USD и AUD.
Одиночный вызов функции nextDST(..), например:
nextDST("EUR", D'2019.02.05 20:00'); nextDST("EUR", D'2019.06.05 20:00'); nextDST("EUR", D'2019.11.20 20:00'); nextDST("USD", D'2019.02.05 20:00'); nextDST("USD", D'2019.06.05 20:00'); nextDST("USD", D'2019.11.20 20:00'); nextDST("AUD", D'2019.02.05 20:00'); nextDST("AUD", D'2019.06.05 20:00'); nextDST("AUD", D'2019.11.20 20:00');
проверяет все три момента в году для трех регионов. И вот какой результат:
Европа: последнее воскресенье марта и последнее воскресенье октября:
EUR-DST for 2019.02.05 20:00 DST: 0 nxtSwitch: Su. 2019.03.31 03:00
EUR-DST for 2019.06.05 20:00 DST: -3600 nxtSwitch: Su. 2019.10.27 03:00
EUR-DST for 2019.11.20 20:00 DST: 0 nxtSwitch: Su. 2020.03.29 03:00
США: 2-е воскресенье марта и 1-е воскресенье ноября:
USD-DST for 2019.02.05 20:00 DST: 0 nxtSwitch: Su. 2019.03.10 03:00
USD-DST for 2019.06.05 20:00 DST: -3600 nxtSwitch: Su. 2019.11.03 03:00
USD-DST for 2019.11.20 20:00 DST: 0 nxtSwitch: Su. 2020.03.08 03:00
Австралия: первое воскресенье ноября и последнее воскресенье марта
AUD-DST for 2019.02.05 20:00 DST: -3600 nxtSwitch: Su. 2019.03.31 03:00
AUD-DST for 2019.06.05 20:00 DST: 0 nxtSwitch: Su. 2019.11.03 03:00
AUD-DST for 2019.11.20 20:00 DST: -3600 nxtSwitch: Su. 2020.03.29 03:00
Перевод времени в Австралии может сбивать с толку, но это связано с тем, что Австралия расположена в южном полушарии, где начало года приходится на середину лета, поэтому переход на летнее время происходит, когда в Европе зима.
Перевод часов в России
Отдельно пришлось написать код для работы со временем в России. Поскольку в России были изменения, связанные с переводом часов, я решил использовать двумерный массив, который содержит время переходов. Запросить ее можно с помощью этой функции:
long RussiaTimeSwitch[][2] = { D'1970.01.00 00:00', -10800, D'1980.01.00 00:00', -10800, D'1981.04.01 00:00', -14400, ... D'2012.01.00 00:00', -14400, D'2014.10.26 02:00', -10800, D'3000.12.31 23:59', -10800 }; int SzRussiaTimeSwitch = 67; // ArraySize of RussiaTimeSwitch //+------------------------------------------------------------------+ //| Russian Time Switches | //+------------------------------------------------------------------+ void offsetRubGMT(const datetime t) { int i = SzRussiaTimeSwitch; //ArrayRange(RussiaTimeSwitch,0); 66 while(i-->0 && t < RussiaTimeSwitch[i][0]) continue; // t >= RussiaTimeSwitch[i][0] nxtSwitch_RUB = (datetime)RussiaTimeSwitch[fmin(SzRussiaTimeSwitch-1,i+1)][0]; DST_RUS = (int)RussiaTimeSwitch[fmin(SzRussiaTimeSwitch-1,i+1)][1]; return; } //+------------------------------------------------------------------+
Функция, обновляющая значения
Мы подошли к последней функции в этом проекте. Эта функция обеспечивает актуальность всех важных значений:
//+------------------------------------------------------------------+ //| функция определения смещения брокера для указанного tB | //+------------------------------------------------------------------+ void checkTimeOffset(datetime tB) { if(tB < nxtSwitch_USD && tB < nxtSwitch_EUR && tB < nxtSwitch_AUD) return; // nothing has changed, return
В самом начале функция спрашивает, нужно ли установить смещение времени (и дату следующего перехода). Если нет, работа функции завершается.
В противном случае функция nextDST() рассчитывает соответствующие значения для EUR, USD, AUD и RUB (описано выше):
if(tB>nxtSwitch_USD) nextDST("USD", tB); // был переход в США if(tB>nxtSwitch_EUR) nextDST("EUR", tB); // был переход в Европе if(tB>nxtSwitch_AUD) nextDST("AUD", tB); // был переход в Австралии if(tB>nxtSwitch_RUB) nextDST("RUB", tB); // был переход в России
Для определения сдвига времени брокера нужны только USD и EUR. А AUD и RUB просто дают актуальные значения для соответствующих стран. Если они вам не нужны, можете закомментировать //.
Далее, в зависимости от периода, в поле OffsetBroker.actOffset прописывается сдвиг времени брокера, действующий с соответствующего периода, а в OffsetBroker.actSecFX — время работы рынка в текущий момент:
if(DST_USD+DST_EUR==0) // оба значения в зимнем времени { OffsetBroker.actOffset = OffsetBroker.USwinEUwin; OffsetBroker.actSecFX = OffsetBroker.secFxWiWi; } else if(DST_USD == DST_EUR) // оба в летнем времени { OffsetBroker.actOffset = OffsetBroker.USsumEUsum; OffsetBroker.actSecFX = OffsetBroker.secFxSuSu; } else if(DST_USD != DST_EUR) // US:лето EU:зима { OffsetBroker.actOffset = OffsetBroker.USsumEUwin; OffsetBroker.actSecFX = OffsetBroker.secFxSuWi; }
И все. Мы рассмотрели все необходимые функции: функция определения смещения времени брокера по котировке и функция, которая всегда определяет текущее смещение, на основе которого можно легко определить время по Гринвичу (GMT) и, соответственно, локальное время, даже при работе в тестере стратегий.
Есть два способа работы с ними.
Скрипт, демонстрирующий настройку и использование
К статье приложен файл скрипта DealingWithTimeScript.mq5:
#include <DealingWithTime.mqh> //+------------------------------------------------------------------+ //| Finding the broker offsets | //+------------------------------------------------------------------+ void OnStart() { //--- шаг 1: устанавливаем смещение у брокера зимой, летом и в промежутке bool isTimeSet = setBokerOffset(); if(!isTimeSet) { Alert("setBokerOffset failed"); return; }
В журнал советника будет выведено:
USD: Fr.2020.10.30 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h
Offset for MetaQuotes Software Corp.:
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200
Найденные значения можно присваивать входным переменным. Это пример для следующей главы. Мы уже разобрали выше, как работает эта часть. Моделируем путь от прошлого к настоящему часу работы брокера, рассчитываем и печатаем значения GMT New York и оставшееся время, в течение которого рынок форекс будет открытым для случайно выбранных временных меток.
Всю историю для таймфрейма 1h по EURUSD можно получить с помощью функции CopyTime("EURUSD",PERIOD_H1,datetime(0),TimeCurrent(),arr1h).
Чтобы не утонуть в куче данных, посмотрим данные для случайно определенных баров. Для этого выберем количество данных. Если задать 5, баров будет около 10, потому что в случайном среднем расстояние шага составляет примерно половину sz/5:
//--- шаг 2: получаем котировки (у нас только H1) datetime arr1h[], tGMT, tNY, tLeft; CopyTime("EURUSD",PERIOD_H1,datetime(0),TimeCurrent(),arr1h); int b = 0, sz = ArraySize(arr1h)-1, // oldest time stamp nChecks = sz/5, // ~2*5+1 randomly chosen bars chckBar = MathRand()%nChecks; // index of the first bar to check
Пройдем по всем барам, от самого старшего до текущего, как при тестировании или оптимизации в тестере стратегий: while(++b<=sz). Будем проверять ситуацию на каждом новом баре: checkTimeOffset(arr1h[b]). Мы помним, что в этой функции в первую очередь проверяется необходимость пересчета, поэтому вызов не очень ресурсоемкий, несмотря на частоту:
//--- шаг 3: смоделируем, как советник или индикатор проходит во времени из прошлого в настоящее while(++b<=sz) { //--- проверим время, обычно на первом баре после выходных checkTimeOffset(arr1h[b]);
Теперь мы вычисляем только для бара, определенного случайным значением GMT (tGMT), tNY — нью-йоркское время и tLeft — оставшееся время до закрытия рынка. Значения выводятся и вычисляется следующий бар:
//--- for a randomly selected bar calc. the times of GMT, NY & tLeft and print them if(b>=chckBar || b==sz) { tGMT = arr1h[b] + OffsetBroker.actOffset; // GMT tNY = tGMT - (NYShift+DST_USD); // время в Нью-Йорке tLeft = OffsetBroker.actSecFX - SoW(arr1h[b]); // время до закрытия FX PrintFormat("DST_EUR:%+ 6i DST_EUR:%+ 6i t[%6i] tBrk: %s%s "+ "GMT: %s%s NY: %s%s End-FX: %2ih => left: %2ih ", DST_EUR,DST_USD,b, DoWs(arr1h[b]),TimeToString(arr1h[b],TIME_DATE|TIME_MINUTES), DoWs(tGMT),TimeToString(tGMT,TIME_DATE|TIME_MINUTES), DoWs(tNY),TimeToString(tNY,TIME_DATE|TIME_MINUTES), OffsetBroker.actSecFX/3600,tLeft/3600 ); chckBar += MathRand()%nChecks; // индекс следующего бара для проверки }
Вот что вывел скрипт для демо-счета на сервере MetaQuotes:
USD: Fr.2020.10.30 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 142h
NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h
USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h
EUR: Fr.2021.03.26 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 142h
NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h
Сдвиг для MetaQuotes Software Corp.:
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200
DST_EUR: -3600 DST_EUR: -3600 t[ 28194] tBrk: Mo.2002.05.20 22:00 GMT: Mo.2002.05.20 19:00 NY: Mo.2002.05.20 15:00 End-FX: 143h => left: 97h
DST_EUR: -3600 DST_EUR: -3600 t[ 40805] tBrk: We.2004.05.26 06:00 GMT: We.2004.05.26 03:00 NY: Tu.2004.05.25 23:00 End-FX: 143h => left: 65h
DST_EUR: -3600 DST_EUR: -3600 t[ 42882] tBrk: Th.2004.09.23 19:00 GMT: Th.2004.09.23 16:00 NY: Th.2004.09.23 12:00 End-FX: 143h => left: 28h
DST_EUR: +0 DST_EUR: +0 t[ 44752] tBrk: Tu.2005.01.11 17:00 GMT: Tu.2005.01.11 15:00 NY: Tu.2005.01.11 10:00 End-FX: 143h => left: 78h
DST_EUR: +0 DST_EUR: -3600 t[ 64593] tBrk: We.2008.03.26 03:00 GMT: We.2008.03.26 01:00 NY: Tu.2008.03.25 21:00 End-FX: 142h => left: 67h
DST_EUR: +0 DST_EUR: +0 t[ 88533] tBrk: Tu.2012.02.07 13:00 GMT: Tu.2012.02.07 11:00 NY: Tu.2012.02.07 06:00 End-FX: 143h => left: 82h
DST_EUR: +0 DST_EUR: +0 t[118058] tBrk: We.2016.11.16 06:00 GMT: We.2016.11.16 04:00 NY: Tu.2016.11.15 23:00 End-FX: 143h => left: 65h
DST_EUR: -3600 DST_EUR: -3600 t[121841] tBrk: Mo.2017.06.26 05:00 GMT: Mo.2017.06.26 02:00 NY: Su.2017.06.25 22:00 End-FX: 143h => left: 114h
DST_EUR: +0 DST_EUR: -3600 t[144995] tBrk: Mo.2021.03.22 06:00 GMT: Mo.2021.03.22 04:00 NY: Mo.2021.03.22 00:00 End-FX: 142h => left: 112h
DST_EUR: -3600 DST_EUR: -3600 t[148265] tBrk: Tu.2021.09.28 15:00 GMT: Tu.2021.09.28 12:00 NY: Tu.2021.09.28 08:00 End-FX: 143h => left: 80h
Первые два блока мы уже обсудили. Третья и последняя часть показывает для случайно выбранных точек соответствующую разницу во времени между ЕС и США, индекс временной точки, время брокера, время по Гринвичу и Нью-Йорку, время открытия рынка на данный момент времени и оставшееся время - для наглядности секунды переведены в часы. Все это можно быстро проверить: 5/20/2002, время брокера (MQ) 22:00, с переходом на летнее время, GMT = broker-3 ч = 19:00, а нью-йоркское = GMT - (5-1) = 15:00, рынок закроется через 97 часов. 97 = 4*24 (Mon.22:00-Fri.22:00 = 96h) +1h (Fri.22:00-23:00).
Таким образом, в советнике или индикаторе нужно добавить всего два вызова функции:
bool isTimeSet = setBokerOffset(); if(!isTimeSet) { Alert("setBokerOffset failed"); return; } .. checkTimeOffset(TimeCurrent());
Альтернативное использование через входные переменные
Рассмотрим пример работы через входные переменные. Скрипт дал такие значения:
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200
В советнике это может выглядеть так:
#include <DealingWithTime.mqh> // offsets of MetaQuotes demo account: DO NOT USE THEM FOR DIFFERENT BROKERS!! input int USwinEUwin= -7200; // US=Winter & EU=Winter input int USsumEUsum= -10800; // US=Summer & EU=Summer input int USsumEUwin= -7200; // US=Summer & EU=Winter //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- OffsetBroker.USwinEUwin = USwinEUwin; OffsetBroker.USsumEUsum = USsumEUsum; OffsetBroker.USsumEUwin = USsumEUwin; OffsetBroker.actOffset = WRONG_VALUE; nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0; //--- Just a simple test if not set or changed if(OffsetBroker.USwinEUwin+OffsetBroker.USsumEUsum+OffsetBroker.USsumEUwin==0) OffsetBroker.set = false; else OffsetBroker.set = true; //... //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- checkTimeOffset(TimeCurrent()); tGMT = TimeCurrent() + OffsetBroker.actOffset; // GMT tNY = tGMT - (NYShift+DST_USD); // время в Нью-Йорке tLon = tGMT - (LondonShift+DST_EUR); // время в Лондоне tSyd = tGMT - (SidneyShift+DST_AUD); // время в Сиднее tMosc = tGMT - (MoskwaShift+DST_RUS); // время в Москве tTok = tGMT - (TokyoShift); // время в Токио - нет перехода на летнее время //... }
Я указал значения, полученные для сервера MetaQuotes. Убедитесь, что используете значения для вашего брокера!
В OnTick() сначала вычисляются смещения времени, а затем сразу после этого GMT и местное время Нью-Йорка, Лондона, Сиднея, Москвы и Токио. Все очень просто, но не забывайте про скобки.
Заключение
Вместо заключения я просто покажу результаты функции setBokerOffset() на демо-счетах разных брокеров:
EUR: Fr.2020.10.23 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End-FX after: 143h USD: Fr.2020.10.30 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 142h NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h EUR: Fr.2021.03.26 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 142h NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h Time Offset of MetaQuotes Software Corp.: US=Winter & EU=Winter (USwinEUwin) = -7200 US=Summer & EU=Summer (USsumEUsum) = -10800 US=Summer & EU=Winter (USsumEUwin) = -7200 EUR: Fr.2020.10.23 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End-FX after: 143h USD: Fr.2020.10.30 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 142h NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h EUR: Fr.2021.03.26 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 142h NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h Time Offset of RoboForex Ltd: US=Winter & EU=Winter (USwinEUwin) = -7200 US=Summer & EU=Summer (USsumEUsum) = -10800 US=Summer & EU=Winter (USsumEUwin) = -7200 EUR: Fr.2020.10.23 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End-FX after: 143h USD: Fr.2020.10.30 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 142h NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h EUR: Fr.2021.03.26 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 142h NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h Time Offset of Alpari International: US=Winter & EU=Winter (USwinEUwin) = -7200 US=Summer & EU=Summer (USsumEUsum) = -10800 US=Summer & EU=Winter (USsumEUwin) = -7200 EUR: Fr.2020.10.23 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End-FX after: 143h USD: Fr.2020.10.30 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 143h NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h EUR: Fr.2021.03.26 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 143h NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h Time Offset of Pepperstone Group Limited: US=Winter & EU=Winter (USwinEUwin) = -7200 US=Summer & EU=Summer (USsumEUsum) = -10800 US=Summer & EU=Winter (USsumEUwin) = -10800 EUR: Fr.2020.10.23 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End-FX after: 143h USD: Fr.2020.10.30 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 143h NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h EUR: Fr.2021.03.26 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 143h NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h Time Offset of Eightcap Pty Ltd: US=Winter & EU=Winter (USwinEUwin) = -7200 US=Summer & EU=Summer (USsumEUsum) = -10800 US=Summer & EU=Winter (USsumEUwin) = -10800 EUR: Fr.2020.10.23 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End-FX after: 143h USD: Fr.2020.10.30 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 142h NXT: Fr.2020.11.06 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 143h USD: Fr.2021.03.12 23:00: hNY:16 hGMT:21 hTC:23 hDiff:-2 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 143h EUR: Fr.2021.03.26 22:00: hNY:16 hGMT:20 hTC:22 hDiff:-2 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 142h NXT: Fr.2021.04.02 23:00: hNY:16 hGMT:20 hTC:23 hDiff:-3 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 143h Time Offset of InstaForex Companies Group: US=Winter & EU=Winter (USwinEUwin) = -7200 US=Summer & EU=Summer (USsumEUsum) = -10800 US=Summer & EU=Winter (USsumEUwin) = -7200 EUR: Fr.2020.10.23 21:00: hNY:16 hGMT:20 hTC:21 hDiff:-1 BrokerTime => GMT: 2020.10.23 20:00 => tNY: 2020.10.23 16:00 End-FX after: 141h USD: Fr.2020.10.30 21:00: hNY:16 hGMT:20 hTC:21 hDiff:-1 BrokerTime => GMT: 2020.10.30 20:00 => tNY: 2020.10.30 16:00 End-FX after: 141h NXT: Fr.2020.11.06 21:00: hNY:16 hGMT:21 hTC:21 hDiff: 0 BrokerTime => GMT: 2020.11.06 21:00 => tNY: 2020.11.06 16:00 End-FX after: 141h USD: Fr.2021.03.12 21:00: hNY:16 hGMT:21 hTC:21 hDiff: 0 BrokerTime => GMT: 2021.03.12 21:00 => tNY: 2021.03.12 16:00 End-FX after: 141h EUR: Fr.2021.03.26 21:00: hNY:16 hGMT:20 hTC:21 hDiff:-1 BrokerTime => GMT: 2021.03.26 20:00 => tNY: 2021.03.26 16:00 End-FX after: 141h NXT: Fr.2021.04.02 21:00: hNY:16 hGMT:20 hTC:21 hDiff:-1 BrokerTime => GMT: 2021.04.02 20:00 => tNY: 2021.04.02 16:00 End-FX after: 141h Time Offset of JFD Group Ltd: US=Winter & EU=Winter (USwinEUwin) = 0 US=Summer & EU=Summer (USsumEUsum) = -3600 US=Summer & EU=Winter (USsumEUwin) = -3600
Желаю вам успешной торговли!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/9929
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Вообще перешел на гринвич. И время перехода на зимнее определяю как разницу серверного времени и гринвича. Единственно, что для каждого брокера эту разницу приходится считать самому и забивать в константы советника. Просто когда у пользователей разные сдвиги, у брокеров, у бирж, и время перехода на зимнее не одинаково, гринвич одинаков для всех.
А как именно вы это сделали? Каким образом высчитывается константы?
А как именно вы это сделали? Каким образом высчитывается константы?
Время гринвича минус таймкаррент, с переходом на зимнее он изменится на час. Писал как то время начала и окончания работы, с клиентом разница в час +3 и +2, у брокеров +3, +2, -6 по гринвичу.))) А начинать работу надо было в определенное время, одинаковое для всех. Гринвич одинаков, а серверное и локальное время разные. Код из учебника Федосеева переделал.)
В общем проблема как бы, что нет штатной функции разницы серверного и гринвича времени. Но она считается. Тут еще затык, что у локального времени тоже может быть переход на зимнее время, и в отличное время, от перехода у брокера.
Время гринвича минус таймкаррент, с переходом на зимнее он изменится на час. Писал как то время начала и окончания работы, с клиентом разница в час +3 и +2, у брокеров +3, +2, -6 по гринвичу.))) А начинать работу надо было в определенное время, одинаковое для всех. Гринвич одинаков, а серверное и локальное время разные. Код из учебника Федосеева переделал.)
В общем проблема как бы, что нет штатной функции разницы серверного и гринвича времени. Но она считается. Тут еще затык, что у локального времени тоже может быть переход на зимнее время, и в отличное время, от перехода у брокера.
Спасибо, да, такое решение есть в голове, оно +- так и реализовано. Но вы в последнем абзаце указали на всю боль)
Версия DealingWithTime.mqh v. 1.01 из статьи Работа со временем (Часть 2): Функции ( https://www.mql5.com/ru/articles/9929 ) перестала работать, так как MQ изменил поведение CopyTime( ) через некоторое время после публикации этой статьи. Теперь эта функция больше не возвращает будущие значения времени, если они больше, чем TimeCurrent() , указанный для параметров start_time и/или stop_time. Вместо этого возвращается максимально возможное значение времени открытия последнего текущего бара.
Так как окончание валютной сессии было определено таким образом, чтобы определить смещение времени брокера, теперь это приводит к неверным значениям!
Этот расчет был изменен в версии 2.03. Эта версия теперь доступна в CodeBase здесь: https://www.mql5.com/ru/code/45287 .
Но также был полностью изменен расчет перевода времени, так что теперь охвачены сложные времена перевода времени из Сиднея (Австралия) обратно в 70-е годы.
Также прилагается таблица DST 1975 - 2030.xlsx в виде zip-файла со всеми временными изменениями с 70-х годов, чтобы каждый мог проверить правильность работы формул, вот пример серии таблицы:
1 января 1982 г. - стандартное время в США (DST == 0), а следующее изменение произойдет 25 апреля 1982 г., в последнее (25-е число месяца) воскресенье апреля (4). Таблица уже отсортирована по географическому часовому поясу (столбец A), затем по часовому поясу года (столбец L, spr=весна, aut=осень) и, наконец, по дате запроса (столбец C). Таблица может быть создана автоматически включенным советником (скрипт не может быть запущен в режиме отладки). Test_DST 2.mq5, если вы запустите его в режиме отладки и скопируете строки журнала журнала в отладчике и вставите их в электронную таблицу; Разделителем ячеек будет пробел.
Кроме того, теперь есть новая простая функция SecTillClose() , которая дает вам оставшееся время в секундах (валюта времени MQ) до закрытия рынка форекс - без CopyTime() . Это интересно для тех, кто хочет закрыть свои позиции до выходных или не хочет открывать новую позицию в определенный период до выходных.
Включенный индикатор DealingWithTime_TestIndi.mq5, как комментарий к графику, показывает не только летнее время в Европе, США и Австралии (Сидней), но также текущее время и разницу во времени различных городов. Здесь вы можете найти таблицу с разным местным временем крупных городов для сравнения: https://www.timeanddate.com/worldclock/ . Таким образом, вы можете проверить значения в любое время. Этот индикатор также показывает, как эти значения определяются и используются (что от чего вычитается или прибавляется), что облегчает самостоятельное использование — копирование и вставка, самая быстрая форма программирования.
Последние две строки также показывают последнюю секунду текущей FX-сессии и оставшееся время в часах (о чем проще судить) и в секундах. В Нью-Йорке, когда сессия FX закрывается в 17:00 по местному времени в пятницу, нет действительного бара, открытого в 17:00 по нью-йоркскому времени. Поэтому в этой функции вычитается 1 секунда, чтобы получить последнее действительное время открытия последнего бара во времени брокера. Однако некоторые брокеры заканчивают свою валютную сессию на несколько минут раньше, больше не предоставляя цены и не принимая торговые приказы.