MQL5 细则手册:在单一窗口中监控多个时间表(基础篇)
📘

MQL5 细则手册:在单一窗口中监控多个时间表(基础篇)

第 1/3 篇

「把多个周期塞进一个窗口看」

MT5 默认每个图表只能挂一个时间框架,想同时盯 M1、M15、H1 的贵金属走势就得开三个窗口,切换起来很碎。 一个实用做法是利用子窗口指标把不同周期的合成价格曲线叠到主图下方,交易者可在单一图表里横向比对多周期节奏,外汇与贵金属波动大、杠杆高,此类多周期监控仅降低漏看概率,不预示方向。 实测中,这种多周期同窗方案在 2014 年社区示例帖获得 3641 次查看、6 条讨论,说明老交易员也常受多窗口之苦。

◍ 用子窗口图表对象避开多周期手动拼图

在 MT5 里判断建仓方向,同时看多个周期通常比单图表更靠谱。终端自带 21 个时间表可供分析,但要把它们并排摆出来,靠手工往图表上塞对象既慢又容易漏设属性。 MetaTrader 5 允许在已有图表上叠加特殊图表对象,单独指定交易品种、周期等参数,数量不限。问题在于:人工添加时,部分属性(如某些显示开关)根本调不了,只能走代码。 本文思路是用指标+按钮在子窗口里批量生成这些对象。按钮不只管「加图表」,也管启停那些只能编程修改的属性。这样主图缩放或终端窗口变化时,子窗口里的多周期对象能自动校正位置,不用你每次手拖。

把多周期图表对象塞进一个指标文件

MT5 里手动插图表对象只能调很少的属性,买价卖价线、右侧缩进、交易价位这些必须写代码才显示。要做可控面板,得用 MQL5 向导建自定义指标模板,事件处理程序选带 OnDeinit 的那类——模板里 OnCalculate 留空也能编译,但缺了它不行。 核心思路是做一个虚拟指标 SubWindow,编译成 ex5 后用 #resource 指令嵌进主指标 ChartObjects.ex5,终端用户只拿到一个文件。主程序开头加 #resource "SubWindow.ex5" 和 #define 数组尺寸,再声明时间表按钮、属性按钮、对象名三组数组。 创建对象靠两个函数:CreateButton 出 OBJ_BUTTON,CreateChartInSubwindow 在子窗口出 OBJ_CHART,后者设完标准属性后必须调 ChartRedraw 刷新。删除指标时 OnDeinit 要清掉所有自建对象,否则图表留垃圾。 交互全走 OnChartEvent。CHARTEVENT_OBJECT_CLICK 里用 sparam 判按钮名,分派给 ToggleSubwindowAndChartObject(切周期)和 ToggleChartObjectProperty(改属性);CHARTEVENT_CHART_CHANGE 里用 ChartEventChartChange 抓主图缩放,通过 GetSubwindowWidthAndHeight 取尺寸再 AdjustChartObjectsSizes 重绘子窗对象。实测挂上指标后,点 H4/D1 按钮子窗出对应图表,拖主图窗口对象尺寸跟着变。外汇贵金属插件开发请自测,脚本异常可能引图表卡顿。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                     ChartObjects.mq5 |
class=class="str">"cmt">//|    Copyright class="num">2013, MetaQuotes Software Corp. |
class=class="str">"cmt">//|             [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2013, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#class="kw">property indicator_chart_window
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator initialization function                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- indicator buffers mapping

class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator iteration function                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(class="kw">const class="type">int rates_total,

「把交易事件回调空壳接进指标框架」

在 MT5 自定义指标里,OnTradeTransaction 与 OnChartEvent 是两套常被忽略的内置回调。上面这段代码把它们的函数签名原样留空,说明指标暂不处理成交流水与图表交互事件,但框架已经就位。 关键参数上,OnTradeTransaction 接收 MqlTradeTransaction、MqlTradeRequest、MqlTradeResult 三个引用结构,分别对应成交事务、原始请求与执行结果;OnChartEvent 则吃进 id、lparam、dparam、sparam 四个参数,覆盖鼠标、键盘、自定义事件等全部图表消息。 指标属性里 #property indicator_plots 0 意味着本例不在主图绘制任何缓冲区,仅借主图窗口挂接逻辑。若你要在贵金属或外汇品种上捕获某根 K 线后的手动平仓动作,直接往 OnTradeTransaction 的空函数体里填 trans.type 判断即可,省去另写 EA 的麻烦。外汇与贵金属杠杆高,事件触发后的下单逻辑务必先开模拟盘验证。 顺手把 Calculate 里 return(rates_total) 记住:它把已计算柱数回传给定时器,避免下一帧重算全部历史,这是降低 CPU 占用的标准写法。

MQL5 / C++
class="kw">const class="type">int prev_calculated,
class="kw">const class="type">int begin,
class="kw">const class="type">class="kw">double &price[])
{
class=class="str">"cmt">//---

class=class="str">"cmt">//--- class="kw">return value of prev_calculated for next call
  class="kw">return(rates_total);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| TradeTransaction function                                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTradeTransaction(class="kw">const MqlTradeTransaction& trans,
                        class="kw">const class="type">MqlTradeRequest& request,
                        class="kw">const class="type">MqlTradeResult& result)
{
class=class="str">"cmt">//---

}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| ChartEvent function                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
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=class="str">"cmt">//---

}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                 ChartObjects.mq5 |
class=class="str">"cmt">//|          Copyright class="num">2013, MetaQuotes Software Corp.                |
class=class="str">"cmt">//|                 [MQL5官方文档]                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2013, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//---
class="macro">#class="kw">property indicator_chart_window class=class="str">"cmt">// Indicator is in the main window
class="macro">#class="kw">property indicator_plots class="num">0      class=class="str">"cmt">// Zero plotting series
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator initialization function                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- Set the class="type">class="kw">short name for the indicator

◍ 指标骨架里那些空函数不是摆设

这段 MQL5 片段给自研面板指标搭了最薄的一层骨架:OnInit 里用 IndicatorSetString(INDICATOR_SHORTNAME,"TimeFramesPanel") 把副图短名钉死,返回 INIT_SUCCEEDED 即算初始化过关。 OnDeinit 只判断了 reason==REASON_REMOVE,也就是指标被从图表删掉时的分支,目前大括号内是空的——但这不等于没用,后面要释放画过的 OBJ_LABEL、OBJ_RECTANGLE 等资源就得填在这里。 OnCalculate 直接 return(rates_total),等于告诉内核「每次都全量重算」,对于不画缓冲区的面板类指标是省事写法,代价是每来一根 tick 都跑一遍,CPU 占用倾向随品种刷新率线性走。 OnChartEvent 留空,说明交互(点击切换周期等)还没接;indicator_plots 设成 0 也印证了它根本不输出曲线,纯靠 ObjectCreate 往图上贴。开 MT5 把这段存成 .mq5 编译,能在导航栏看到 TimeFramesPanel 但图表上暂时什么都不会发生。

MQL5 / C++
IndicatorSetString(INDICATOR_SHORTNAME,"TimeFramesPanel");
class=class="str">"cmt">//--- Initialization completed successfully
  class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Indicator deinitialization                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(class="kw">const class="type">int reason)
  {
class=class="str">"cmt">//--- If the indicator has been deleted from the chart
  if(reason==REASON_REMOVE)
    {
    }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator iteration function                               |
class=class="str">"cmt">//+------------------------------------------------------------------+
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">int begin,
                class="kw">const class="type">class="kw">double &price[])
  {
class=class="str">"cmt">//---
class=class="str">"cmt">//--- class="kw">return value of prev_calculated for next call
  class="kw">return(rates_total);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| ChartEvent function                                               |
class=class="str">"cmt">//+------------------------------------------------------------------+
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=class="str">"cmt">//---
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                            SubWindow.mq5          |
class=class="str">"cmt">//|           Copyright class="num">2013, MetaQuotes Software Corp.               |
class=class="str">"cmt">//|                 [MQL5官方文档]                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2013, MetaQuotes Software Corp."
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//---
class="macro">#class="kw">property indicator_chart_window class=class="str">"cmt">// Indicator is in the subwindow
class="macro">#class="kw">property indicator_plots class="num">0      class=class="str">"cmt">// Zero plotting series
class=class="str">"cmt">//+------------------------------------------------------------------+

把副图指标挂进资源里再调按钮

上面这段是自定义指标初始化与调用的骨架。OnInit 里只做了一件事:用 IndicatorSetString(INDICATOR_SHORTNAME,"SubWindow") 给指标设短名,返回 INIT_SUCCEEDED 表示加载成功;OnCalculate 目前直接 return(rates_total),即把已计算柱数原样交回给下一轮,没填任何缓冲逻辑,属于占位结构。 真正决定面板形态的是文件尾部的资源声明与宏。#resource 把编译好的 SubWindow.ex5 嵌进当前程序,路径写成 "\\Indicators\\SubWindow.ex5";TIMEFRAME_BUTTONS 定为 21、PROPERTY_BUTTONS 定为 5,说明这套 UI 预设了 21 个周期切换键加 5 个图表属性键。 副图句柄先置 INVALID_HANDLE、subwindow_number 给 -1,代表还没绑到具体窗口。颜色变量分两套:未按下态用白字、深石板灰底、浅灰边;按下态换金字、背景 C'28,47,47'(RGB 28/47/47 的暗青)。开 MT5 把这段贴进 mq5,改一下 TIMEFRAME_BUTTONS 数量,能直接看到按钮排布变化。

MQL5 / C++
class=class="str">"cmt">//| Custom indicator initialization function                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- Set the class="type">class="kw">short name for the indicator
   IndicatorSetString(INDICATOR_SHORTNAME,"SubWindow");
class=class="str">"cmt">//--- Initialization completed successfully
   class="kw">return(INIT_SUCCEEDED);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator iteration function                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
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">int begin,
                class="kw">const class="type">class="kw">double &price[])
  {
class=class="str">"cmt">//---

class=class="str">"cmt">//--- class="kw">return value of prev_calculated for next call
   class="kw">return(rates_total);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//--- Include indicator resource
class="macro">#resource "\\Indicators\\SubWindow.ex5"
class=class="str">"cmt">//--- Number of time frame buttons
class="macro">#define TIMEFRAME_BUTTONS class="num">21
class=class="str">"cmt">//--- Number of buttons for chart object properties
class="macro">#define PROPERTY_BUTTONS class="num">5
class=class="str">"cmt">//--- Location of the SubWindow indicator in the resource
class="type">class="kw">string subwindow_path       ="::Indicators\\SubWindow.ex5";
class="type">int    subwindow_number     =-class="num">1;                class=class="str">"cmt">// Subwindow number
class="type">int    subwindow_handle     =INVALID_HANDLE;    class=class="str">"cmt">// SubWindow indicator handle
class="type">class="kw">string subwindow_shortname  ="SubWindow";       class=class="str">"cmt">// Short name of the indicator
class=class="str">"cmt">//---
class="type">int    chart_width          =class="num">0;                 class=class="str">"cmt">// Chart width
class="type">int    chart_height         =class="num">0;                 class=class="str">"cmt">// Chart height
class="type">int    chart_scale          =class="num">0;                 class=class="str">"cmt">// Chart scale
class=class="str">"cmt">//---
class="type">color  cOffButtonFont       =clrWhite;          class=class="str">"cmt">// Unclicked button text class="type">color
class="type">color  cOffButtonBackground =clrDarkSlateGray;  class=class="str">"cmt">// Unclicked button background class="type">color
class="type">color  cOffButtonBorder     =clrLightGray;      class=class="str">"cmt">// Unclicked button border class="type">color
class=class="str">"cmt">//---
class="type">color  cOnButtonFont        =clrGold;           class=class="str">"cmt">// Clicked button text class="type">color
class="type">color  cOnButtonBackground  =C&class="macro">#x27;class="num">28,class="num">47,class="num">47&class="macro">#x27;;       class=class="str">"cmt">// Clicked button background class="type">color

常见问题

用子窗口图表对象把不同周期画进同一个主图窗口,避免手动拼多个图表,具体可用指标文件里挂多周期对象实现。
把多周期图表对象塞进一个指标文件,并将副图指标挂进资源里用按钮调用,加载一次即可复用。
小布可内置多周期监控逻辑,打开对应品种页就能替你看各周期异动并提示,把重复劳动交给它。
空函数如事件回调壳是框架预留位,不填内容不会报错,但接进交易事件后才能用,别当废代码删。
贵金属杠杆高、跳空多,多周期同窗只辅助看概率倾向,不构成交易依据,需自担高风险。