一张图表上的多个指标(第 05 部分):将 MetaTrader 5 转变为 RAD 系统(I)(基础篇)
📘

一张图表上的多个指标(第 05 部分):将 MetaTrader 5 转变为 RAD 系统(I)(基础篇)

第 1/3 篇

◍ 把 MT5 当成 RAD 环境来用

很多交易者只把 MetaTrader 5 当成看图下单的终端,但它内嵌的 MQL5 编辑器加上指标容器机制,足以当作轻量 RAD(快速应用开发)系统来搭自己的分析面板。原文作者 Daniel Jose 在 2022 年 5 月 18 日发布的这篇笔记,到统计时已有 1,991 次浏览、2 条讨论,说明这种玩法在实战圈并非冷门。 核心思路是在一张图表上叠加多个自定义指标,各自负责一类计算(比如波动率、订单流、支撑阻力),再通过共享全局变量或图形对象联动。比起切换多个窗口,这种单图 RAD 模式能让你在盯盘时少漏信号,但外汇与贵金属杠杆高、滑点不可控,任何面板都只是概率辅助,不是决策保险。 要验证这条路是否适合你,直接开 MT5 新建一个空指标,把下面这段最小框架跑起来,观察它能否在主图画出一条横线——能跑通,就说明你的本地已经具备 RAD 改造基础。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                TestRadar.mq5 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property indicator_chart_window
class="macro">#class="kw">property indicator_buffers class="num">0
class="type">int OnInit()
{
   ObjectCreate(class="num">0,"radar_line",OBJ_HLINE,class="num">0,class="num">0,class="num">0);
   ObjectSetDouble(class="num">0,"radar_line",OBJPROP_PRICE,SymbolInfoDouble(_Symbol,SYMBOL_BID));
   class="kw">return(INIT_SUCCEEDED);
}
class="type">int OnCalculate(class="kw">const class="type">int rates_total,
                class="kw">const class="type">int prev_calculated,
                class="kw">const class="type">class="kw">datetime &time[],
                class="kw">const class="type">class="kw">double &open[],
                class="kw">const class="type">class="kw">double &high[],
                class="kw">const class="type">class="kw">double &low[],
                class="kw">const class="type">class="kw">double &close[],
                class="kw">const class="type">long &tick_volume[],
                class="kw">const class="type">long &volume[],
                class="kw">const class="type">int &spread[])
{
   class="kw">return(rates_total);
}
class=class="str">"cmt">//+------------------------------------------------------------------+

「不写代码也能在图上做交易面板」

很多有交易想法的人卡在不会编程上,其实在 MT5 里可以借智能交易系统的内置函数,直接在图表上搭出市价单和挂单参数的操作界面,完全不用自己从头写逻辑。 原文作者演示的面板就是基于 MetaTrader 5 平台生成的,界面布局按预设图样排布,确认环境支持后,缺的只是把辅助代码先挂上去。 本篇承接系列前文,建议先翻完前几篇再动手;只要辅助层就位,你能在图上设计交易 IDE 的创意空间就只受自己想象力限制。外汇与贵金属杠杆高,这类自制面板仅降低操作门槛,不削减品种固有风险。

用 TPL 模板搭出自绘交易面板

开干前先把图表属性清干净:除掉所有会干扰对象定位的默认元素,只留一张空白图。我们的 IDE 最终存成设置文件(TPL 模板),MetaTrader 5 的对象里只有用 X/Y 坐标定位的才适合做界面件——文本、位图、事件这三类靠日期/价格锚定,直接排除。 实际能用的就六个:标签(102)、按钮(103)、位图标签(106)、编辑框(107)、矩形标签(110)。这数量足够拼出完整面板,且能贴到屏幕任意区域。建界面思路类似 RAD 拖控件:先铺背景,再自上而下叠对象,练两次就顺手。 TPL 里每个对象被包在 <object> 和 </object> 之间,type 变量决定种类(102=OBJ_LABEL,103=OBJ_BUTTON,106=OBJ_BITMAP_LABEL,107=OBJ_EDIT,110=OBJ_RECTANGLE_LABEL)。文件是 UTF-16 编码,用二进制读模式打开才不会漏字节。下面这段是 EA 原型里验证点击事件的代码: 先用 CHARTEVENT_OBJECT_CLICK 抓单击,Print 出 sparam 看到的只是 EA 自建对象名,不是 IDE 里的。解决办法是读 TPL 重建对象——分析文件时按行读,遇等号就拆键值,单行上限设 500 字符可改。 消息协议是 IDE 与 EA 通联的核心:MSG_BUY_MARKET 发市价买、MSG_SELL_MARKET 发市价卖、MSG_LEVERAGE_VALUE 杠杆、MSG_TAKE_VALUE 止盈、MSG_STOP_VALUE 止损、MSG_RESULT 持仓结果、MSG_DAY_TRADE 日内平仓通知。对象 NAME 属性对齐这些消息名就能收发音讯。def_MaxObject 设 40,前 8 个专用于消息通道,枚举 eObjectsIDE 里可见。 外汇和贵金属波动剧烈、杠杆风险高,面板只是降低操作延迟的工具,不预示任何方向。加载 IDE 必须绑 OBJ_CHART 左上角做 X 偏移基准,否则控件会跑偏;模板同名的干净文件放 Profiles\Templates 能压掉默认模板残留。

MQL5 / C++
class="type">void OnChartEvent(class="kw">const class="type">int id, class="kw">const class="type">long &lparam, class="kw">const class="type">class="kw">double &dparam, class="kw">const class="type">class="kw">string &sparam)
{
    class="kw">switch (id)
    {
        case CHARTEVENT_OBJECT_CLICK:
            Print(sparam);
            class="kw">break;
class=class="str">"cmt">// .... The rest of the code...
    }
}
<chart>
.... DATA
<window>
... DATA

◍ 多模板图表的加载与自适应排布

在 MT5 里做多品种 / 多指标同屏时,核心动作是把 .tpl 模板按类型塞进子窗口并自动算坐标。下面这段类方法展示了模板上限保护、符号预选与失败回退逻辑。 AddTemplate 先判断 m_Counter 是否触到 def_MaxTemplates,超了直接 return,避免无限制叠加子图导致终端卡死。若类型是 SYMBOL 会用 SymbolSelect 把品种加进市场观察,再调用 SetBase 绑定基准;模板应用失败且为符号类型时,回退到 Default.tpl,保证空窗不至于裸奔。 Resize 用宏 macro_SetInteger 批量改对象的 XDISTANCE、XSIZE、YSIZE。它读取当前子窗口的 CHART_WIDTH_IN_PIXELS 和 CHART_HEIGHT_IN_PIXELS,按计数器切分可用宽度;若某子图手动设了 width 就优先用定值,否则平分。注意 m_CPre 与 m_Counter 的差值会影响最后一个图表的分配比例。 Create 从 Chart Trade\IDE.tpl 以二进制读方式打开,句柄无效直接返回 false;随后 FileReadInteger(m_fp, SHORT_VALUE) 跳过模板头两字节长度标识。外汇与贵金属图表多开属高风险操作环境,实盘前应在模拟盘验证子窗体数量上限与重绘耗时。

MQL5 / C++
class="type">void AddTemplate(class="kw">const eTypeChart type, class="kw">const class="type">class="kw">string szTemplate, class="type">int scale, class="type">int iSize)
{
      if (m_Counter >= def_MaxTemplates) class="kw">return;
      if (type == SYMBOL) SymbolSelect(szTemplate, true);
      SetBase(szTemplate, (type == INDICATOR ? _Symbol : szTemplate), scale, iSize);
      if (!ChartApplyTemplate(m_handle, szTemplate + ".tpl")) if (type == SYMBOL) ChartApplyTemplate(m_handle, "Default.tpl");
      if (szTemplate == "IDE") C_Chart_IDE::Create(m_IdSubWin);
      ChartRedraw(m_handle);
}
class="type">void Resize(class="type">void)
{
class="macro">#define macro_SetInteger(A, B) ObjectSetInteger(Terminal.Get_ID(), m_Info[c0].szObjName, A, B)
      class="type">int x0 = class="num">0, x1, y = (class="type">int)(ChartGetInteger(Terminal.Get_ID(), CHART_HEIGHT_IN_PIXELS, m_IdSubWin));
      x1 = (class="type">int)((ChartGetInteger(Terminal.Get_ID(), CHART_WIDTH_IN_PIXELS, m_IdSubWin) - m_Aggregate) / (m_Counter > class="num">0 ? (m_CPre == m_Counter ? m_Counter : (m_Counter - m_CPre)) : class="num">1));
      for (class="type">char c0 = class="num">0; c0 < m_Counter; x0 += (m_Info[c0].width > class="num">0 ? m_Info[c0].width : x1), c0++)
      {
            macro_SetInteger(OBJPROP_XDISTANCE, x0);
            macro_SetInteger(OBJPROP_XSIZE, (m_Info[c0].width > class="num">0 ? m_Info[c0].width : x1));
            macro_SetInteger(OBJPROP_YSIZE, y);
            if (m_Info[c0].szTemplate == "IDE") C_Chart_IDE::Resize(x0);
      }
      ChartRedraw();
class="macro">#undef macro_SetInteger
}
class="type">bool Create(class="type">int nSub)
{
      m_CountObject = class="num">0;
      if ((m_fp = FileOpen("Chart Trade\\IDE.tpl", FILE_BIN | FILE_READ)) == INVALID_HANDLE) class="kw">return false;
      FileReadInteger(m_fp, SHORT_VALUE);
}

常见问题

直接存一个带指标和对象的 TPL 模板,加载到任意图表就能得到现成的自绘面板,不用碰代码。
把每种布局存成独立 TPL,在对应品种图表上手动或计划任务加载,MT5 会按模板自适应排布窗口和对象。
小布可读取你当前图表结构并生成适配的模板方案,省去手动摆控件的重复劳动,你只管确认布局。
检查模板里对象的坐标是否用了相对比例而非固定像素,改完重新存模板即可稳定自适应。
多半是屏幕分辨率或图表字体设置不同,统一显示缩放比例后再存一次 TPL 就能解决。