MQL5 编程基础: 终端的全局变量(基础篇)
MT5 全局变量的真实边界
MT5 客户端里有一类全局变量(Global Variable),它不由 EA 私有,而是挂在终端进程下,所有 MQL5 程序都能读能写。和图表变量不同,这类变量在 EA 停止、图表关闭后依然存活,直到终端退出或手动清除才消失。 实测一个细节:全局变量带时间戳,每次写入都会刷新最后访问时间。官方文档给出的存活上限是永久驻留,但只要客户端重启,未被显式删除的全局变量依旧保留——这点对跨会话传递状态很有用,比如让两个独立 EA 共享一个开关标志。 高风险提示:外汇与贵金属杠杆交易波动剧烈,用全局变量做跨 EA 通信时,若某一程序异常崩溃留下脏值,另一程序可能误读,引发非预期下单。建议每次启动先做一次键值校验。 下面这段演示如何写、读、删一个全局变量:
class="type">class="kw">string name="GV_Test"; class="type">class="kw">double value=class="num">123.45; class="type">bool written=GlobalVariableSet(name,value); class=class="str">"cmt">// 写入全局变量 class="type">class="kw">double read=GlobalVariableGet(name); class=class="str">"cmt">// 读取全局变量 class="type">class="kw">double deleted=GlobalVariableDel(name); class=class="str">"cmt">// 删除全局变量
「终端全局变量到底活在哪」
MT5 客户端自带一套全局变量(Global Variables of the Terminal),它和 EA、指标、脚本里的局部变量不是一回事。这套存储区被终端内所有程序共享,EA 写了之后,指标和脚本也能读同一份数据。 更关键的一点:全局变量的生命周期不随终端关闭而清零。实测在 MT5 里写入一个全局变量后正常退出客户端,重新打开后该变量依然存在,除非手动删除或调用清除接口。 后面正文里提到的“全局变量”若无特别说明,都指这套客户端级共享存储,而不是 MQL5 程序内部的全局作用域变量。想验证的话,开 MT5 按 F4 进 MetaEditor,用 GlobalVariableSet 写一个值,关终端再开就能看到它还在。
◍ 终端级全局变量与那 11 个内置函数
从程序视角看,全局变量就是一块带名字的内存区,MT5 里所有运行的程序(EA、指标、脚本)都能读写它。但要注意:如果你同时开了多个终端实例,每个终端各自独占一套全局变量空间,彼此不互通,也不会因为同名而互相覆盖。 MQL5 标准库给了 11 个专门操作全局变量的函数,覆盖创建、读取、修改、删除和枚举。做跨 EA 通信或脚本间传状态时,这套接口比写文件轻得多,但也要求你主动清理,否则变量会一直躺在终端内存里。 外汇与贵金属交易本身杠杆高、滑点不可控,用全局变量做信号中转时,必须考虑终端异常退出后旧值残留导致的误触发——这属于实盘高风险环节,任何自动逻辑都只能当作概率辅助。
用类封装 MT5 全局变量
把全局变量当成对象来管理,比直接调 GlobalVariableSet 更不容易乱。最小可用的 CGlobalVar 类只抓五个属性:变量名、数值、创建时间、最后访问时间、是否临时变量;方法覆盖创建、删除、存在检查、赋值、条件赋值和取值。 GetValue 做成模板方法,返回类型由调用方参数决定。MQL5 里函数只能靠参数传类型,所以得塞一个假参数占位,这点写的时候别漏。 测试脚本 Globals_test1.mq5 里建变量时传三参:基名 "Gvar1"、值 3.123456789101235、临时标记 true。实际名会被拼成 Gvar1_temp_prog_Globals_test1_scr,按 F3 能在全局变量列表看到,日志里打出不同数据类型。 重启终端后临时变量直接消失,因为它只活在当前会话。MQL 本身不记录临时属性,想区分就只能在名里加 "temp" 字样,但这样非本类创建的变量就对不上了。 顺手测了下吞吐:Globals_test2.mq5 多次启停,临时变量创建耗时见图表,完全变量稍慢——后者要写盘到 Profiles\gvariables.dat。实测没必要堆几千个,纯属好奇。外汇贵金属脚本跑这套注意终端异常退出可能丢临时态,属高风险环境。
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="comment">class=class="str">"cmt">//| Class CGlobalVar |</span> <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span> <span class="keyword">class</span> CGlobalVar : <span class="keyword">class="kw">public</span> CObject { <span class="comment">class=class="str">"cmt">//--- === Data members === --- </span> <span class="keyword">class="kw">private</span>: <span class="keyword">class="type">class="kw">string</span> m_name; <span class="keyword">class="type">class="kw">double</span> m_value; <span class="comment">class=class="str">"cmt">//---</span> <span class="keyword">class="type">class="kw">datetime</span> m_create_time; <span class="keyword">class="type">class="kw">datetime</span> m_last_time; <span class="comment">class=class="str">"cmt">//--- flag for temporary var</span> <span class="keyword">class="type">bool</span> m_is_temp; <span class="comment">class=class="str">"cmt">//--- === Methods === --- </span> <span class="keyword">class="kw">public</span>: <span class="comment">class=class="str">"cmt">//--- constructor/destructor</span> <span class="keyword">class="type">void</span> CGlobalVar(<span class="keyword">class="type">void</span>); <span class="keyword">class="type">void</span> CGlobalVar(<span class="keyword">const</span> <span class="keyword">class="type">class="kw">string</span> _var_name,<span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> _var_val, <span class="keyword">const</span> <span class="keyword">class="type">class="kw">datetime</span> _create_time); <span class="keyword">class="type">void</span> ~CGlobalVar(<span class="keyword">class="type">void</span>){}; <span class="comment">class=class="str">"cmt">//--- create/class="kw">delete</span> <span class="keyword">class="type">bool</span> Create(<span class="keyword">const</span> <span class="keyword">class="type">class="kw">string</span> _var_name,<span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> _var_val=<span class="number">class="num">0.0</span>, <span class="keyword">const</span> <span class="keyword">class="type">bool</span> _is_temp=<span class="macro">false</span>); <span class="keyword">class="type">bool</span> Delete(<span class="keyword">class="type">void</span>); <span class="comment">class=class="str">"cmt">//--- exist</span> <span class="keyword">class="type">bool</span> IsGlobalVar(<span class="keyword">const</span> <span class="keyword">class="type">class="kw">string</span> _var_name,<span class="keyword">class="type">bool</span> _to_print=<span class="macro">false</span>); <span class="comment">class=class="str">"cmt">//--- set methods</span> <span class="keyword">class="type">bool</span> Value(<span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> _var_val); <span class="keyword">class="type">bool</span> ValueOnCondition(<span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> _var_new_val,<span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> _var_check_val); <span class="comment">class=class="str">"cmt">//--- get methods</span> <span class="keyword">class="type">class="kw">string</span> Name(<span class="keyword">class="type">void</span>) <span class="keyword">const</span>;
「用 CGlobalVar 在 EA 间传一个临时变量」
MT5 的全局变量存在客户端终端里,不依赖图表周期,因此可以被不同 EA、脚本跨程序读取。上面的类把创建、取值、改值封装掉了,调用层只需要关心变量名和类型。 看 OnStart 里的实际跑法:gVar1.Create("Gvar1",3.123456789101235,true) 第三个参数 true 代表临时变量,终端退出后会被自动清掉。日志里 Name 被打成了 "Gvar1_temp_prog_Globals_test1_scr",说明类内部用 FormName 拼接了临时标记和脚本名,避免和其他程序撞名。 GetValue 是模板方法,传 double 拿到 15 位精度(%0.15f),传 float 只给 7 位,传 string 返回原值字符串。如果你想在 AUDUSD 的 H1 上复现,直接把脚本挂上去,专家日志里 10:20:21 附近就能看到这组打印。外汇与贵金属波动剧烈,全局变量只解决传递问题,不替你过滤报价风险。 ValueOnCondition(3.18,3.191) 这类条件写入在实盘里有点用:只有当终端里现有值等于 3.191 时才改成 3.18,相当于无锁的 CAS 操作,多程序抢同一个全局键时不容易互相覆盖。
class="type">class="kw">datetime CreateTime(class="type">void) const; class="type">class="kw">datetime LastTime(class="type">void); class="kw">template<class="kw">typename T> T GetValue(T _type) const; class="type">bool IsTemporary(class="type">void) const; class=class="str">"cmt">//--- class="kw">private: class="type">class="kw">string FormName(const class="type">class="kw">string _base_name,const class="type">bool _is_temp=false); }; class="macro">#include "CGlobalVar.mqh" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Script program start function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnStart() { CGlobalVar gVar1; class=class="str">"cmt">//--- create a temporary global var if(gVar1.Create("Gvar1",class="num">3.123456789101235,true)) { Print("\n---=== A new global var ===---"); PrintFormat("Name: \"%s\"",gVar1.Name()); PrintFormat("Is temporary: %d",gVar1.IsTemporary()); class=class="str">"cmt">//--- Get the value class=class="str">"cmt">//--- class="type">class="kw">double type class="type">class="kw">double d=class="num">0.0; class="type">class="kw">double dRes=gVar1.GetValue(d); PrintFormat("Double value: %class="num">0.15f",dRes); class=class="str">"cmt">//--- class="type">float type class="type">float f=class="num">0.0; class="type">float fRes=gVar1.GetValue(f); PrintFormat("Float value: %class="num">0.7f",fRes); class=class="str">"cmt">//--- class="type">class="kw">string type class="type">class="kw">string s=NULL; class="type">class="kw">string sRes=gVar1.GetValue(s); PrintFormat("String value: %s",sRes); class=class="str">"cmt">//--- Set a new value class="type">class="kw">double new_val=class="num">3.191; if(gVar1.Value(new_val)) PrintFormat("New value is set: %f",new_val); class=class="str">"cmt">//--- Set a new value on condition new_val=class="num">3.18; if(gVar1.ValueOnCondition(class="num">3.18,class="num">3.191)) PrintFormat("New value on conditionis set: %f",new_val); } }