我受够了错过MT4的报警。不是因为我不专心,而是MT4里那个
Comment()函数,基本上就是个摆设。你在左上角写一句话,下一笔tick过来直接给你清了。Alert()更离谱,弹个窗几秒钟就没了,或者响个声音——要是你刚好不在电脑前,等于白报。上个月我在测一个新EA,回测跑了一个小时回来看,中间发生过什么事完全不知道。开过几单、有没有报错、改过几次止损,全没记录。我就开始翻MQL4的文档,还真让我找到了一个大多数人都跳过去的东西——
#property indicator_separate_window加上ObjectCreate()画标签的方法。默认的报警方式为什么不好用
在讲解决方案之前,我先说一下为什么MT4默认的那几招对跑回测的人来说都不太顶用。
Comment()在图表角落显示文本,简单,但它只保留你最后写的那句话。下一笔tick一来,前面的全没了。如果你的EA在一个tick里干了好几件事——开仓、改止损、报个错——你只能看到最后一条,前面的信息全丢。Alert()弹个窗,但弹窗不堆叠。EA连续触发三条报警,你可能只看到最后一条就没了。Print()往终端的"EA交易"标签页里写日志,这个其实还行,但你要手动去翻,而且那个标签页里还混着其他EA和终端自己的各种信息,看得很累。我想要的是能持续显示、像聊天记录一样往上堆、而且不用我去翻日志的东西。
自定义指标做消息窗口
MQL4文档其实专门有一节讲这个,在"创建普通程序"那一章里。方案是用一个自定义指标,这个指标的唯一作用就是开一个子窗口,然后在里面用图形对象显示文本消息。指标本身不做任何计算,就是个容器。
核心思路是这样的:
#property indicator_separate_windowOnCalculate()函数是空的,不干活Inform.mqh)来管理所有图形对象的创建和排布MQL4教程里给了一个完整的模板。
Inform()函数接收消息编号和可选的整数/实数参数,然后创建一个标签对象存起来,通过调整Y坐标来滚动消息列表。第一步:建一个容器指标
MetaEditor里新建一个自定义指标,叫
Inform.mq4,代码极其简单:``
mql4
//--------------------------------------------------------------------
// Inform.mq4
// 仅供学习参考使用
//--------------------------------------------------------------------
#property indicator_separate_window // 独立的指标窗口
//--------------------------------------------------------------------
int start() // 特殊函数start()
{
}
//--------------------------------------------------------------------
`
就这么几行。指标本身什么事都不干,就是开一个子窗口让你写消息。
第二步:消息管理逻辑
真正干活的是Inform.mqh。MQL4教程里给了一个完整的实现,最多能存30条消息,新消息来了旧的自动往上滚。
几个关键函数:
Inform(0)——每笔tick调用一次,检查消息是不是超时了。连续15秒没有新消息,所有已显示的消息就变灰色。这个设计很贴心——瞟一眼颜色就知道EA是不是还活着。
Inform(-1)——EA卸载的时候调用,把所有图形对象删掉。做清理很重要,因为MT4不会自动清理你创建的标签。
Inform(Mess_Number, Number, Value)——主函数。根据Mess_Number生成对应格式的消息。每个编号对应一个模板,比如"Closed order Buy X"或者"Not enough money for X lots"之类。
消息系统用一个数组Name_Grf_Txt[30]存所有标签的名字。来新消息的时候:
删掉第29条(最老的那条)
把第28到第0条全部上移一个位置
在最下面新建一个标签
这样你就有了一个能滚动的30条消息历史,而且还能按类型设颜色。
第三步:把消息系统挂到自己的EA里
要在自己的EA里用这个,先把Inform.mq4放到MQL4/Indicators目录里编译一遍。再把Inform.mqh放到MQL4/Include目录。
在EA代码里加上:
`mql4
#include
`
然后想发消息的时候直接调Inform()就行:
`mql4
Inform(1, ticket); // "Closed order Buy X"
Inform(11, 0, lots); // "Not enough money for X lots"(红色字体)
`
函数内部还带了PlaySound(),所以音频提醒和文字记录一块来,不会错过。
为什么这个方案比别的都好用
这个方案解决的是"离开一会儿回来不知道发生了什么"的问题。你跑出去喝杯水再回来,消息窗口里清清楚楚列着EA在你这段时间里干了什么。不用翻日志、不用猜刚才那个声音是开仓还是报错。
我最近三周在三个不同EA上都用了这套。每个EA单独开一个消息窗口,互不干扰。跑回测的时候,我能看到完整的事件序列,不用停掉回测去翻日志。
性能方面有个坑要注意
图形对象不停地创建和删除,如果你每秒发几十条消息,EA确实会变慢。但MQL4教程里的实现只用了30个对象,来了新消息就复用旧的,不会无限制地新建,所以性能开销其实还好。
如果是高频策略,可以把消息数量砍到10或15条,改一下数组大小和循环上限就行。
说个真实例子
上周我有个EA老是在不该平仓的时候自己平掉。我把Inform()加到了所有决策点——入场条件、止损触发、止盈触发。EA再瞎操作的时候,我直接看消息窗口就知道它在哪一步抽风了。最后查出来是移动止损的计算逻辑写错了。如果没有消息历史,我可能要在日志里翻半天才能找到问题。
MQL4官方教程里"Combined Use of Programs"那一章有一个完整示例,展示了怎么把这个消息系统跟iCustom()`结合起来做基于自定义指标的交易决策。参考来源:MQL4教程 – 创建普通程序(book.mql4.com),MQL4参考 – 自定义指标(docs.mql4.com),MQL4教程 – 程序的组合使用(book.mql4.com)。
本文首发于FXEAR.com,原创内容,未经授权禁止转载。