首页 / 交易学院 / 小布知识库 / MQL5时间处理从入门到实战
MQL5时间处理从入门到实战
⏱️

MQL5时间处理从入门到实战

掌握datetime、时区与跨周期时间函数

MQL5开发 难度 · 进阶 2026-03-04 6 分钟阅读
#MQL5#时间函数#datetime#跨周期

为什么时间处理在MQL5中容易踩坑

MQL5提供了大量处理时间的简单函数,但实际应用中困难重重。主要难点并不在于函数本身,而在于时间测量的特殊性与EA、指标运行环境。比如短周期图表上可能因缺少价格变动而缺柱;部分交易中心报价包含周日柱甚至整个周末连续报价;周末无报价时周一直接接续周五;不同交易服务器时区不同;还有夏令时调整。这些都会导致单纯比较时钟时间出错。

常见任务有两类:一是在某给定时间点执行操作,如每天同一时间、一周某天或指定日期;二是在某时间范围内启用禁用操作,如日内时段、跨天时段或指定日期范围。理解底层机制才能写出健壮代码。

⚠ 新手注意
本文较长,建议投入三天以上分段掌握,不要试图一次读完所有函数。

时间测量的理论基础

地球绕轴自转产生恒星日(23时56分4秒),相对太阳自转产生太阳日(24小时),后者为民用时间基础。一年约365.25天,故每四年闰一日,但百年不闰、四百年再闰。1900非闰、2000闰、2100不闰、2400闰。

时区以本初子午线(格林威治)为0区,向东向西各12区,日期变更线在±12区之间。部分国家采用半时区如+05:45。夏令时约80国遵守,欧美多在3月改、10/11月回,南半球相反;俄罗斯2011后永久不退。UTC基于原子钟,不受夏令时,与GMT偶有1秒差。

日期格式各国不同:俄式dd.mm.yyyy,美式mm/dd/yy。程序最宜用yyyy.mm.dd hh:mi:ss,便于字符串排序。MQL5中时间自1970.01.01 Unix时间戳起按秒计,类型为datetime,范围0至32535244799(3000年底)。

MQL5核心时间函数与当前时间获取

确定当前服务器时间用TimeCurrent(),返回Market Watch中任一品种最后价格变动时间,基本等同服务器时间,但周末无变动时会停于周五。若需指定品种最后变动时间,用SymbolInfoInteger(_Symbol,SYMBOL_TIME)。本地时间用TimeLocal(),多用于提醒与日志,但终端Alert/Print会自动加时间戳,故较少直接用。

datetime tm=TimeCurrent();
Alert(tm);
datetime tm=(datetime)SymbolInfoInteger(_Symbol,SYMBOL_TIME);
Alert(tm);
datetime tm=TimeLocal();
Alert(tm);

输出时Alert等函数自动将datetime转为可读串如2012.12.05 22:31:57。若自行拼字符串,需显式转换:(string)tm得格式化, (long)tm得秒数。

datetime tm=TimeCurrent();
Alert("Formatted: "+(string)tm+", in seconds: "+(string)(long)tm);

时间格式化与字符串互转

TimeToString()可指定TIME_DATE、TIME_MINUTES、TIME_SECONDS等标志格式化。StringToTime()将字符串转为秒数,支持不完整日期如仅日期或仅时间。加减时间即加减秒数,如±3600为一小时。

datetime tm=StringToTime("2012.12.05 22:31:57");
Alert((string)(long)tm);
datetime tm=TimeCurrent();
datetime ltm=tm-3600;
datetime ftm=tm+3600;
Alert("Current: "+(string)tm+", an hour ago: "+(string)ltm+", in an hour: "+(string)ftm);
✦ 技巧
用StringToTime("2012.12.05")得当日00:00:00,方便计算日始。

日期分量拆解与重构

TimeToStruct()配合MqlDateTime结构取年月中日时分秒、星期(0=周日)和年中天(0基)。TimeCurrent(stm)亦可填结构。StructToTime()反向由分量生成时间,适合计算上月同日等。

datetime tm=TimeCurrent();
MqlDateTime stm;
TimeToStruct(tm,stm);
Alert("Year: "+(string)stm.year);
Alert("Day of week: "+(string)stm.day_of_week);
datetime tm=TimeCurrent();
MqlDateTime stm;
TimeToStruct(tm,stm);
if(stm.mon==1){stm.mon=12;stm.year--;}else{stm.mon--;}
datetime ltm=StructToTime(stm);
Alert("a month ago: "+(string)ltm);

获取K线柱时间与跨周期对齐

指标OnCalculate第一版直接收time[]数组。EA或其它周期需用CopyTime(),有三版:按索引+数量、按起始时间+数量、按时间范围。柱从右零计数,数组默认左旧右新,ArraySetAsSeries可反排。跨周期取低周期首柱需注意高周期柱时间在低周期可能缺失,文附LowerTFFirstBarTime等函数处理。

int start=0; int count=2; datetime tm[];
CopyTime(_Symbol,PERIOD_D1,start,count,tm);
Alert("Today: "+(string)tm[1]+", yesterday: "+(string)tm[0]);
datetime BarTimeNormalize(datetime aTime,ENUM_TIMEFRAMES aTF){
   int BarLength=PeriodSeconds(aTF);
   return(BarLength*(aTime/BarLength));
}
⚠ 坑点
高周期柱时间在低周期无对应柱时,不能硬拷贝,必须用文中函数向前找。

日始、周始与流逝时间计算

日始= (tm/86400)*86400(整数除截尾)。流逝秒= tm%86400。周始稍复杂,因时间戳始于周四且各国周起始不同,需加3或4日修正再整除604800后减回。文中WeekStartTime、SecondsFromWeekStart已封装。自年/月始周数可用YearStartTime/MonthStartTime配合通用函数。

datetime tm=TimeCurrent();
tm=(tm/86400)*86400;
Alert("Day start: "+(string)tm);
long WeekStartTime(datetime aTime,bool aStartsOnMonday=false){
   long tmp=aTime; long C=aStartsOnMonday?259200:345600;
   tmp+=C; tmp=(tmp/604800)*604800; tmp-=C; return(tmp);
}

实战:时段、时间点与支点指标

日内时段TimeSession将起止时分转秒比当前日秒;跨午夜时结束小于开始则双判。时间点TimeCross检查指定时分是否被跨过,防报价间隙漏触发。支点指标Pivot1用NewDay判日始;Pivot2用NewCustomDay支持用户定义日并忽略周末柱。文中附Session/TimePoint/TradeWeekDays/SessionWeek等指标。

bool TimeSession(int sh,int sm,int eh,int em,datetime aT){
   int S=3600*sh+60*sm, E=3600*eh+60*em; aT=aT%86400;
   if(E<S){ if(aT>=S||aT<E) return(true);}
   else{ if(aT>=S&&aT<E) return(true);}
   return(false);
}
bool TimeCross(int h,int m,datetime c,datetime p){
   datetime pt=h*3600+m*60; c=c%86400; p=p%86400;
   if(c<p){ if(c>=pt||p<pt) return(true);}
   else{ if(c>=pt&&p<pt) return(true);}
   return(false);
}

依赖本机设置的函数与回测特殊性

TimeTradeServer()周末也返真服务器时间;TimeGMT()依本机时钟算UTC;TimeDaylightSavings()返夏令修正;TimeGMTOffset()返时区秒差。本地时间=TimeGMT()-Offset()-DST。策略测试器中TimeCurrent与报价流同步,无真实时区/DST模拟,测跨时区EA需注意。

datetime tm=TimeTradeServer();
Alert(tm);
int val=TimeGMTOffset();
Alert(val);
✦ 回测建议
EA逻辑尽量用TimeCurrent(),避免依赖本机时区函数在测中失真。

常见问题

用TimeCurrent()得datetime,Alert()自动转字符串;若要自拼,用TimeToString(tm,TIME_DATE|TIME_SECONDS)或(string)tm。
比较两柱时间除86400是否不等:NewDay=(time[i]/86400)!=(time[i-1]/86400);含周末柱需用文中NewDay2区分周六周日。
CopyTime(_Symbol,PERIOD_D1,1,1,tm)取索引1的日柱时间即得昨日起点;或用CopyTime按时间范围拉取。
调用TimeSession(8,0,14,0,TimeCurrent()),返回true即在时段内;跨午夜如22点到2点也自动处理。
不会。测试器按报价流给TimeCurrent,不模拟时区与DST,依赖本机设置的TimeGMT等也不随测变化,需自行处理。