处理时间(第二部分):函数
全局变量
与其请求您的经纪商的支持,您可能会从他们那里得到一个不充分的答案(他们很愿意解释时间错位),我们只需自行查看在时间变化的几周内他们如何计算价格 — 但手工操作极其繁琐,我们让程序来做这件事 — 毕竟这就是为什么我们要有一台 PC。
在包含文件 DealingWithTime.mqh 的函数声明之前,且在宏替换之后,声明所需变量为全局变量:
//--- global variables for time switches int DST_USD=0, // act time shift USA DST_EUR=0, // act time shift EU DST_AUD=0, // act time shift Australia DST_RUS=0; // D'2014.10.26 02:00', -10800,
这些变量 DST_USD, DST_EUR,.. 将含有美国、欧盟、等地区的实际时移。 它们将由我们的函数进行更新和设置。 在冬季,采用正常时间,它们的值是零:在此阶段没有时移。
之后,我们的变量含有下一次时间变更时的时移。 它们主要需要知道何时需要执行新的计算,从而节省 CPU 资源:
datetime nxtSwitch_USD, // date of next switch nxtSwitch_EUR, // date of next switch nxtSwitch_AUD, // date of next switch nxtSwitch_RUB = D'2014.10.26 02:00'; // Russia s different :(
我们稍后将研究俄罗斯的情形。
这种结构及其全局变量是一切的核心。 :)
struct _OffsetBroker { int USwinEUwin, // US=Winter & EU=Winter USsumEUsum, // US=Summer & EU=Summer USsumEUwin, // US=Summer & EU=Winter actOffset, // actual time offset of the broker secFxWiWi, // duration of FX in sec secFxSuSu, // duration of FX in sec secFxSuWi, // duration of FX in sec actSecFX; // actual duration of FX in sec bool set; // are all set? }; _OffsetBroker OffsetBroker;
我们将为三个相关时段分配经纪商时移,且外汇市场在这三个持续时段是开放的,包括实际值和易于检查的设置(如果已经分配了数值)。 全局变量名为 OffsetBroker,我们将多次遇到它。
判定经纪商时间变换的核心函数
通过调用此函数:
setBokerOffset();
EA、指标或脚本可以自行决定经纪商何时处理时间变换,以及如何处理。 它位于所附脚本中 Start() 之后的代码开头,该函数判定经纪商在相关时间段(夏季时间、冬季时间和过渡时间)的相关值,然后可以通过 GMT 判定所有其它所需时间。 与其它所有事情一样,它位于包含文件 DealingWithTime.mqh 当中,其内还包括第一篇文章中的部分。 变量声明、初始化和相关全局变量归零后:
datetime dateEUR,dateUSD,dateAUD,dateNxt, // switch date for EU, AU, & US arrTme[]; // array to copy time int b; OffsetBroker.USsumEUwin = OffsetBroker.USsumEUsum = OffsetBroker.USwinEUwin = INT_MIN; nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0; // reset variables
我们找到周末的变更:
//--- AU, EU & US switches to winter time in 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: get DST and set next change b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_EUR,1,arrTme); // get time last 1h bar before switch in EU dateEUR = arrTme[0]; // last hour on Friday before the weekend nextDST("USD", D'2020.06.21 14:00'); // USA: get DST and set next change b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_USD,1,arrTme); // get time last 1h bar before switch in USA dateUSD = arrTme[0]; // last hour on Friday before the weekend nextDST("AUD", D'2020.06.21 14:00'); // AUD: get DST and set next change b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_AUD,1,arrTme); // get time last 1h bar before switch in AU dateAUD = arrTme[0]; // last hour on Friday before the weekend dateNxt = fmax(nxtSwitch_EUR,nxtSwitch_USD)+WeekInSec; // get the next weekend b = CopyTime("EURUSD",PERIOD_H1,dateNxt,1,arrTme); // get time last 1h bar before the weekend dateNxt = arrTme[0]; // last hour on Friday before the weekend
为方便起见,大多数打印输出都是在调试模式下自动执行的:if(IS_DEBUG_MODE)。 因此,当您在调试器(F5)中启动附带的脚本时,您会看到所有细节;但如果您在图表上正确启动相同的脚本,您只会得到重要的东西。
对于所有三个时段,函数调用,即 nextDST("EUR", D'2020.06.21 14:00'),首先计算 EU 的适用时移,其次切换下一个。 六月是夏令时,下一次变更为冬季时间。 在这之后,我们得到了最后一根 H1 柱线在周末前的周五的开盘时间,因为这将是我们进行计算的锚点。 参见第一篇文章末尾的第 4 点假设:
4. 如果在两个周五之间缺少若干个小时。 17:00 和周日 17:00,那么直到周日第一次报价,所有报价缺失,而非周五收到的最后一次报价之后。
我决定采用 "EURUSD" 的 H1 时间。 该品种历史最悠久,可能不仅仅是在 MQ。 但这也意味着,如果外汇市场在纽约时间 17:00 收盘,那么最后一个小时或最后一个 1 小时的交易时间从 16:00 开始,这是我们接下来特别感兴趣的时间。 周末过后的第一个小时是纽约周日 17:00。 判断澳大利亚的变更也是为了完整性,但不会进一步使用(见下文)。 之后,两个时区转换后的第一个周末仍然需要判定,从而计算经纪商在下一个时间变更期间的时移。
然后,对于星期五的三个钟点,调用函数 chckFriday(...) 计算经纪商各自相对于纽约时间 16:00 的时移。 这个函数是包含文件的一部分,我们将在下面讨论它。
chckFriday(dateEUR,"EUR"); // function to determine broker offset for the Friday given chckFriday(dateUSD,"USD"); // function to determine broker offset for the Friday given chckFriday(dateNxt,"NXT"); // function to determine broker offset for the Friday given
之后,遵循同样的原则计算一年中另一半的其它时间变化 — 我们实际上不需要这些(见上文),故可注释掉:
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: get DST and set next change b = CopyTime("EURUSD",PERIOD_H1,nxtSwitch_AUD,1,arrTme); // get time last 1h bar before switch in EU dateAUD = arrTme[0]; // last hour on Friday before the weekend ... chckFriday(dateUSD,"USD"); // function to determine broker offset for the Friday given chckFriday(dateEUR,"EUR"); // function to determine broker offset for the Friday given chckFriday(dateNxt,"NXT"); // function to determine broker offset for the Friday given
最后,在检测到经纪商时移,并将其赋值到相应字段后,决定性的变更时间 (nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0) 将重置为零,以供后续使用。 由于重新计算时间变更仅在历史过程中“过去”的周末进行,因此较迟的时间可能会阻止正确的计算,因此,重置一次太少,不如重置多次。 然后检查是否分配了所有值,并将结果打印到智能系统日志之中,然后检查返回:
nxtSwitch_USD = nxtSwitch_EUR = nxtSwitch_AUD = 0; // reset variables for use by a user 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
这令任何用户都可以使用这些值作为输入变量,可取代预先在策略测试器亦或实际图表上运行 EA 执行函数。 本文最后给出了一个示例。
判断并设置经纪商的时移
现在我们来研究函数 chckFriday(...)。 它判定不同时段各自经纪商的时移,并根据结构类型将其分配到全局变量 OffsetBroker 的相应字段 _OffsetBroker。 该结构知晓以下三个领域:
int USwinEUwin, // US=Winter & EU=Winter USsumEUsum, // US=Summer & EU=Summer USsumEUwin, // US=Summer & EU=Winter
它们会分别分配相应时段经纪商的时移。 这些时段是:
- 这两个地区都是一样的,要么是冬季(或标准时间),要么是夏季,或者
- 美国,已到夏季,欧盟仍然在冬季。
逆转的情况是,美国已经(仍然)在冬季,而欧盟仍然(已经)在夏季,这种情况并不存在。 此处出现的问题不仅是为什么第四个类别不存在,以及澳大利亚或 AUD 会如何 — 它在于此缺失了吗?
以下是切换的规则:
- 欧盟:10 月份最后的周日,和 3 月份最后的周日
- 美国:11 月份的首个周日,和 3 月份的第二个周日
- 澳洲:11 月份的首个周日,和 3 月份的最后一个周日
关于第一个问题。 欧盟比美国早一到两周切换到冬季时间:美国仍然是夏季,而欧盟已经是冬季,因此该值被分配到 OffsetBroker 变量的 USsumEUwin 字段。 然后在春季,美国先于欧盟就转为夏季,如此美国的夏季已持续一两周,而欧盟仍然是冬季。 同样,该值被分配给 OffsetBroker 变量的 USsumEUwin 字段。 由此清晰地表明,相反的情况欧盟已经(仍然)夏季了,但美国仍然(已经)是冬季的情况根本不会发生。 这实际上不需要计算秋季和春季变更期间的经纪商时移。 尽管如此,它还是被执行了 — 仅仅是出于完整性和控制。
关于第二个问题。 澳大利亚和美国一样,在 11 月份切换。 在春季,则和欧盟一致。 因此,没有其它进行变更的不同周末。 然而,在澳大利亚,当欧盟和美国处于冬季时,时钟会提前 1 小时,因为那里的圣诞节和新年都在夏季
现在,如果我们已经计算出一个特殊时段的时移,那么我们也可以计算外汇市场在这几周期间的开盘时间。 这些值存储在 secFxWiWi、secfxsuu、secFxSuWi 字段和 actSecFX 里的当前有效值当中。 在文章的最后,在应用程序一章中,我们将展示如何处理这个问题。
但在赋值之前,必须先要判定它们。 在变量声明和重置全局变量之后,将计算给定时间 tB(time Broker)的欧盟和美国时移:
//+------------------------------------------------------------------+ //| auxiliary function to determine time offset of the broker | //+------------------------------------------------------------------+ int chckFriday( datetime tB, // time Broker: the last hour on Friday string cmt="" // text to start the line ) { int hNY, hGMT, hTC, hDiff; nxtSwitch_AUD = nxtSwitch_USD = nxtSwitch_EUR = 0; // reset to be save nextDST("EUR",tB); // get the offset for EUR of the time tB given nextDST("USD",tB); // get the offset for USA of the time tB given
此处,tB 是周五最后一个小时的开始,也就是纽约的 16:00。 这个假设是进一步计算的基础,因为我们可以计算这个时间的 GMT:
tGMT = tNY + (NYShift + DST_USD)
以及经纪商相对 GMT 的时移。 我们遵循这种方式判定这个时移:从经纪商最后一个星期五的时间 tB 减去今天过去的秒数,SoB(tB)。 我们得到一天的时间 00:00,然后加上直到 16:00 的秒数(16*3600)。 现在我们知道了纽约时间,据其我们通过加上 NYShift + DST_USD 得到 GMT。 现在,我们可以很容易地判定经纪商的时移,然后将其分配到相应的 OffsetBroker 字段。
在函数中,这一切都是利用宏替换HoD()( 日内钟点),按小时(而不是按秒)完成的,为了在打印输出中便于记录和轻易验证:
hNY = HoD(tB - SoD(tB) + 16*3600); // get the hour of New York time hGMT = HoD(tB - SoD(tB) + 16*3600 + NYShift + DST_USD); // get the hour of GMT hTC = HoD(tB); // get the hour of the time given hDiff = hGMT - HoD(tB); // get the difference between GMT and the broker
毕竟这不是很困难。 ;)
为了安全起见,插入以下内容。 它检查是否有预期之外情况的发生,即美国夏季,而欧盟冬季:
if(DST_USD==0 && DST_EUR!=0) // this should not occur Alert(__LINE__," ",TOSTR(DST_USD),TOSTR(DST_EUR)," USwin && EUsum");
现在我们可以分配已发现的差值,和外汇市场开盘的持续时间:
//--- set the broker offset for the various time situations: if(DST_USD+DST_EUR==0) // both in winter (normal) time { OffsetBroker.actOffset = OffsetBroker.USwinEUwin = hDiff*3600; OffsetBroker.actSecFX = OffsetBroker.secFxWiWi = SoW(tB); } else if(DST_USD == DST_EUR) // else both in summer time { OffsetBroker.actOffset = OffsetBroker.USsumEUsum = hDiff*3600; OffsetBroker.actSecFX = OffsetBroker.secFxSuSu = SoW(tB); } else if(DST_USD!=0 && DST_EUR==0) // US:summer EU:winter { OffsetBroker.actOffset = OffsetBroker.USsumEUwin = hDiff*3600; OffsetBroker.actSecFX = OffsetBroker.secFxSuWi = SoW(tB); }
最后,我们打印出所有找到的值,并返回最后一个实际时移:
//--- calc the ring of times NY->GMT->Broker->GMT->NY <= the last NY must always be 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
此处展示的一些有趣内容值得讨论。 欧盟首先在 10 月 25 日进行切换。 一周后,美国于 11 月 1 日切换。 在此过渡期内,MQ 周五的最后一个小时从 22:00,而非 23:00,且本周结束是在此根柱线,于 142 小时后,替代正常的 143 小时后。 143 或r 142 小时? 外汇市场一周只有 120 小时:5*24=120? 一周中的秒数(SoW()) 和其它类似函数指的是日历周,从周日 00:00 开始。 但从周日 00:00 至周五 23:00 现在有 6* 24-1 = 143。 以下依据该值计算一周内任何给定时刻外汇市场保持开放的剩余时间。
这三行还用于检查逻辑和计算,并作为用户如何基于 GMT 判定所需本地时间的示例。 从左边开始,经纪商的时间戳后面跟着纽约的假定时间,hNY:16,然后是基于纽约时间的 GMT 钟点、经纪商的钟点,及其时移:-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 的值重置为零很重要,因为不如此就可能无法在整个测试期间重新进行计算。
然后,在变量声明和初始化之后,我们来到函数的核心,它不是出自我手。 之前有段时间了,我在网上的某个地方发现了一个算法,它判断一个月中的某一天。 它可用于判断给定时间点是夏季或冬季时间。 算法并没有那么复杂:
- 判定一个月的一天,一个周日,在这一天进行变更。
- 据其创建一个日期。
- 找到最近的未来变更周日。
- 设置时移,0 或 -1 小时,以及下一个变更周日。
这个算法的神奇之处在于它的代码行能判断时间变更在月份中的那一天。 对于欧盟来说,这是 3 月的最后一个周日,计算方式如下(正如我所说,公式的思路并非来自我):
d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7)); // determine the last Sunday in March for the EU switch针对 2021 年的结果,3 月份最后一个周日,此处是 Excel 公式,D=25:
31 - MOD(ROUNDDOWN(5*2021/4);7) = 25.
从那刻起形成时间戳,于该时间戳欧盟切换到夏季时间:2021 年 3 月 25 日,3 月的最后一个周日:
spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // convert to datetime format
所有其它日期的流程都与之类似,无需单独解释。
此处代码中有一个较大的部分,它判定当前夏季或冬季的时移,以及给定日期后的欧盟下一个变更日期。 一年内我们需要三个部分:第一次变更之前、第一次和第二次之间、以及第二次变更之后。 随后的时间变更已经是下一年了,必须考虑到这一点:
if(zone == "EUR") { d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7)); // determine the last Sunday in March for the EU switch spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // convert to datetime format if(t < spr) { DST_EUR = 0; // no time offset nxtSwitch_EUR = spr; // set the next time switch 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"); // convert to datetime format if(t < aut) { DST_EUR =-3600; // = +1h => 09:00 London time = GMT+05h+DST_EU = GMT+0+1 = GMT+1; nxtSwitch_EUR = aut; // set the next time switch if(IS_DEBUG_MODE) Print(zone,"-DST for ",TimeToString(t)," DST: ",StringFormat("% 5i",DST_EUR)," nxtSwitch: ",DoWs(nxtSwitch_EUR)," ",TimeToString(nxtSwitch_EUR)); return; } y++; // re-calc the spring switch for the next year d = (int)(31 - MathMod((4 + MathFloor(5*y/4)), 7)); // determine the last Sunday in March for the EU switch spr = StringToTime(""+(string)y+".03."+(string)d+" 03:00"); // convert to datetime format if(t < spr) { DST_EUR = 0; // no time offset nxtSwitch_EUR = spr; // set the next time switch 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; }
一年内可以看到三个部分:
- 在三月份变更为夏季之前。
- 在 10 月份/11 月份切换到冬季之前。
- 在冬季,下一年将切换到夏季。
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');
将测试这三个地区一年中的所有三个相关时间点。 结果是:
EU: last Sunday in March and last Sunday in October:
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
US: 2nd Sunday in March and 1st Sunday in November:
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
AU: 1st Sunday in November and last Sunday in March:
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
也许澳大利亚的时间变更有点令人困惑,但澳大利亚,不像美国和欧盟,它位于南半球,那里是一年中的夏季,因此他们的夏令时处于欧洲的冬季是意料之中的。
俄罗斯的变更
一个小注意事项是,由于 MQ 有俄罗斯的根源,而且有许多俄罗斯用户,所以还需包括俄罗斯的时间变更。 然而,由于俄罗斯的时钟在何时以及如何变更的幅度很大,我决定使用一个二维数组,在该数组中输入时间和相应的时移,并可通过该函数查询:
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; } //+------------------------------------------------------------------+
保持时间更新的函数
现在我们来讨论这个项目的最后一个函数,即保持关键值随时更新的函数:
//+------------------------------------------------------------------+ //| function to determine broker offset for the time tB given | //+------------------------------------------------------------------+ void checkTimeOffset(datetime tB) { if(tB < nxtSwitch_USD && tB < nxtSwitch_EUR && tB < nxtSwitch_AUD) return; // nothing has changed, return
它也首先在开始处询问是否必须设置时移(以及下一个变更日期)。 若不需要,该函数将立即退出。
否则,“EUR”、“USD”、“AUD” 和 “RUB” 的值将调用上述函数 nextDST() 进行计算:
if(tB>nxtSwitch_USD) nextDST("USD", tB); // US has switched if(tB>nxtSwitch_EUR) nextDST("EUR", tB); // EU has switched if(tB>nxtSwitch_AUD) nextDST("AUD", tB); // AU has switched if(tB>nxtSwitch_RUB) nextDST("RUB", tB); // RU has switched
需要 “USD” 和 “EUR” 来判定经纪商时移。 "AUD" 和 "RUB" 仅当用户想了解它们时才需要,否则简单地用 “//” 注释语句即可停用它们。
然后,根据不同的时段,OffsetBroker.actOffset 字段必须指定距该时刻起,和当前外汇市场开放期 OffsetBroker.actSecFX 的有效经纪商时移:
if(DST_USD+DST_EUR==0) // both in winter (normal) time { OffsetBroker.actOffset = OffsetBroker.USwinEUwin; OffsetBroker.actSecFX = OffsetBroker.secFxWiWi; } else if(DST_USD == DST_EUR) // else both in summer time { OffsetBroker.actOffset = OffsetBroker.USsumEUsum; OffsetBroker.actSecFX = OffsetBroker.secFxSuSu; } else if(DST_USD != DST_EUR) // US:summer EU:winter { OffsetBroker.actOffset = OffsetBroker.USsumEUwin; OffsetBroker.actSecFX = OffsetBroker.secFxSuWi; }
就这样了。 这些都是需要用到的函数:判定经纪商与报价的时移,以及始终判定当前时移的函数,从中可以轻松判定 GMT 和任何其它本地时间,即使在策略测试器中也是如此。
我们现在展示利用这一切的两种方式。
演示设置和使用的脚本
首先,我们将其放入一个(附加的)脚本,DealingWithTimeScript.mq5:
#include <DealingWithTime.mqh> //+------------------------------------------------------------------+ //| Finding the broker offsets | //+------------------------------------------------------------------+ void OnStart() { //--- step 1: set the broker time offsets in winter, summer and in between 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
Time Offset of MetaQuotes Software Corp.:
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200
这可令用户将找到的偏移量分配给输入变量。 这是下一章节的示例。 我们在此看到的内容已解释过了,所以我们进入本脚本的下一步。 我们模拟从过去时间到经纪商实际工作时间的路径,计算并打印 GMT 纽约时间的值,以及随机选择的时间戳距外汇市场保持开市的剩余时间。
我们通过这个函数 CopyTime("EURUSD",PERIOD_H1,datetime(0),TimeCurrent(),arr1h) 得到了 “EURUSD” H1 时间戳的全部历史。
但为了避免淹没在海量数据和这么长时间的冗长表述之中,我们只显示随机判定的柱线图的数据。 为此,我们选择应有多少数据。 对于给定的 5,它大约是 10,因为在随机平均中,跳跃距离约为 sz/5 的一半:
//--- step 2: get the quotes (here only 1h time stamps) 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])。 我们记得,在这个函数中,第一件事要检查是否需要重新计算,故这个调用不是很占用资源,尽管它的频率很高:
//--- step 3: simulate an EA or an indicator go through the time from the past to now while(++b<=sz) { //--- check the time situation, normally do it at the first bar after the weekend 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); // time in New York tLeft = OffsetBroker.actSecFX - SoW(arr1h[b]); // time till FX closes 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; // calc. the index of the next bar to check }
此处是该脚本 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
Time Offset of 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
前两个模块已经讨论过了。 第三部分和最后一部分针对随机选择的时间点分别显示欧盟和美国的时差、时间点索引、经纪商时移、GMT、和纽约时间,以及外汇市场在该时间点的开盘时间和剩余时间 — 为了清晰起见,转换为小时单位替代秒数。 现在可以快速检查:On 5/20/2002, broker time (MQ) is 22:00, daylight saving time applies, GMT = broker-3h = 19:00 and NY = GMT - (5h-1h) = 15:00 and the FX market closes in 97 hours。 97 = 4*24 (Mon.22:00-Fri.22:00 = 96h) +1h (Fri.22:00-23:00) - qed.
因此,一款 EA、指标,只需要两个函数调用即可得到各种偏移量:
bool isTimeSet = setBokerOffset(); if(!isTimeSet) { Alert("setBokerOffset failed"); return; } .. checkTimeOffset(TimeCurrent());
利用输入变量的备案
最后,举例说明 EA 如何将其用于输入变量。 通过上面的脚本,您可以得到以下表述:
US=Winter & EU=Winter (USwinEUwin) = -7200
US=Summer & EU=Summer (USsumEUsum) = -10800
US=Summer & EU=Winter (USsumEUwin) = -7200
知道了这一点,EA(未附带,您可以从此处复制)看起来就像:
#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 ste 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); // time in New York tLon = tGMT - (LondonShift+DST_EUR); // time in London tSyd = tGMT - (SidneyShift+DST_AUD); // time in Sidney tMosc = tGMT - (MoskwaShift+DST_RUS); // time in Moscow tTok = tGMT - (TokyoShift); // time in Tokyo - no DST //... }
这里我采用了来自 Metaquotes 的偏移量。 确保您采用的是经纪商的偏移量!
在 OnTick() 中,首先计算时移,然后计算 GMT 和纽约、伦敦、悉尼、莫斯科和东京的当地时间,来示意现在这是多么简单。 然后别忘了:注意括号。
结束语
用某些经纪商演示账户上执行函数 setbokerofset() 的结果来替代最后的几句:
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
文章处理时间(第 2 部分):函数 ( https://www.mql5.com/en/articles/9929 ) 的DealingWithTime.mqh v. 1.01 版本停止工作,因为 MQ 更改了CopyTime( )在本文发表后一段时间发挥作用。现在,如果未来时间值大于为 start_time 和/或 stop_time 参数指定的TimeCurrent(),则该函数不再返回未来时间值。相反,最后一个当前柱的开盘时间将作为最大可能值返回。
由于外汇交易时段的结束是通过这种方式确定的,以便确定经纪商时间偏移,因此现在会导致错误的值!
此计算在 2.03 版本中已更改。该版本现已在代码库中提供:https: //www.mql5.com/en/code/45287 。
而且时间变化的计算也完全改变了,这样现在就涵盖了从悉尼(澳大利亚)到 70 年代的时间变化的复杂时间。
还附上表格DST 1975 - 2030.xlsx作为 zip 文件,其中包含自 70 年代以来的所有时间变化,以便每个人都可以检查公式的正确工作,以下是表格的示例系列:
1982 年 1 月 1 日是美国标准时间 (DST==0),下一次更改时间为 1982 年 4 月 25 日,即 4 月的最后一个(每月 25 日)星期日 (4)。该表已按地理时区(A 列)排序,然后按年份时区(L 列,spr=spring,aut=autumn)排序,最后按查询日期(C 列)排序。该表可以由包含的EA自动创建(脚本不能在调试模式下运行)。 Test_DST 2.mq5如果您在调试模式下运行它并复制调试器中日志日志的行并将其粘贴到电子表格中;细胞分隔物就是空间。
此外,现在还有一个新的简单函数SecTillClose() ,它可以为您提供外汇市场关闭之前的剩余时间(以秒为单位)(MQ 的时间货币) - 无需CopyTime() 。对于那些想在周末之前平仓或不想在周末之前的指定时间内开立新头寸的人来说,这很有趣。
包含的指标DealingWithTime_TestIndi.mq5作为图表的注释,不仅显示欧洲、美国和澳大利亚(悉尼)的夏令时,还显示当前时间和各个城市的时差。在这里您可以找到主要城市不同当地时间的表格进行比较:https: //www.timeanddate.com/worldclock/ 。因此,您可以随时检查这些值。该指标还显示了如何确定和使用这些值(从什么中减去或添加什么),使您更容易使用自己 - 复制和粘贴,这是最快的编程形式。
最后两行还显示当前外汇交易时段的最后一秒以及以小时(更容易判断)和秒为单位的剩余时间。在纽约,当外汇交易时段于周五当地时间下午 5:00 关闭时,纽约时间下午 5:00 没有有效的酒吧开放。因此,在此函数中,减去 1 秒即可得到经纪商时间中最后一根柱的最后有效开盘时间。然而,一些经纪商提前几分钟结束外汇交易,不再提供价格,也不再接受交易订单。