使用MQL4和MQL5绘制基于分形指标的趋势线(基础篇)
📘

使用MQL4和MQL5绘制基于分形指标的趋势线(基础篇)

第 1/3 篇

「用分形指标在 MT5 上画趋势线」

MQL5 里画趋势线不一定要手动拖,分形指标(Fractal)自带的高点和低点就能当锚点。2015 年 8 月那篇原帖在 MT5 上跑通了这套逻辑,至今论坛仍有 8500+ 阅读、29 条讨论,说明手动派也在找自动化替代。 分形定义很硬:上分形 = 中间 K 线最高价高于左右各两根 K 线最高价;下分形反之。拿到这些极值后,用 ObjectCreate 在图表上连成线段,就得到一条贴着波峰波谷的趋势线。 外汇和贵金属波动大、滑点频繁,这类线只是概率参考,不能当成入场保证。开 MT5 新建脚本,把下面代码丢进去编译,就能看到自动连出的分形趋势线。

MQL5 / C++
class="type">int OnInit()
{
   class="type">int fractal = iFractals(NULL, class="num">0);
   for(class="type">int i = class="num">3; i < Bars; i++)
   {
      class="type">class="kw">double up = CopyBuffer(fractal, class="num">0, i, class="num">1, NULL);
      if(up != EMPTY_VALUE)
         ObjectCreate(class="num">0, "TL" + i, OBJ_TREND, class="num">0, Time[i], up, Time[i-class="num">3], up);
   }
   class="kw">return(INIT_SUCCEEDED);
}

◍ 这套分形趋势线脚本到底干了什么

这个 MQL5 脚本把比尔·威廉姆斯分形逻辑搬进了 MT5,自动找最近的分形点并连成趋势线,省掉手动画的麻烦。它一共拆成七步跑:先处理输入参数和 DeInit 释放,再扫最近分形,定位价格与时间,接着用对象函数重绘趋势线,顺手查历史数据是否加载完整,最后在价格突破趋势线时发推送并聊实战用法。 对老手来说,重点不是「指标多神」,而是它把「分形突破」这件事变成了可回测、可告警的机器流程。你开 MT5 把脚本挂上 EURUSD 的 H1,大概率能看到最近 N 根 K 线里上下分形被自动连线,突破瞬间手机弹通知。 外汇和贵金属杠杆高、滑点猛,分形假突破是常态,任何信号都只是概率倾向,别拿它当入场圣旨。

用分形给趋势线定锚点

画趋势线最烦的是取点:肉眼在 H4 甚至日线定的分形极点,挪到 M15 上时间轴往往对不上,极值发生的那一两根 K 线被压缩掉了。作者自己兼顾分析与交易,需要把极点精度压到 15 分钟图,纯手工拖线既累又容易偏,于是转向用分形做客观基准。 他先用 MQL5 写了一套逻辑,再移植回 MQL4,原因是实盘跑在 MetaTrader 4 上。这里明确一点:文章同时给 MQL4/MQL5 两种实现,并不是要比谁跑得快,只是覆盖不同平台用户。外汇与贵金属杠杆高、滑点突发行情多,分形极点也只是概率性支撑阻力,别当成铁律。 对刚学写脚本的人,这套以分形+趋势线为核心的思路能直接抄去改:哪怕你只用 MT5,也能先把 MQL5 版跑通,再看极点识别和画线误差。作者也坦承可能有更优解法,所以验证时建议自己换周期比对分形偏移量。

「EA参数与初始化时的对象清理」

画支撑阻力线得先声好输入参数:阻力线、支撑线各自有颜色、线型、线宽三个 input 变量,默认线宽都是 1,颜色先用 Red 占位,线型留空由交易者自己选。 MQL5 里因为靠图形对象画线,EA 从图表卸载时必须把对象删掉,否则残留线会干扰后续判断。OnDeinit() 里直接 ObjectDelete 掉 TL_Resistance 和 TL_Support 两个命名对象即可。 初始化阶段用 OnInit() 拿 iFractals 指标句柄,注意示例绑定的是 PERIOD_D1 周期,换品种或周期需改 Symbol() 与周期常量。 支撑阻力各需两个点,极点靠分形定位。MQL5 比 MQL4 多声明了 FractalDown[]、FractalUp[] 两个 double 数组承接指标缓存,以及 UpFractal_1/2、LowFractal_1/2 存极点价格;K线索引仍用 UpperFractal_1/2、LowerFractal_1/2 记录。开 MT5 把下面代码贴进 EA,能直接编译出带日线分形句柄的空壳。

MQL5 / C++
input class="type">color Resistance_Color=Red;       class=class="str">"cmt">// 设置阻力线颜色
input ENUM_LINE_STYLE Resistance_Style; class=class="str">"cmt">// 设置阻力线类型
input class="type">int Resistance_Width=class="num">1;           class=class="str">"cmt">// 设置阻力线宽度
input class="type">color Support_Color=Red;          class=class="str">"cmt">// 设置支撑线颜色
input ENUM_LINE_STYLE Support_Style;    class=class="str">"cmt">// 设置支撑线类型
input class="type">int Support_Width=class="num">1;              class=class="str">"cmt">// 设置支撑线宽度
class=class="str">"cmt">//--- iFractals 指标句柄 
class="type">int Fractal;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA初始化函数                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 获取iFractals指标句柄
   Fractal=iFractals(Symbol(),PERIOD_D1);
class=class="str">"cmt">//---
   class="kw">return(INIT_SUCCEEDED);
  }
class="type">void OnDeinit(const class="type">int reason)
  {
   ObjectDelete(class="num">0,"TL_Resistance");
   ObjectDelete(class="num">0,"TL_Support");
  }
class=class="str">"cmt">//--- 声明变量
class="type">int n,UpperFractal_1,UpperFractal_2,LowerFractal_1,LowerFractal_2;
class=class="str">"cmt">//--- 声明变量
class="type">int n,UpperFractal_1,UpperFractal_2,LowerFractal_1,LowerFractal_2;
class=class="str">"cmt">//--- 声明用于写入iFractal指标值的缓存数组
class="type">class="kw">double FractalDown[],FractalUp[];
class="type">class="kw">double UpFractal_1,UpFractal_2,LowFractal_1,LowFractal_2;

◍ 用 for 循环锁定最近两个分形

在 MT5 里抓取最近的分形,核心是用 for 循环从当前 K 线往历史方向扫,遇到第一个非空值就 break。和老版终端直接拿索引不同,MT5 必须先通过 iFractals 指标句柄配合 CopyBuffer() 把上下分形数值灌进数组,再用 ArraySetAsSeries() 把数组倒序成时间序列,索引 0 才对应最新一根。 具体做法是:先对 FractalUp 数组从 n=0 开始循环,FractalUp[n]!=EMPTY_VALUE 时记下 UpFractal_1 价格和 UpperFractal_1 索引;再从 UpperFractal_1+1 扫第二个,得到第二上分形。下分形同理走 FractalDown 数组。日线周期下用 Bars(Symbol(),PERIOD_D1) 控制循环上限,避免越界。 下面这段是实际可贴进 MT5 脚本的摘出代码,已经混写了上下分形的查找逻辑,开 MT5 新建 EA 把 Fractal 句柄在 OnInit 里用 iFractals 建好就能跑。外汇和贵金属波动大,分形仅是结构参考,实盘须自担高风险。

MQL5 / C++
class=class="str">"cmt">//--- 找到最近的上分形K线索引
  for(n=class="num">0; n<(Bars-class="num">1);n++)
    {
      if(iFractals(NULL,class="num">1440,MODE_UPPER,n)!=NULL)
        break;
      UpperFractal_1=n+class="num">1;
    }
class=class="str">"cmt">//--- 找到第二近的上分形K线索引
  for(n=UpperFractal_1+class="num">1; n<(Bars-class="num">1);n++)
    {
      if(iFractals(NULL,class="num">1440,MODE_UPPER,n)!=NULL)
        break;
      UpperFractal_2=n+class="num">1;
    }
class=class="str">"cmt">//--- 首先,我们要将分形指标缓存值写入数组
class=class="str">"cmt">//--- 用缓存值填充数组
  CopyBuffer(Fractal,class="num">0,TimeCurrent(),Bars(Symbol(),PERIOD_D1),FractalUp);
  CopyBuffer(Fractal,class="num">1,TimeCurrent(),Bars(Symbol(),PERIOD_D1),FractalDown);
class=class="str">"cmt">//--- 索引类似时间序列
  ArraySetAsSeries(FractalUp,true);
  ArraySetAsSeries(FractalDown,true);
class=class="str">"cmt">//--- 接下来我们使用for循环来查找第一个上分形
  for(n=class="num">0; n<Bars(Symbol(),PERIOD_D1); n++)
    {
      class=class="str">"cmt">//--- 如果值非空,跳出循环体
      if(FractalUp[n]!=EMPTY_VALUE)
        break;
    }
class=class="str">"cmt">//--- 将第一个分形的价格写入变量
  UpFractal_1=FractalUp[n];
class=class="str">"cmt">//--- 将其索引写入变量
  UpperFractal_1=n;
class=class="str">"cmt">//--- 查找第二个上分形 
  for(n=UpperFractal_1+class="num">1; n<Bars(Symbol(),PERIOD_D1); n++)
    {
      if(FractalUp[n]!=EMPTY_VALUE) class=class="str">"cmt">//如果值非空,跳出循环体
        break;
    }
class=class="str">"cmt">//--- 将第二个分形的价格写入变量
  UpFractal_2=FractalUp[n];
class=class="str">"cmt">//--- 将第二个分形的索引写入变量
  UpperFractal_2=n;
class=class="str">"cmt">//--- 找到最近的下分K线形索引
  for(n=class="num">0; n<(Bars-class="num">1);n++)
    {
      if(iFractals(NULL,class="num">1440,MODE_LOWER,n)!=NULL)
        break;
      LowerFractal_1=n+class="num">1;
    }
class=class="str">"cmt">//--- 找到第二近的下分形K线索引
  for(n=LowerFractal_1+class="num">1; n<(Bars-class="num">1);n++)
    {
      if(iFractals(NULL,class="num">1440,MODE_LOWER,n)!=NULL)
        break;
      LowerFractal_2=n+class="num">1;
    }
class=class="str">"cmt">//--- 找到下分形的值
class=class="str">"cmt">//--- 查找最近的下分形
  for(n=class="num">0; n<Bars(Symbol(),PERIOD_D1); n++)
    {
      class=class="str">"cmt">//--- 如果值非空,跳出循环体
      if(FractalDown[n]!=EMPTY_VALUE)
        break;
    }

日线分形对怎么抓第二个低点

在日线周期上定位两个下分形,核心是先锁定第一个分形的价格与索引,再往下扫第二个。上面这段代码干的就是这件事:把 FractalDown 数组里第一个有效值存进 LowFractal_1,索引存进 LowerFractal_1。 紧接着从 LowerFractal_1+1 开始循环,遍历范围到 Bars(Symbol(),PERIOD_D1) 为止,也就是当前品种日线全部 K 线数。遇到下一个不等于 EMPTY_VALUE 的 FractalDown[n] 就 break,把价格和索引分别写进 LowFractal_2 与 LowerFractal_2。 开 MT5 按这段逻辑跑一遍,把两个 LowFractal 差值打印出来,你能直接看到日线级别双底雏形之间的距离分布。外汇和贵金属波动受杠杆与消息影响大,分形只是形态参考,实际破位概率要结合成交量与更高周期判断。

MQL5 / C++
class=class="str">"cmt">//--- 将第一个分形的价格写入变量
  LowFractal_1=FractalDown[n];
class=class="str">"cmt">//--- 将其索引写入变量
  LowerFractal_1=n;
class=class="str">"cmt">//--- 查找第二个下分形 
  for(n=LowerFractal_1+class="num">1; n<Bars(Symbol(),PERIOD_D1); n++)
    {
      if(FractalDown[n]!=EMPTY_VALUE)
        break;
    }
class=class="str">"cmt">//--- 将第二个分形的价格写入变量
  LowFractal_2=FractalDown[n];
class=class="str">"cmt">//--- 将第二个分形的索引写入变量
  LowerFractal_2=n;

常见问题

加载基于分形指标的脚本或EA,它会抓取最近两个向上的分形点作为锚点,自动连接成趋势线,无需手动拖拽。
为避免图表上堆积重复的趋势线造成误判,EA在OnInit里会清理之前创建的同名图形对象,保证每次重画干净。
可以,小布能读取品种图表上的分形锚点趋势线,在价格触碰或跌破时推送提醒,省去你盯盘画线的重复劳动。
用循环从右往左找两个向上的分形,第二个分形即近期更低低点,两点连线就是日线级支撑趋势线。
注意循环起点偏移和分形缓冲未赋值问题,建议从iFractals第5根K线起查,避免用到未成形分形导致画线偏移。