MQL5 自定义指标入门:用价格行为把趋势结构画成信号(基础篇)
📊

MQL5 自定义指标入门:用价格行为把趋势结构画成信号(基础篇)

(1/3)· 很多交易者脑子里有结构突破逻辑,却卡在不会把它变成图表上的可视工具

偏理论 第 1/3 篇
你大概在图表上手动标过更高的低点、更高的高点,但每次切换周期就要重画一遍。把这套结构识别写成 MQL5 指标,逻辑一次成型、全周期自动跑,才是脱离手工盯盘的第一步。

◍ MQL5 自定义指标的内存与句柄机制

在 MT5 里写自定义指标,第一道坎不是画图,而是搞清数据怎么进、怎么存。MQL5 指标不直接读价格数组,而是通过 CopyBuffer 从已创建的技术指标句柄拉数据,这和 MQL4 里直接访问数组的写法完全不同。 一个容易踩的坑:指标句柄必须在 OnInit 里用 iMA / iRSI 等函数创建,若返回 INVALID_HANDLE(值为 -1),后续 CopyBuffer 会静默失败,指标线空白却不报错。实盘前务必在策略测试器用 2020–2025 年 XAUUSD 的 M15 数据跑一遍,确认句柄有效。 外汇与贵金属杠杆高、滑点突变频繁,句柄失效可能导致信号延迟甚至反向,回测通过不等于 live 环境稳。开 MT5 按 F4 建个空指标模板,先 Print(Handle) 看返回值再写逻辑。

用项目把 MQL5 基础串成趋势指标

本篇不是从零讲语法,而是接着前面几篇已经铺开的基础继续往前走。如果你已经写过简单的脚本或指标,这里直接进项目:做一个能识别趋势、抓结构突破并吐出买卖信号的自定义指标。 指标会标出 L、H、HL、HH、LL、LH 这些结构点,据此画溢价区、折价区和 50% 回撤位;在多头结构里按风险回报比算潜在利润目标,并给出入场、止损与多档止盈。 学习方法只有一条:水平由你做完的项目定义。本系列始终用基于项目的方式推进,这一节就落地一个价格行为趋势跟踪指标,你开 MT5 新建自定义指标就能跟着复现。外汇与贵金属波动剧烈,这类信号仅作概率参考,实盘前务必在策略测试器跑历史数据验证。

「指标怎么判定趋势与挂单位」

这套指标先把市场结构拆成四类点:低点、高点、更高的低点、更高的高点。上升趋势里,它取更高低点到更高高点的区间,算出 50% 回撤位,价格突破更高高点时触发买入,止损就压在那根 50% 线上。 下跌方向反过来处理:先抓高点、低点、更低的高点、更低的低点,用更低高点到更低低点的中间位做止损,价格跌破更低低点才进场卖。 盈亏比写死在两档:TP1 是 1:1,TP2 是 1:2。外汇和贵金属波动大、滑点频繁,这种固定比值的止损止盈在重大数据行情里可能被瞬间扫掉,实盘前建议在 MT5 用历史数据跑一遍结构识别准确率。

◍ 用 MQL5 把波段点拼成趋势结构

任何交易逻辑只要能写成规则,就能在 MT5 里变成可视化指标。价格行为最核心的原材料是摆动高点与摆动低点:把当前柱的最高/最低价,同前一根、后一根比较,就能用 IsSwingLow() / IsSwingHigh() 抓出转折。更高的高点、更高的低点、更低的高点、更低的低点,全部建立在这个基础上。 看涨结构要求依序出现低点 L、高点 H、更高低点 HL、更高高点 HH,且必须满足 L < H && HL < H && HL > L && HH > H。代码中 LookbackBars 控制识别摆动点时前后回看几根;bars_check 控制总共扫描多少根(示例给到 1000),值越大覆盖越广但更吃算力。show_bullish 为 false 时即使结构成立也不画任何东西。 确认四点后,从 HL 到 HH 拉一个矩形框,用 lvl_50 = HL + ((HH - HL)/2) 算出 50% 线。框上方为溢价区、下方为折扣区。该指标不抄底折扣区,而是等价格收在 HH 上方、完全脱离溢价区才认买入——这过滤了多数回调假突破。 入场放在突破 HH 的阳线收盘,止损设在 lvl_50,TP1 为 1:1、TP2 为 1:2。n_bars 算框尾到 HL 的柱数,n_bars_2 算框尾到突破柱的柱数;要求 n_bars_2 < n_bars,避免信号离结构太远。所有 ObjectCreate 只在全部条件通过后执行,图表才不会堆满半成品。 看跌镜像处理:H、L、LH、LL 满足 H > L && LH < H && LH > L && LL < L 后,从 LH 到 LL 画框,等阴线收破 LL 才标卖出,SL 同样放 50% 线。外汇与贵金属杠杆高,结构失效时回撤可能快而深,任何信号都只是概率倾向。

下跌结构只是镜像翻转

下跌趋势的识别逻辑与上涨完全对称,只是把高点、低点的大小关系反过来:原来看涨要找更高的低点(HL)和更高的高点(HH),看跌就变成更低的低点(LL)和更低的高点(LH)。指标在阴线烛形上打卖出箭头和“卖出”字样,本质是把同一套摆动点判定函数倒序调用。 摆点判定的核心是两个函数:IsSwingLow 检查某根 K 线低点是否同时小于左右各 lookback 根 K 线的低点,是则为真;IsSwingHigh 则反过来比高点。下面这段是原文里的函数与参数声明,直接贴出来逐行看。 //+------------------------------------------------------------------+

//FUNCTION FOR SWING LOWS

//+------------------------------------------------------------------+ bool IsSwingLow(const double &low[], int index, int lookback) { for(int i = 1; i <= lookback; i++) {

if(low[index] > low[index - i]low[index] > low[index + i])

return false; } return true; } //+------------------------------------------------------------------+

//FUNCTION FOR SWING HIGHS

//+------------------------------------------------------------------+ bool IsSwingHigh(const double &high[], int index, int lookback) { for(int i = 1; i <= lookback; i++) {

if(high[index] < high[index - i]high[index] < high[index + i])

return false; } return true; } 上面 IsSwingLow 中,low[index] 是当前考察 K 线低点,循环比对左侧 index-i 与右侧 index+i 共 2*lookback 根 K 线,只要有一根更低就返回 false,全段更低才认作摆动低点。IsSwingHigh 同理,只是比较方向换成“有更高就否”。 输入参数里 LookbackBars=10 控制摆点左右回看根数,bars_check=1000 是总共扫描的历史 bar 数,show_bullish=true 控制是否绘制买入信号。外汇与贵金属杠杆高、滑点跳空频繁,摆点识别在极端行情中可能滞后,实盘前务必在 MT5 用历史数据跑一遍验证。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| FUNCTION FOR SWING LOWS                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool IsSwingLow(const class="type">class="kw">double &low[], class="type">int index, class="type">int lookback)
  {
   for(class="type">int i = class="num">1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
        class="kw">return class="kw">false;
     }
   class="kw">return true;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| FUNCTION FOR SWING HIGHS                                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool IsSwingHigh(const class="type">class="kw">double &high[], class="type">int index, class="type">int lookback)
  {
   for(class="type">int i = class="num">1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
        class="kw">return class="kw">false;
     }
   class="kw">return true;
  }
class=class="str">"cmt">// CHART ID
class="type">long chart_id = ChartID();
class=class="str">"cmt">// Input parameters
input class="type">int   LookbackBars = class="num">10;   class=class="str">"cmt">// Number of bars to look back/forward for swing points
input class="type">int   bars_check   = class="num">1000; class=class="str">"cmt">// Number of bars to check for swing points
input class="type">bool show_bullish = true; class=class="str">"cmt">//Show Buy Signals
class=class="str">"cmt">// Variables for Bullish Market Structure
class="type">class="kw">double L;            class=class="str">"cmt">// Low: the starting low point in the up trend
class="type">class="kw">datetime L_time;     class=class="str">"cmt">// Time of the low
class="type">class="kw">string L_letter;     class=class="str">"cmt">// Label for the low point(e.g., "L")
class="type">class="kw">double H;            class=class="str">"cmt">// High: the first high after the low
class="type">class="kw">datetime H_time;     class=class="str">"cmt">// Time of the high
class="type">class="kw">string H_letter;     class=class="str">"cmt">// Label for the high point(e.g., "H")
class="type">class="kw">double HL;           class=class="str">"cmt">// Higher Low: the next low that is higher than the first low
class="type">class="kw">datetime HL_time;    class=class="str">"cmt">// Time of the higher low
class="type">class="kw">string HL_letter;    class=class="str">"cmt">// Label for the higher low point(e.g., "HL")
class="type">class="kw">double HH;           class=class="str">"cmt">// Higher High: the next high that is higher than the first high
class="type">class="kw">datetime HH_time;    class=class="str">"cmt">// Time of the higher high
class="type">class="kw">string HH_letter;    class=class="str">"cmt">// Label for the higher high point(e.g., "HH")
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator initialization function                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {

「摆动点识别的循环收尾与对象清理」

指标的退出函数只做一件事:把当前图表上由本程序绘制的全部图形对象清掉。 OnDeinit 里直接调用 ObjectsDeleteAll(chart_id),避免切换周期或移除 EA 时残留箭头和线段。 OnCalculate 的牛势分支里,先判断 show_bullish 开关,再用 rates_total >= bars_check 确认 K 线数量够用,否则不进循环。 内层从 i = rates_total - bars_check 扫到 rates_total - LookbackBars,遇到 IsSwingLow 就记下低价 L、时间 L_time 和标签名,再嵌套 j 循环向后找 IsSwingHigh 且时间晚于 L_time 的摆动高点,从而配对出一段可能的上升结构。外汇与贵金属波动剧烈,这类结构仅作概率参考,实盘须自担高风险。

MQL5 / C++
class=class="str">"cmt">//--- indicator buffers mapping
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
   }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
   ObjectsDeleteAll(chart_id);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Custom indicator iteration function                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(const class="type">int rates_total,
                const class="type">int prev_calculated,
                const class="type">class="kw">datetime &time[],
                const class="type">class="kw">double &open[],
                const class="type">class="kw">double &high[],
                const class="type">class="kw">double &low[],
                const class="type">class="kw">double &close[],
                const class="type">long &tick_volume[],
                const class="type">long &volume[],
                const class="type">int &spread[])
  {
class=class="str">"cmt">//---
   if(show_bullish == true) class=class="str">"cmt">// Check if the bullish trend is to be displayed
     {
      if(rates_total >= bars_check) class=class="str">"cmt">// Ensure enough bars are available for analysis
        {
         class=class="str">"cmt">// Loop through the price data starting from a certain point based on bars_check and LookbackBars
         for(class="type">int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
           {
            class=class="str">"cmt">// Check if the current bar is a swing low
            if(IsSwingLow(low, i, LookbackBars))
              {
               class=class="str">"cmt">// Store the values for the swing low
               L = low[i];
               L_time = time[i];
               L_letter = StringFormat("Low%d", i);
               class=class="str">"cmt">// Loop through further to find a swing high after the low
               for(class="type">int j = i; j < rates_total - LookbackBars; j++)
                 {
                  class=class="str">"cmt">// Check if the current bar is a swing high and occurs after the identified swing low
                  if(IsSwingHigh(high, j, LookbackBars) && time[j] > L_time)
                    {
交给小布把结构识别跑起来
这些市场结构诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到 HL、HH、LL、LH 的自动标注,你只需专注判断破位是否有效。

常见问题

指标只做可视化与信号提示,不参与下单;EA 能自动执行交易。基础篇先写指标,能让你把价格行为逻辑跑通而不碰订单风险。
小布盯盘内置了结构点识别与溢价折价区域标注,无需你自己写代码即可看同款信号;要深度定制再回头学 MQL5 更顺。
上升趋势中每个回撤低点高于前低即 HL,每个反弹高点高于前高即 HH;连续出现 HH+HL 倾向看涨结构成立。
取 HL 与 HH 之间中段作为参考,价格回踩不破倾向延续;破位则结构可能失效,常作止损参考而非必守线。
外汇贵金属杠杆高、跳空频繁,结构假突破概率不低,信号仅作概率参考,实盘需自设风控。