MQL5 Cookbook: 处理典型图表事件(基础篇)
◍ 在 MT5 里抓住图表上的典型事件
MT5 的图表不只是画 K 线,它会在用户操作时抛出一系列事件:新建对象、删除对象、鼠标点击、图表重绘等。想在 EA 或指标里对这些动作做出反应,就得理解 MQL5 的事件分发机制。 OnChartEvent 是接收图表事件的入口函数。它带五个参数:事件 ID、鼠标 X/Y、鼠标按键状态、以及附带的字符串 ID(常用于对象交互)。比如点击一个手动画的趋势线,事件 ID 会是 CHARTEVENT_OBJECT_CLICK,而字符串参数会带回该对象的名字。 下面这段最小可用代码,演示如何监听对象点击并打印对象名——把它塞进 EA 的 OnChartEvent 就能在终端日志里看到你点的是什么: 外汇与贵金属杠杆交易高风险,事件驱动逻辑只解决‘何时响应’,不解决‘该不该下单’的问题,信号触发后仍需人工复核。
class="type">void OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam) { if(id==CHARTEVENT_OBJECT_CLICK) Print("Clicked object: ", sparam); }
为什么要把 OnChartEvent 单独拎出来练
这一篇不重复 MQL5 文档和代码库里已有的处理器例程,而是把 OnChartEvent() 放到面向事件编程(EOP)的语境下,看它在真实图表交互里的表现。 官方和社区仓库里能找到标准事件的处理样例,但多数只演示“能跑”,没拆过它在半自动系统里怎么接决策链。 我的判断是:这个事件处理器既能喂给全自动逻辑做信号触发,也能在人工确认环节里当半自动系统的钩子,外汇和贵金属波动大、滑点风险高,用它做交互层比轮询图表状态更省资源。
「ChartEvent 到底在监听什么」
ChartEvent 是 MT5 图表在交互发生时抛出的事件信号,触发源很具体:激活图表里按键盘、新建或删除图形对象、在对象上点击、用鼠标拖拽对象,以及在 LabelEdit 的文本框里完成编辑。它把『人手动操作』和『EA 或脚本自动改图表』都统一成了同一种回调入口。 MQL5 用 ENUM_CHART_EVENT 枚举给这些事件分类,开发者在 OnChartEvent 里靠 id 参数分流处理。值得注意的是,枚举里留了一段用户自定义事件区间,程序员能用 EventChartCustom() 发最多 65535 个自定义标识符,相当于给自己的模块留了隐藏信道。 本文暂不展开自定义事件,但你在写面板类 EA 时应该先想清楚:哪些交互该走 ChartEvent、哪些该轮询对象属性。开 MT5 新建一个空 EA,在 OnChartEvent 打印 id 和参数,手动拖一下趋势线,就能看到事件流长什么样。
◍ 图表事件的收发双通道
MT5 里图表交互走的是事件驱动:鼠标、键盘、自定义信号全都进 OnChartEvent(),就像 OnInit() 接初始化、OnTrade() 接成交回执一样,分工明确。 OnChartEvent() 的四个入参全是 const,调用时由系统填好:id 告诉你触发的是哪类事件,lparam / dparam / sparam 则按事件类型分别承载长整型、双精度或字符串的附加信息。 想主动发事件,用 EventChartCustom()。它能往指定 chart_id 的图表(含当前图)塞一个自定义 id,并附带长整型、双精度、字符串三组载荷。下面这段就是两个函数的签名,注意接收端用 const 引用、发送端用值传递。 两者配合等于在 EA 和指标之间开了异步总线:一个图表算完信号,推给另一个图表立即重绘,省掉轮询。外汇与贵金属波动剧烈、滑点频发,这类自定义事件若用于下单联动,需先在模拟盘验证时序竞争。
class="type">void OnChartEvent(const class="type">int id, class=class="str">"cmt">// event identifier const class="type">long& lparam, class=class="str">"cmt">// parameter of the event of type class="type">long const class="type">class="kw">double& dparam, class=class="str">"cmt">// parameter of the event of type class="type">class="kw">double const class="type">class="kw">string& sparam class=class="str">"cmt">// parameter of the event of type class="type">class="kw">string ) class="type">bool EventChartCustom(class="type">long chart_id, class=class="str">"cmt">// receiving chart identifier class="type">class="kw">ushort custom_event_id,class=class="str">"cmt">// event identifier class="type">long lparam, class=class="str">"cmt">// the class="type">long parameter class="type">class="kw">double dparam, class=class="str">"cmt">// the class="type">class="kw">double parameter class="type">class="kw">string sparam class=class="str">"cmt">// the class="type">class="kw">string parameter )
图表事件的分支捕获骨架
MT5 的图表交互不是黑盒,MQL5 一共定义了 10 种典型图表事件,从按键、鼠标移动到图形对象的创建删除都涵盖。其中鼠标移动、对象创建、对象删除这 3 类,需要先调用 ChartSetInteger() 打开图表的事件响应开关,否则 EA 收不到信号。 下面这段 OnChartEvent 是最朴素的事件分发模板:用 switch(id) 把 10 种事件挨个 case 一遍,每个分支只往 comment 字符串里追加一句说明。把它挂到 EURUSD 或 XAUUSD 图表上跑,你在图面点一下、拖一根趋势线,左上角注释就会实时翻出“6) mouse click on chart”这类记录。 这套模板目前只能告诉你“刚才发生了什么”,离真正的策略逻辑还差一层。外汇和贵金属波动剧烈、杠杆高风险大,光靠事件回显做不了交易决策,下一步要往分支里塞具体的价格行为判断。 代码逐行拆解: void OnChartEvent(...) —— 系统回调入口,四个参数分别是事件ID、长整型参、双精度参、字符串参。 switch(id) —— 按事件编号分流。 CHARTEVENT_KEYDOWN —— 键盘按键,lparam 里是虚拟键码。 CHARTEVENT_MOUSE_MOVE —— 鼠标移动,dparam/lparam 带坐标。 CHARTEVENT_OBJECT_CREATE / CHANGE / DELETE —— 图形对象的增改删。 CHARTEVENT_CLICK / OBJECT_CLICK —— 图表空白处或对象上的单击。 CHARTEVENT_OBJECT_DRAG / ENDEDIT / CHART_CHANGE —— 拖拽对象、结束文本编辑、图表缩放平移。
class="type">void OnChartEvent(const class="type">int id, const class="type">long &lparam, const class="type">class="kw">double &dparam, const class="type">class="kw">string &sparam) { class="type">class="kw">string comment="Last event: "; class=class="str">"cmt">//--- select event on chart class="kw">switch(id) { class=class="str">"cmt">//--- class="num">1 case CHARTEVENT_KEYDOWN: { comment+="class="num">1) keystroke"; break; } class=class="str">"cmt">//--- class="num">2 case CHARTEVENT_MOUSE_MOVE: { comment+="class="num">2) mouse"; break; } class=class="str">"cmt">//--- class="num">3 case CHARTEVENT_OBJECT_CREATE: { comment+="class="num">3) create graphical object"; break; } class=class="str">"cmt">//--- class="num">4 case CHARTEVENT_OBJECT_CHANGE: { comment+="class="num">4) change object properties via properties dialog"; break; } class=class="str">"cmt">//--- class="num">5 case CHARTEVENT_OBJECT_DELETE: { comment+="class="num">5) class="kw">delete graphical object"; break; } class=class="str">"cmt">//--- class="num">6 case CHARTEVENT_CLICK: { comment+="class="num">6) mouse click on chart"; break; } class=class="str">"cmt">//--- class="num">7 case CHARTEVENT_OBJECT_CLICK: { comment+="class="num">7) mouse click on graphical object"; break; } class=class="str">"cmt">//--- class="num">8 case CHARTEVENT_OBJECT_DRAG: { comment+="class="num">8) move graphical object with mouse"; break; } class=class="str">"cmt">//--- class="num">9 case CHARTEVENT_OBJECT_ENDEDIT: { comment+="class="num">9) finish editing text"; break; } class=class="str">"cmt">//--- class="num">10 case CHARTEVENT_CHART_CHANGE: {
「把诊断结果甩到图表上」
这段收尾逻辑干的事很直接:当循环跑完所有检测项,把拼好的 comment 字符串通过 Comment() 推到 MT5 图表左上角,交易者不用切窗口就能看见当前品种卡在哪一步。 注意代码里 "10) modify chart" 配合 break,意味着若检测到需要改图表属性(比如周期不匹配或对象冲突),直接终止后续判断并标注第 10 类问题;这种提前跳出能避免重复报警刷屏。 在 MT5 里按 F4 把这段嵌进你已有的 OnCalculate 尾部,编译后拖到 XAUUSD 的 M15 上,就能实时看到注释输出;外汇与贵金属杠杆高、滑点跳空频繁,图表对象状态异常可能让你漏掉信号,建议每次加载 EA 前手动清一次图表对象。
comment+="class="num">10) modify chart"; break; } } class=class="str">"cmt">//--- Comment(comment); }