MQL5 编程基础: 终端的全局变量(基础篇)
📘

MQL5 编程基础: 终端的全局变量(基础篇)

第 1/3 篇

MT5 全局变量的真实边界

MT5 客户端里有一类全局变量(Global Variable),它不由 EA 私有,而是挂在终端进程下,所有 MQL5 程序都能读能写。和图表变量不同,这类变量在 EA 停止、图表关闭后依然存活,直到终端退出或手动清除才消失。 实测一个细节:全局变量带时间戳,每次写入都会刷新最后访问时间。官方文档给出的存活上限是永久驻留,但只要客户端重启,未被显式删除的全局变量依旧保留——这点对跨会话传递状态很有用,比如让两个独立 EA 共享一个开关标志。 高风险提示:外汇与贵金属杠杆交易波动剧烈,用全局变量做跨 EA 通信时,若某一程序异常崩溃留下脏值,另一程序可能误读,引发非预期下单。建议每次启动先做一次键值校验。 下面这段演示如何写、读、删一个全局变量:

MQL5 / C++
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。实测没必要堆几千个,纯属好奇。外汇贵金属脚本跑这套注意终端异常退出可能丢临时态,属高风险环境。

MQL5 / C++
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//| Class CGlobalVar&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |</span>
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="keyword">class</span> CGlobalVar : <span class="keyword">class="kw">public</span> CObject
&nbsp;&nbsp;{
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- === Data members === --- </span>
<span class="keyword">class="kw">private</span>:
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">string</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_name;
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_value;
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//---</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">datetime</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_create_time;
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">datetime</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_last_time;
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- flag for temporary var</span>
&nbsp;&nbsp; <span class="keyword">class="type">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_is_temp;
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- === Methods === --- </span>
<span class="keyword">class="kw">public</span>:
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- constructor/destructor</span>
&nbsp;&nbsp; <span class="keyword">class="type">void</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CGlobalVar(<span class="keyword">class="type">void</span>);
&nbsp;&nbsp; <span class="keyword">class="type">void</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const</span> <span class="keyword">class="type">class="kw">datetime</span> _create_time);
&nbsp;&nbsp; <span class="keyword">class="type">void</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ~CGlobalVar(<span class="keyword">class="type">void</span>){};
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- create/class="kw">delete</span>
&nbsp;&nbsp; <span class="keyword">class="type">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="keyword">const</span> <span class="keyword">class="type">bool</span> _is_temp=<span class="macro">false</span>);
&nbsp;&nbsp; <span class="keyword">class="type">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Delete(<span class="keyword">class="type">void</span>);
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- exist</span>
&nbsp;&nbsp; <span class="keyword">class="type">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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>);
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- set methods</span>
&nbsp;&nbsp; <span class="keyword">class="type">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Value(<span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> _var_val);
&nbsp;&nbsp; <span class="keyword">class="type">bool</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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);
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- get methods</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">string</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;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 操作,多程序抢同一个全局键时不容易互相覆盖。

MQL5 / C++
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);
  }
 }

常见问题

终端全局变量存活于终端进程内,关 EA 不影响;但退出终端或重启电脑后会被清除,需要持久化得写文件或数据库。
可用终端全局变量作为中介,一个 EA 写、另一个 EA 读,配合 GlobalVariableGet / GlobalVariableSet 这类函数即可。
小布可以读取并列出当前终端的全局变量名称与数值,提醒你哪些被遗忘的变量可能干扰 EA 通信。
可能变量名拼写不一致,或写入失败返回 false;建议先判断函数返回值,并用 GlobalVariableCheck 确认变量存在。
能把命名、读写、超时清理逻辑收进一个对象里,减少重复代码,降低 EA 之间因变量名冲突导致的 bug。