MQL5 Cookbook: 处理典型图表事件(基础篇)
📘

MQL5 Cookbook: 处理典型图表事件(基础篇)

第 1/3 篇

◍ 在 MT5 里抓住图表上的典型事件

MT5 的图表不只是画 K 线,它会在用户操作时抛出一系列事件:新建对象、删除对象、鼠标点击、图表重绘等。想在 EA 或指标里对这些动作做出反应,就得理解 MQL5 的事件分发机制。 OnChartEvent 是接收图表事件的入口函数。它带五个参数:事件 ID、鼠标 X/Y、鼠标按键状态、以及附带的字符串 ID(常用于对象交互)。比如点击一个手动画的趋势线,事件 ID 会是 CHARTEVENT_OBJECT_CLICK,而字符串参数会带回该对象的名字。 下面这段最小可用代码,演示如何监听对象点击并打印对象名——把它塞进 EA 的 OnChartEvent 就能在终端日志里看到你点的是什么: 外汇与贵金属杠杆交易高风险,事件驱动逻辑只解决‘何时响应’,不解决‘该不该下单’的问题,信号触发后仍需人工复核。

MQL5 / C++
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 和指标之间开了异步总线:一个图表算完信号,推给另一个图表立即重绘,省掉轮询。外汇与贵金属波动剧烈、滑点频发,这类自定义事件若用于下单联动,需先在模拟盘验证时序竞争。

MQL5 / C++
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 —— 拖拽对象、结束文本编辑、图表缩放平移。

MQL5 / C++
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 前手动清一次图表对象。

MQL5 / C++
   comment+="class="num">10) modify chart";
   break;
   }
  }
class=class="str">"cmt">//---
  Comment(comment);
  }

常见问题

用图表事件监听函数捕获鼠标和对象交互,在分支里判断事件ID即可,不需要轮询,事件触发才执行。
大概率没处理对象被拖动或删除的图表事件,补上对应事件分支并强制重绘就能解决。
可以,小布能接管这类图表事件流,把关键交互和对象变动做成看盘诊断,打开对应品种页就能看到。
不会,两者走同一监听入口但事件ID不同,用switch分支隔离处理就不会冲突。
在事件分支里调用图表文本绘制接口,按坐标把提示语甩到对应价格位置即可,注意控制刷新频率。