使用MQL4和MQL5绘制基于分形指标的趋势线(基础篇)
「用分形指标在 MT5 上画趋势线」
MQL5 里画趋势线不一定要手动拖,分形指标(Fractal)自带的高点和低点就能当锚点。2015 年 8 月那篇原帖在 MT5 上跑通了这套逻辑,至今论坛仍有 8500+ 阅读、29 条讨论,说明手动派也在找自动化替代。 分形定义很硬:上分形 = 中间 K 线最高价高于左右各两根 K 线最高价;下分形反之。拿到这些极值后,用 ObjectCreate 在图表上连成线段,就得到一条贴着波峰波谷的趋势线。 外汇和贵金属波动大、滑点频繁,这类线只是概率参考,不能当成入场保证。开 MT5 新建脚本,把下面代码丢进去编译,就能看到自动连出的分形趋势线。
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,能直接编译出带日线分形句柄的空壳。
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 建好就能跑。外汇和贵金属波动大,分形仅是结构参考,实盘须自担高风险。
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 差值打印出来,你能直接看到日线级别双底雏形之间的距离分布。外汇和贵金属波动受杠杆与消息影响大,分形只是形态参考,实际破位概率要结合成交量与更高周期判断。
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;