价格行为分析工具包开发(第二十五部分):双指数移动平均线(EMA)分形突破策略
内容
概述
本文介绍一款工具的开发情况,该工具旨在通过运用比尔·威廉姆斯最初开发的分形指标,为价格行为分析提供更深入、更具洞察力的评估。
比尔M·威廉姆斯(Bill M. Williams)(1932—2019)是一位颇具影响力的美国交易员和作家,在交易心理学、技术分析以及金融市场混沌理论方面颇有建树。在其职业生涯中,威廉姆斯深耕股票、大宗商品和外汇(Forex)市场,开发了一系列创新的技术分析工具,用于识别趋势和潜在的反转点。他的一些最为著名的指标包括加速/减速振荡器、鳄鱼指标、动量振荡器、分形指标、鳄鱼振荡器以及市场便利指数。如今,这些指标因其分析市场行为的有效性,在外汇、股票及其他金融市场中得到了广泛应用。
分形指标是威廉姆斯方法论中的一个关键组成部分,在我们的方法中,该指标结合了14周期和200周期的指数移动平均线(EMA)。通过将分形形态与这些动态趋势过滤器相结合,我们的智能交易系统(EA)旨在精准识别潜在市场反转,并确保交易方向与整体趋势一致。这套组合策略能够提早发现反转信号,并确认趋势强度,从而提升交易决策能力,最终带来更可靠、高概率的入场点。分形分析与移动平均线的协同作用,为交易者提供了强大的工具,使其不仅能够更深入地解读价格行为,还有助于优化交易时机并改善交易结果。
策略解析
我们的EA运用了三个关键技术指标:分形指标 、EMA 14和EMA 200。分形指标由比尔·威廉姆斯开发,是技术分析中用于识别潜在趋势反转的常用工具。它能检测特定的价格形态(即分形),表现为局部的高点或低点,预示着市场可能的转折点。这些分形可作为支撑或阻力位,为交易者提供直观的提示,以便他们精确地把握入场和离场时机。
指数移动平均线(EMA)与简单移动平均线(SMA)的最大区别在于,EMA更关注最新价格,因此反应更灵敏。这种加权是通过一个平滑因子来放大近期价格的权重,使得EMA能够更迅速地响应市场变化。因此,EMA在捕捉新兴趋势和提供趋势转变的早期信号方面非常有效,尤其是在较短的周期内。
基于我们的设置,EMA 14反映了短期市场动能,能迅速对近期价格变动做出反应,适合及时入场交易。相反,EMA 200是一个长期趋势指标,能平滑掉短期波动,揭示整体市场方向。当价格在EMA 200之上交易时,表明长期为牛市趋势;当价格在EMA 200之下时,则暗示为熊市趋势。此外,EMA 200经常充当动态支撑位或阻力位,帮助交易者过滤掉虚假信号并确认趋势的有效性。
买入信号(看涨突破):
当同时满足多个条件,表明市场将强劲上行时,会触发买入信号。首先,EA会监测最近的分形低点水平(即支撑位)。它会寻找当前市场价格上穿该分形支撑位的情景,这预示着可能出现突破。为确认市场处于上升趋势,EA会检查当前价格是否同时高于EMA 14和EMA 200,且EMA 14位于EMA 200之上,这表明趋势为牛市。当这些条件都满足时,就会生成买入信号。图表上会显示向上箭头和标签等视觉提示,并可触发警报通知交易者。
- 价格上穿最近的支撑分形水平。
- 当前价格高于EMA 14和EMA 200。
- EMA 14高于EMA 200,确认上升趋势。

图例1. 看涨突破
卖出信号(看跌跌破):
相反,当价格下穿重要的分形高点(阻力位)时,会发出卖出信号,表明市场可能出现下行走势。EA会盯紧最近的分形高点,等价格跌穿这个位置。为确认市场处于下行趋势,它会验证当前价格是否低于两条EMA,且EMA 14位于EMA 200下方,这表明趋势为熊市。当满足以下条件时,即价格下穿阻力分形水平且趋势保持熊市,便会发出卖出信号。图表上会绘制类似的视觉标记,如下行箭头和标签,并可能触发警报。
- 价格下穿最近的阻力分形水平。
- 当前价格低于EMA 14和EMA 200。
- EMA 14位于EMA 200下方,确认下行趋势。

图例2. 看跌突破
代码组件分解
该EA将分形分析与移动平均线趋势过滤器相结合,用于识别并直观呈现市场中潜在的突破点。其通过在最近的分形高点和低点处绘制水平线,标示出关键支撑位和阻力位区域。当价格顺沿EMA所确认的趋势方向穿越这些水平位时,该EA会生成视觉信号(箭头和标签)并发出声音警报,从而简化交易者的决策过程。其模块化设计包含专门用于绘图、信号提示和数据管理的功能,使其能够适应各种交易风格和偏好。此外,该系统注重资源管理和清理,确保运行过程中的稳定性和清晰性。总体而言,这款将指标与视觉提示巧妙结合的先进工具,为交易者提供了一个全方位解决方案,有助于在趋势行情中捕捉分形突破机会。头文件与基础数据
代码的初始部分包含描述脚本作者、版本及许可信息的元数据。以 //+------------------------------------------------------------------+ 包围的注释用于明确脚本的用途并提供归属信息。#property 指令用于指定版权所有者、指向MetaTrader社区作者个人资料的超链接、版本号,并强制实施严格的编译规则。#property strict指令尤为重要,因为它指示编译器遵循更严格的编码标准,从而捕获诸如未声明变量或类型不匹配等潜在错误。这些元数据和指令不会影响代码的实际运行,但可以作为文档,并在编译过程中确保代码质量。
//+------------------------------------------------------------------+ //| Fractal Breakout, EMA 14 and EMA 200| //| Copyright 2025, MetaQuotes Ltd.| //| https://www.mql5.com/en/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict
输入参数
这里定义了一些可调参数,用户无需修改核心代码就能直接调整参数。这些输入项包括分析所采用的时间周期(InpTimeframe)、要检查的K线数量(InpHistoryBars),以及用作趋势过滤器的两条EMA的周期(InpEMA14Period和InpEMA200Period)。
颜色参数(InpBullColor和InpBearColor)允许用户自行定制突破箭头和线条的样式。文本标签(InpBullText和InpBearText)为信号提供描述性注释,增强图表的可读性。箭头偏移量(InpArrowOffset)和字体大小(InpArrowFontSize)进一步控制视觉呈现,使交易者能够方便地定位标签。
警报系统由InpAlertsEnabled控制,该参数用于开启或关闭弹出通知,而InpAlertSoundFile则指定检测到信号时播放的声音文件。这些参数使该EA具有灵活性,能够适应不同的交易风格和视觉偏好,使用户能够根据自己的具体需求进行定制。
input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // chart TF input int InpHistoryBars = 200; // bars back to scan input int InpEMA14Period = 14; // fast EMA input int InpEMA200Period = 200; // slow EMA input color InpBullColor = clrLime; // bullish arrow color input color InpBearColor = clrRed; // bearish arrow color input string InpBullText = "BULL Break"; // bullish label input string InpBearText = "BEAR Break"; // bearish label input int InpArrowOffset = 20; // offset in points for label input int InpArrowFontSize = 12; // size of the arrow glyph input bool InpAlertsEnabled = true; // show pop-up alerts input string InpAlertSoundFile = "alert.wav"; // sound file in /Sounds/
全局变量与指标句柄
在函数外部声明的变量用于存储指标句柄和分形数据数组。句柄(hFractals、hEMA14、hEMA200)是对初始化过程中创建的指标实例的引用。这些句柄至关重要,因为它们使EA能够与指标的数据缓冲区进行交互,从而获取实时和历史数据。数组fractalUp[]和fractalDown[]是动态分配的缓冲区,将分别存储分形的高点和低点。将这些变量作为全局变量进行管理,可确保在整个脚本中(尤其是在发生实时分析的OnTick处理过程中)能够访问它们。
int hFractals, hEMA14, hEMA200; double fractalUp[], fractalDown[];
初始化(OnInit)
在启动时,会调用OnInit函数来配置必要的资源。该函数使用iFractals和iMA等函数为分形和EMA创建指标句柄,并指定交易品种和时间周期。成功创建这些句柄非常关键;如果某个句柄无效(例如,由于参数错误或数据不可用),会导致初始化失败,EA运行异常。
随后,代码将分形数据数组配置为序列模式,这意味着最新数据将位于索引0处,从而简化了向后分析的过程。将这些数组的大小调整为指定的K线数量,可确保数据缓冲区的大小适当,以便进行高效处理。总之,这一步骤为可靠的数据检索奠定了基础,这对于准确地检测突破至关重要。
int OnInit() { hFractals = iFractals(_Symbol, InpTimeframe); hEMA14 = iMA(_Symbol, InpTimeframe, InpEMA14Period, 0, MODE_EMA, PRICE_CLOSE); hEMA200 = iMA(_Symbol, InpTimeframe, InpEMA200Period,0, MODE_EMA, PRICE_CLOSE); if(hFractals==INVALID_HANDLE || hEMA14==INVALID_HANDLE || hEMA200==INVALID_HANDLE) return(INIT_FAILED); ArraySetAsSeries(fractalUp, true); ArraySetAsSeries(fractalDown, true); ArrayResize(fractalUp, InpHistoryBars); ArrayResize(fractalDown, InpHistoryBars); return(INIT_SUCCEEDED); }
反初始化(OnDeinit)
当EA从图表中移除或交易终端关闭时,OnDeinit函数将执行以清理资源。该函数使用IndicatorRelease释放指标句柄,从而释放相关内存并防止内存泄漏。此外,它会遍历图表上的所有对象,识别并删除以“FB_”为前缀的对象,这些对象是EA运行过程中创建的可视化信号(箭头、标签、线条)。这种清理操作可确保EA停用后图表上不会残留多余的对象,从而保持图表环境的整洁,并防止在后续分析中出现潜在冲突或混淆。
void OnDeinit(const int reason) { if(hFractals!=INVALID_HANDLE) IndicatorRelease(hFractals); if(hEMA14 !=INVALID_HANDLE) IndicatorRelease(hEMA14); if(hEMA200 !=INVALID_HANDLE) IndicatorRelease(hEMA200); for(int i=ObjectsTotal(0)-1; i>=0; i--) { string n = ObjectName(0,i); if(StringFind(n,"FB_")>=0) ObjectDelete(0,n); } }
主处理逻辑(OnTick)
核心逻辑位于OnTick函数中,该函数在每次新市场报价到达时执行。它首先使用CopyBuffer获取两条EMA的最新值。这些EMA值作为趋势过滤器:它们的相对位置表明市场处于上升趋势还是下降趋势,从而辅助突破决策。如果EMA数据获取失败,函数将提前退出,以防止生成错误信号。接下来,函数再次通过错误检查获取最近高点和低点的分形数据缓冲区。代码向后遍历这些缓冲区,以查找最近的有效分形点,忽略任何占位符EMPTY_VALUEs。通过识别最近的重要分形点,EA确定可能触发突破的关键支撑位或阻力位。随后,它使用辅助函数在这些水平位绘制水平线,以供视觉参考。终端调试输出提供有关这些水平位、价格和EMA状态的实时信息,帮助交易者验证逻辑。
最后,EA检查突破条件:当上一根K线收盘价高于低点分形水平,当前K线收盘价下穿该水平,且价格在下降趋势中位于两条EMA下方时,发生看跌突破。相反,当上一根K线收盘价低于高点分形水平,当前K线收盘价上穿该水平,且价格在上升趋势中位于两条EMA上方时,确认看涨突破。检测到这些条件将触发信号生成函数。
void OnTick() { // 1) Read current EMAs double ema14Arr[1], ema200Arr[1]; if(CopyBuffer(hEMA14,0,0,1,ema14Arr)<=0 || CopyBuffer(hEMA200,0,0,1,ema200Arr)<=0) return; double ema14_now = ema14Arr[0]; double ema200_now = ema200Arr[0]; // 2) Read fractal history (skip current bar) if(CopyBuffer(hFractals,0,1,InpHistoryBars,fractalUp)<=0 || CopyBuffer(hFractals,1,1,InpHistoryBars,fractalDown)<=0) return; // 3) Find most recent valid fractals (ignore EMPTY_VALUE) int upShift=-1, downShift=-1; for(int i=1; i<InpHistoryBars; i++) { if(fractalUp[i] != EMPTY_VALUE && upShift<0) upShift = i+1; if(fractalDown[i] != EMPTY_VALUE && downShift<0) downShift = i+1; if(upShift>0 && downShift>0) break; } // 4) Levels double lvlUp = (upShift>0) ? fractalUp[upShift-1] : 0.0; double lvlDown = (downShift>0) ? fractalDown[downShift-1] : 0.0; // 5) Draw level lines DrawHLine("FB_LevelUp", lvlUp, InpBullColor); DrawHLine("FB_LevelDown", lvlDown, InpBearColor); // 6) DEBUG print double prevC = iClose(_Symbol,InpTimeframe,1); double currC = iClose(_Symbol,InpTimeframe,0); PrintFormat( "DBG lvlUp=%.5f lvlDown=%.5f prevC=%.5f currC=%.5f EMA14=%.5f EMA200=%.5f", lvlUp, lvlDown, prevC, currC, ema14_now, ema200_now ); // 7) Breakouts on the last closed candle (shift=1) // Bearish breakout detection if(lvlDown>0 && prevC>=lvlDown && currC<lvlDown && currC<ema14_now && currC<ema200_now && ema200_now>ema14_now) { Print(">>> Bear breakout triggered"); Signal(false, 1, lvlDown, ema14_now, ema200_now); } // Bullish breakout detection if(lvlUp>0 && prevC<=lvlUp && currC>lvlUp && currC>ema14_now && currC>ema200_now && ema14_now>ema200_now) { Print(">>> Bull breakout triggered"); Signal(true, 1, lvlUp, ema14_now, ema200_now); } }
绘制水平线(DrawHLine)
该实用函数负责在图表上绘制水平线并更新位置。调用时,它会检查是否存在指定名称的水平线;如果不存在,则在给定价格水平处以指定颜色创建一条新的虚线。如果该水平线已存在,则仅更新其位置。该方法可防止出现多条重叠的水平线,并确保视觉效果与最新的分形分析结果保持一致。虚线样式有助于将这些水平线与其他图表对象区分开来,突出其作为支撑位或阻力位的作用。对于交易者而言,这种直观的提示非常有效,能帮助快速识别出突破区域,无论手动或自动化决策都更方便。
void DrawHLine(string name, double price, color clr) { if(price<=0) return; if(ObjectFind(0,name)<0) { ObjectCreate(0,name,OBJ_HLINE,0,0,price); ObjectSetInteger(0,name,OBJPROP_COLOR,clr); ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT); ObjectSetInteger(0,name,OBJPROP_WIDTH,1); } else ObjectSetDouble(0,name,OBJPROP_PRICE,price); }
信号生成与可视化(Signal)
Signal函数封装了与突破事件信号生成相关的所有操作。该函数首先获取信号发生所在K线的时间戳,以确保可视化对象的精确定位。随后,根据突破是看涨还是看跌,在突破水平位创建一个向上或向下的箭头对象,箭头颜色与趋势保持一致。为确保清晰可见,箭头的外观通过宽度和大小参数进行了自定义。除箭头外,还会在垂直方向上稍作偏移添加一个文本标签,显示诸如“看涨突破”或“看跌突破”等描述性信息,以强化视觉提示。
该函数会在“专家”选项卡中记录一条详细信息,包括确切时间、水平位、收盘价和EMA值,为触发信号提供完整的记录。如果启用了警报功能,则会弹出消息窗口并播放声音文件,以便立即通知交易者。视觉、声音加上日志三管齐下,确保交易者能够及时获知潜在的突破机会,从而迅速采取行动。
void Signal(bool isBull, int shift, double level, double ema14, double ema200) { datetime t = iTime(_Symbol,InpTimeframe,shift); double price = level; string side = isBull ? "Bull" : "Bear"; // Arrow string arrowName = StringFormat("FB_%sArrow_%d", side, (int)t); ObjectCreate(0, arrowName, OBJ_ARROW, 0, t, price); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, isBull?233:234); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, isBull?InpBullColor:InpBearColor); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2); ObjectSetInteger(0, arrowName, OBJPROP_FONTSIZE, InpArrowFontSize); // Label string lab = arrowName + "_L"; double offset = (isBull ? InpArrowOffset : -InpArrowOffset) * _Point; ObjectCreate(0, lab, OBJ_TEXT, 0, t, price + offset); ObjectSetString(0, lab, OBJPROP_TEXT, isBull?InpBullText:InpBearText); ObjectSetInteger(0, lab, OBJPROP_COLOR, isBull?InpBullColor:InpBearColor); ObjectSetInteger(0, lab, OBJPROP_FONTSIZE, 11); // Log message string msg = StringFormat( "%s breakout at %s | Level=%.5f | Close=%.5f | EMA14=%.5f | EMA200=%.5f", side, TimeToString(t, TIME_DATE|TIME_SECONDS), level, iClose(_Symbol,InpTimeframe,shift), ema14, ema200 ); Print(msg); // Alert and sound if(InpAlertsEnabled) { Alert(msg); if(StringLen(InpAlertSoundFile)>0) PlaySound(InpAlertSoundFile); } }
MQL5代码
//+------------------------------------------------------------------+ //| Fractal Breakout, EMA 14 and EMA 200| //| Copyright 2025, MetaQuotes Ltd.| //| https://www.mql5.com/en/users/lynnchris| //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com/en/users/lynnchris" #property version "1.0" #property strict //---inputs input ENUM_TIMEFRAMES InpTimeframe = PERIOD_CURRENT; // chart TF input int InpHistoryBars = 200; // bars back to scan input int InpEMA14Period = 14; // fast EMA input int InpEMA200Period = 200; // slow EMA input color InpBullColor = clrLime; // bullish arrow color input color InpBearColor = clrRed; // bearish arrow color input string InpBullText = "BULL Break"; // bullish label input string InpBearText = "BEAR Break"; // bearish label input int InpArrowOffset = 20; // offset in points for label input int InpArrowFontSize = 12; // size of the arrow glyph input bool InpAlertsEnabled = true; // show pop-up alerts input string InpAlertSoundFile = "alert.wav"; // sound file in /Sounds/ //---indicator handles & buffers int hFractals, hEMA14, hEMA200; double fractalUp[], fractalDown[]; //+------------------------------------------------------------------+ //| Expert initialization | //+------------------------------------------------------------------+ int OnInit() { hFractals = iFractals(_Symbol, InpTimeframe); hEMA14 = iMA(_Symbol, InpTimeframe, InpEMA14Period, 0, MODE_EMA, PRICE_CLOSE); hEMA200 = iMA(_Symbol, InpTimeframe, InpEMA200Period,0, MODE_EMA, PRICE_CLOSE); if(hFractals==INVALID_HANDLE || hEMA14==INVALID_HANDLE || hEMA200==INVALID_HANDLE) return(INIT_FAILED); ArraySetAsSeries(fractalUp, true); ArraySetAsSeries(fractalDown, true); ArrayResize(fractalUp, InpHistoryBars); ArrayResize(fractalDown, InpHistoryBars); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(hFractals!=INVALID_HANDLE) IndicatorRelease(hFractals); if(hEMA14 !=INVALID_HANDLE) IndicatorRelease(hEMA14); if(hEMA200 !=INVALID_HANDLE) IndicatorRelease(hEMA200); for(int i=ObjectsTotal(0)-1; i>=0; i--) { string n = ObjectName(0,i); if(StringFind(n,"FB_")>=0) ObjectDelete(0,n); } } //+------------------------------------------------------------------+ //| Tick handler | //+------------------------------------------------------------------+ void OnTick() { // 1) Read current EMAs double ema14Arr[1], ema200Arr[1]; if(CopyBuffer(hEMA14,0,0,1,ema14Arr)<=0 || CopyBuffer(hEMA200,0,0,1,ema200Arr)<=0) return; double ema14_now = ema14Arr[0]; double ema200_now = ema200Arr[0]; // 2) Read fractal history (skip current bar) if(CopyBuffer(hFractals,0,1,InpHistoryBars,fractalUp)<=0 || CopyBuffer(hFractals,1,1,InpHistoryBars,fractalDown)<=0) return; // 3) Find most recent valid fractals (ignore EMPTY_VALUE) int upShift=-1, downShift=-1; for(int i=1; i<InpHistoryBars; i++) { if(fractalUp[i] != EMPTY_VALUE && upShift<0) upShift = i+1; if(fractalDown[i] != EMPTY_VALUE && downShift<0) downShift = i+1; if(upShift>0 && downShift>0) break; } // 4) Levels double lvlUp = (upShift>0) ? fractalUp[upShift-1] : 0.0; double lvlDown = (downShift>0) ? fractalDown[downShift-1] : 0.0; // 5) Draw level lines DrawHLine("FB_LevelUp", lvlUp, InpBullColor); DrawHLine("FB_LevelDown", lvlDown, InpBearColor); // 6) DEBUG print double prevC = iClose(_Symbol,InpTimeframe,1); double currC = iClose(_Symbol,InpTimeframe,0); PrintFormat( "DBG lvlUp=%.5f lvlDown=%.5f prevC=%.5f currC=%.5f EMA14=%.5f EMA200=%.5f", lvlUp, lvlDown, prevC, currC, ema14_now, ema200_now ); // 7) Breakouts on the last closed candle (shift=1) // Bearish breakout if(lvlDown>0 && prevC>=lvlDown && currC<lvlDown && currC<ema14_now && currC<ema200_now && ema200_now>ema14_now) { Print(">>> Bear breakout triggered"); Signal(false, 1, lvlDown, ema14_now, ema200_now); } // Bullish breakout if(lvlUp>0 && prevC<=lvlUp && currC>lvlUp && currC>ema14_now && currC>ema200_now && ema14_now>ema200_now) { Print(">>> Bull breakout triggered"); Signal(true, 1, lvlUp, ema14_now, ema200_now); } } //+------------------------------------------------------------------+ //| Draw or update a dotted HLine | //+------------------------------------------------------------------+ void DrawHLine(string name, double price, color clr) { if(price<=0) return; if(ObjectFind(0,name)<0) { ObjectCreate(0,name,OBJ_HLINE,0,0,price); ObjectSetInteger(0,name,OBJPROP_COLOR,clr); ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT); ObjectSetInteger(0,name,OBJPROP_WIDTH,1); } else ObjectSetDouble(0,name,OBJPROP_PRICE,price); } //+------------------------------------------------------------------+ //| Plot arrow, label, log & alert | //+------------------------------------------------------------------+ void Signal(bool isBull, int shift, double level, double ema14, double ema200) { datetime t = iTime(_Symbol,InpTimeframe,shift); double price = level; string side = isBull ? "Bull" : "Bear"; // Arrow string arrowName = StringFormat("FB_%sArrow_%d", side, (int)t); ObjectCreate(0, arrowName, OBJ_ARROW, 0, t, price); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, isBull?233:234); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, isBull?InpBullColor:InpBearColor); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2); ObjectSetInteger(0, arrowName, OBJPROP_FONTSIZE, InpArrowFontSize); // Label string lab = arrowName + "_L"; double offset = (isBull ? InpArrowOffset : -InpArrowOffset) * _Point; ObjectCreate(0, lab, OBJ_TEXT, 0, t, price + offset); ObjectSetString(0, lab, OBJPROP_TEXT, isBull?InpBullText:InpBearText); ObjectSetInteger(0, lab, OBJPROP_COLOR, isBull?InpBullColor:InpBearColor); ObjectSetInteger(0, lab, OBJPROP_FONTSIZE, 11); // Expert log string msg = StringFormat( "%s breakout at %s | Level=%.5f | Close=%.5f | EMA14=%.5f | EMA200=%.5f", side, TimeToString(t, TIME_DATE|TIME_SECONDS), level, iClose(_Symbol,InpTimeframe,shift), ema14, ema200 ); Print(msg); // Pop-up alert + optional sound if(InpAlertsEnabled) { Alert(msg); if(StringLen(InpAlertSoundFile)>0) PlaySound(InpAlertSoundFile); } } //+------------------------------------------------------------------+
成果
要测试EA,首先需使用MetaEditor编译代码。编译完成后,您既可以在MetaTrader 5中将EA应用于图表进行实时测试,也可以直接通过策略测试器进行历史回测。我已经在实盘市场环境和历史回测中对这款EA进行了测试。这一过程非常关键,只有这样才能把EA参数调顺,实现预期的交易行为,并优化其性能。
下图展示了该EA如何利用分形和EMA指标识别重大市场反转。具体而言,EA在关键支撑位检测到看跌分形突破,并在图表上进行可视化标记。随后的价格走势证实了反转,市场持续下行,与EMA趋势一致,其中14周期EMA下穿200周期EMA,表明市场转为看跌趋势。“看跌突破”标记等视觉提示有助于交易者做出严谨的入场和出场决策。这一结果展示了EA识别趋势反转早期迹象的能力,使交易者能够把握高概率的交易机会,同时避免虚假信号。

图例3. 阶梯指数上的看跌突破
以下GIF图展示了该EA实时检测并确认趋势反转的过程。其重点呈现了指标系统如何识别分形支撑位或阻力位,并发出潜在突破信号,促使交易者考虑建仓。随着市场按预测方向运行,通过EMA的排列来验证EA信号;14周期EMA下穿200周期EMA,确认了看跌趋势。箭头和警报等视觉提示,展示了EA如何助力交易者及时做出决策。这一实例凸显了早期检测与趋势确认相结合的重要性,增强了交易信心,并降低了误入场的风险。

图例4. V75(1s)回测
结论
该EA借助比尔·威廉姆斯的分形指标以及短期和长期EMA的力量,精准定位高概率入场点。通过结合这些工具,它能够捕捉早期反转信号,并根据当前市场趋势进行验证,从而提高交易执行的精准度和一致性。严格的回测和实盘测试表明,该EA在不同市场条件下均表现出良好的灵活性,并且经过微调后,可适配其参数以实现最优性能。图表上呈现直观的箭头和标签,再加上全自动下单,该EA能让您的交易流程既严谨又快速。本质上讲,它提供了一个系统化、基于规则的价格行为分析框架,特别适合那些既重视技术,又希望省力而采用自动化的交易者。
特色工具概述请参阅下表。
| 图表展示器 | 分析评论 | 分析大师 | 分析预测 | 波动率导航仪 | 均值回归信号收割器 |
| 信号脉冲 | 指标看板 | 外部数据流 | VWAP | Heikin Ashi | FibVWAP |
| RSI背离 | 抛物线止损与反转指标 (PSAR) | 四分位绘制脚本 | 侵入探测器 | TrendLoom工具 | 四分位看板 |
| ZigZag分析仪 | 相关性探索 | 市场结构反转检测工具 | 关联仪表盘 | 货币强度计 | PAQ分析工具 |
| 针形柱、吞噬形态与相对强弱指数(RSI)背离 | 双EMA分形突破器 |
本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/18297
注意: MetaQuotes Ltd.将保留所有关于这些材料的权利。全部或部分复制或者转载这些材料将被禁止。
本文由网站的一位用户撰写,反映了他们的个人观点。MetaQuotes Ltd 不对所提供信息的准确性负责,也不对因使用所述解决方案、策略或建议而产生的任何后果负责。
价格行为分析工具包开发(第二十六部分):针形线、吞没形态与RSI背离(多模式)工具
精通日志记录(第七部分):如何在图表上显示日志
这篇文章很有意思,感谢您提供 EA 源代码。我会试用并提供反馈。