我们已经掌握了EA这栋“房子”内部的两种变量:放在独立房间的“私人物品”(局部变量),和放在大厅的“公共家具”(程序内全局变量)。但现在思考一个问题:如果整栋房子突然断电(MT4重启或崩溃),会发生什么?
答案是:房子里的一切“记忆”都会丢失。
为了解决这个问题,MQL4提供了一种特殊的工具,我们可以把它理解为存放在银行的“保险柜”,这个“银行”就是我们的MetaTrader终端本身。这就是终端级别的全局变量。
终端变量:独立于EA之外的“公共记事本”
这种变量有两大特性,使其与众不同:
- 持久性:“保险柜”里的东西,不会因为你的EA“房子”断电而消失。即使MT4重启,只要不清空,它就永远在那里。
- 公共性:这个“保险柜”更像是一个放在城市广场的“公共白板”。任何一个在该MT4上运行的EA,只要知道“暗号”(变量名),都可以来读取甚至擦写上面的内容。
用户可以随时通过MT4终端的菜单“工具” -> “全局变量”(或快捷键F3),来查看这块“公共白板”上都写了些什么。
我们什么时候需要使用这个“保险柜”?
最核心的用途是:状态保持与灾后恢复。
想象一个场景:你的EA有一个“每日最多交易5次”的规则。它用一个计数器来记录当天已交易次数。当交易了3次后,你的电脑突然蓝屏重启了。EA重启后,程序内部的普通全局变量计数器会重置为0,于是它会错误地认为今天还可以再交易5次。
但如果我们每完成一笔交易,都把当前的次数3
,用GlobalVariableSet()
函数写入到终端这个“保险柜”里。那么EA重启后,可以在OnInit()
函数中,先用GlobalVariableGet()
去“保险柜”里检查一下,它会发现“啊,我已经交易过3次了”,于是便知道今天只剩下2次机会。
学长建议:从设计的角度看,我们应尽量避免让EA依赖于复杂的、需要持久化的状态。但如果你的策略逻辑确实复杂,那么利用终端变量来做“灾后恢复”,就是目前最简单、最有效的方案。
使用的黄金法则:独一无二的“身份前缀”
因为这是个“公共白板”,为了防止你的EA留下的信息,被其他EA无意中涂改或擦除,我们必须为我们写的每一个变量,都加上一个独一无二的签名或“抬头”。这个“抬头”,就是我们的唯一前缀。
一个不负责任的EA会直接在白板上写"MyCounter = 3"
,而一个专业的EA会写"EURUSD_15_MySuperEA_12345_MyCounter = 3"
。
我们通常在OnInit()
函数中,动态地构建这个前缀:
// 程序内部的全局变量,用于存储前缀
string GlobalVariablePrefix;
int init()
{
// 构建唯一前缀,组合了品种、周期、EA名、魔术号等信息
GlobalVariablePrefix = Symbol() + (string)Period() + "_" + "ProfitBusterEA" + "_" + (string)MagicNumber + "_";
return(0); // init() 函数标准返回
}
核心操作函数
- 写入/设置:
GlobalVariableSet()
当你需要保存一个值时,记得把前缀和你的变量名拼接起来。GlobalVariableSet(GlobalVariablePrefix + "MyCounter", CurrentCounterValue);
- 读取/获取:
GlobalVariableGet()
同样,读取时也要用完整的前缀+变量名去寻找。CurrentCounterValue = GlobalVariableGet(GlobalVariablePrefix + "MyCounter");
- 删除:
GlobalVariableDel()
和GlobalVariableDeleteAll()
一个行为良好的EA,应该在它被移除时(在OnDeinit()
函数中),清理掉自己在“公共白板”上留下的所有信息。// 删除单个变量 GlobalVariableDel(GlobalVariablePrefix + "MyCounter"); // 删除此前缀下的所有变量,一键清扫 GlobalVariableDeleteAll(GlobalVariablePrefix);
学长避坑指南: 终端变量的“保险柜”只能直接存放double
类型的数值。如果你想存字符串或布尔值,需要做一些变通(比如用1.0代表true
,0.0代表false
),这在一定程度上限制了它的使用场景。
总而言之,终端全局变量是一个强大的高级工具,它为我们提供了跨越程序重启的“记忆”能力。虽然不常用,但在构建需要管理复杂状态的、极其稳健的EA时,它是你工具箱中不可或缺的一件利器。