MQL5 中艾略特波浪自动分析的实施·综合运用
🌊

MQL5 中艾略特波浪自动分析的实施·综合运用

(3/3)·从波浪规则编码到事件处理与程序改良,把理论模型真正跑成可用指标

案例拆解 第 3/3 篇
手动数浪时,多数人卡在调整波形态判别和规则冲突的反复核对上。自动分析的价值不在替你决策,而在把五波三波的结构约束先跑一遍。接上篇的标记逻辑,这一篇把完整程序骨架和工程细节补齐。
本章目录
  1. 多层 zigzag 顶部的数组填充逻辑
  2. 从锯齿数组里抠出指定区间的拐点
  3. 未启动与未完成波的节点挂载逻辑
  4. 三浪与五浪节点的实例化与规则校验
  5. 递归拆解子浪与「2<-3-4>」形态匹配
  6. 波浪顶点归零与子波递归挂载
  7. 未成形波浪的 3<-4-5> 公式遍历
  8. 波浪树里第三四五子波的挂接逻辑
  9. 五波段的实例化与规则校验
  10. 波浪树里第二到第四子波的递归挂接
  11. 五浪结构的对象装配与规则校验
  12. 推动浪子波树的递归挂载逻辑
  13. 五波结构的顶点枚举与对象填充
  14. 波浪树里前四级子浪的挂载逻辑
  15. 五浪树里第四子浪的延迟分析逻辑
  16. 波体结构填充与规则校验的落地写法
  17. 三浪与五浪的分支递归落点
  18. 未成形的 3<-4> 波怎么塞进树里
  19. 第四子浪的树节点补建与 4<-5> 公式循环
  20. 末位子波的分支挂载与未启动波处理
  21. 五波段的第四第五子波挂载逻辑
  22. 用 2<-3 公式补齐未展开的三浪
  23. 五波结构的第三子波递归与3<-4-5公式遍历
  24. 推动浪通过规则校验后的树形展开
  25. 未启动波的 1<-2-3 公式遍历
  26. 分形树里逐个挂子波的判断逻辑
  27. 第五浪节点的对象装配与子树展开
  28. 五浪子波在树里的递归挂载
  29. 五波结构的逐顶点实例化
  30. 波浪树里逐个挂子浪节点
  31. 递归遍历里未完波浪的挂起逻辑
  32. 五浪与三浪的递归展开逻辑
  33. 未达标波浪直接释放内存
  34. 把合规波浪挂进分形树并递归拆解子波
  35. 五波结构的逐点填充与规则校验
  36. 递推建树时前四段的递归落点
  37. 五波未完形态的嵌套枚举逻辑
  38. 波形通过规则校验后挂进树
  39. 第四与第五子浪的递归落点
  40. 三层循环里拼出 1-2-3 完整波
  41. 波浪树里逐层挂子浪的递归挂法
  42. 五波段的实例化与规则校验
  43. 波浪树里逐子波挂节点的递归写法
  44. 递归标记里如何避免重复分析子浪
  45. 波浪顶点固定状态的解析逻辑
  46. 用顶点数组判定推动浪与引导三角
  47. 用顶点关系判定五类波浪形态
  48. 复杂调整浪的拓扑判定分支
  49. 顶点高低比较的代码实现
  50. 波A与波B长度比较的判定逻辑
  51. 波幅比较与内存回收的实现细节
  52. 顶点标注的波浪命名映射
  53. 顶点三到五的波浪标签映射
  54. 把波浪顶点映射到图表文字标签
  55. 艾略特波浪标记的大小写与括号层级
  56. 标签随图表缩放自动贴位
  57. 像素价格缓存的收尾赋值
  58. EA 面板按钮与图表对象回收怎么写
  59. 按钮点击顺序错乱时的拦截逻辑
  60. 按钮事件驱动的三段式状态机
  61. 自动波浪标记的五个硬伤与绕法
  62. 别急着下结论

多层 zigzag 顶部的数组填充逻辑

这段实现的核心是把不同 H 参数下的 zigzag 顶点,按层级塞进一个全局动态数组 ZigzagArray。H=1 时先调 Zigzag() 找基础顶点,若返回 n>0 就新建 TZigzag 对象存索引与数值,并让 j 自增计数。 随后的 while(true) 循环里 H 逐层加 1,每轮重建 IndexVertex 与 ValueVertex,再跑一次 Zigzag(H,Start,Finish,...)。若当前层与前一层(取 ZigzagArray.At(j-1))在同位置索引出现不一致,才认为这是有效的新分层,写入数组并 j++。 实盘验证时建议打印各层 j 值:EURUSD H1 上 H 跑到 6~8 层后相邻层差异通常会消失,说明更高 H 已无新顶点,可据此给循环加退出条件避免空转。外汇与贵金属波动随机性高,该结构仅用于形态分层,不预示方向。

MQL5 / C++
CArrayObj *ZigzagArray; class=class="str">"cmt">// declare the ZigzagArray global dynamic array
class="type">void FillZigzagArray(class="type">int Start,class="type">int Finish)
  {
   ZigzagArray=new CArrayObj;                       class=class="str">"cmt">// create the dynamic array of zigzags
   CArrayInt *IndexVertex=new CArrayInt;         class=class="str">"cmt">// create the dynamic array of indexes of zigzag tops
   CArrayDouble *ValueVertex=new CArrayDouble;   class=class="str">"cmt">// create the dynamic array of values of the zigzag tops
   TZigzag *Zigzag;                                 class=class="str">"cmt">// declare the class for storing the indexes and values of the zigzag tops
   class="type">int H=class="num">1;
   class="type">int j=class="num">0;
   class="type">int n=Zigzag(H,Start,Finish,IndexVertex,ValueVertex);class=class="str">"cmt">//find the tops of the zigzag with the parameter H=class="num">1
   if(n>class="num">0)
     {
      Zigzag=new TZigzag;
      Zigzag.IndexVertex=IndexVertex;
      Zigzag.ValueVertex=ValueVertex;
      ZigzagArray.Add(Zigzag);
      j++;
     }
   H++;
   while(true)
     {
      IndexVertex=new CArrayInt;
      ValueVertex=new CArrayDouble;
      n=Zigzag(H,Start,Finish,IndexVertex,ValueVertex);
      if(n>class="num">0)
        {
         Zigzag=ZigzagArray.At(j-class="num">1);
         CArrayInt *PrevIndexVertex=Zigzag.IndexVertex;
         class="type">bool b=false;
         for(class="type">int i=class="num">0; i<=n-class="num">1;i++)
           {
            if(PrevIndexVertex.At(i)!=IndexVertex.At(i))
              {
               Zigzag=new TZigzag;
               Zigzag.IndexVertex=IndexVertex;
               Zigzag.ValueVertex=ValueVertex;
               ZigzagArray.Add(Zigzag);
               j++;
              }
           }
        }
     }
  }

◍ 从锯齿数组里抠出指定区间的拐点

在多层 zigzag 结构里提取局部拐点时,先拿 ZigzagArray 里的第 i 层对象,再分别取它的 IndexVertex(拐点柱索引)和 ValueVertex(拐点价格)。这两根数组必须成对使用,否则后面算点数会错位。 定位区间起止靠两段反向扫描:一段从 IndexVertex 头部找第一个大于等于 IndexStart 的下标 Index1,另一段从尾部找最后一个小于等于 IndexFinish 的下标 Index2。只要两者都不是 -1,就说明区间闭合,点数直接算成 n = Index2 - Index1 + 1。 没找到差异就释放内存 当 b==false 即本层没识别出有效差分时,务必 delete IndexVertex 和 ValueVertex,否则 MT5 跑长周期容易漏内存。外层只要 n<=2 就 break,意味着少于两个拐点就不继续向上层搜了。 外汇与贵金属波动大,这类拐点识别在高波动时段可能漏掉快速反转,实盘前建议在 MT5 用历史数据跑一遍确认。

MQL5 / C++
b=true;
break;
}
}
if(b==false)
{
class=class="str">"cmt">// otherwise, if there is no difference, release the memory
class="kw">delete IndexVertex;
class="kw">delete ValueVertex;
}
}
class=class="str">"cmt">// search for the tops of the zigzag until there is two or less of them
if(n<=class="num">2)
break;
H++;
}
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The FindPoints function                                          |
class=class="str">"cmt">//| Fill the ValuePoints and IndexPoints arrays                      |
class=class="str">"cmt">//| of the Points structure                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool FindPoints(class="type">int NumPoints,class="type">int IndexStart,class="type">int IndexFinish,class="type">class="kw">double ValueStart,class="type">class="kw">double ValueFinish,TPoints &Points)
{
 class="type">int n=class="num">0;
 class=class="str">"cmt">// fill the array ZigzagArray
 for(class="type">int i=ZigzagArray.Total()-class="num">1; i>=class="num">0;i--)
 {
 TZigzag *Zigzag=ZigzagArray.At(i);             class=class="str">"cmt">// the obtained i zigzag in the ZigzagArray
 CArrayInt *IndexVertex=Zigzag.IndexVertex;    class=class="str">"cmt">// get the array of the indexes of the tops of the i zigzags
 CArrayDouble *ValueVertex=Zigzag.ValueVertex; class=class="str">"cmt">// get the array of values of the tops of the i zigzag
 class="type">int Index1=-class="num">1,Index2=-class="num">1;
 class=class="str">"cmt">// search the index of the IndexVertex array, corresponding to the first point
 for(class="type">int j=class="num">0;j<IndexVertex.Total();j++)
 {
 if(IndexVertex.At(j)>=IndexStart)
 {
 Index1=j;
 break;
 }
 }
 class=class="str">"cmt">// search the index of the IndexVertex array, corresponding to the last point
 for(class="type">int j=IndexVertex.Total()-class="num">1;j>=class="num">0;j--)
 {
 if(IndexVertex.At(j)<=IndexFinish)
 {
 Index2=j;
 break;
 }
 }
 class=class="str">"cmt">// if the first and last points were found
 if((Index1!=-class="num">1) && (Index2!=-class="num">1))
 {
 n=Index2-Index1+class="num">1; class=class="str">"cmt">// find out how many points were found
 }

「未启动与未完成波的节点挂载逻辑」

这段逻辑服务于波浪结构里「未启动且未完成」的子波识别,核心是先借 FindPoints 在父波起止顶点间至少抓 2 个拐点,抓不到就直接退出函数。外汇与贵金属市场里这种子波常出现在盘整中继,杠杆环境下误判会带来较高回撤风险。 函数把传入的 Subwaves 字符串按逗号拆进 ListNameWave 数组,再用父波的顶点索引与数值框定搜索区间。下面这段是 FindPoints 内部命中足够点数后的回填与校验代码,注意它先比对首尾拐点值是否匹配预设的 ValueStart / ValueFinish,再逐点写进结构体。 调用层用双层 while 以 v1、v2 遍历 Points 里的候选拐点,公式层面对应「1<-2-3>」的未完结形态。你在 MT5 里改 NumPoints 阈值或 ValueStart 约束,就能收紧/放宽子波识别的灵敏度。

MQL5 / C++
   class=class="str">"cmt">// if the required number of points was found(equal or greater)
   if(n>=NumPoints)
     {
      class=class="str">"cmt">// check that the first and last tops correspond with the required top values
      if(((ValueStart!=class="num">0) && (ValueVertex.At(Index1)!=ValueStart)) ||
         ((ValueFinish!=class="num">0) && (ValueVertex.At(Index1+n-class="num">1)!=ValueFinish)))class="kw">continue;
      class=class="str">"cmt">// fill the Points structure, passed as a parameter
      Points.NumPoints=n;
      ArrayResize(Points.ValuePoints, n);
      ArrayResize(Points.IndexPoints, n);
      class="type">int k=class="num">0;
      class=class="str">"cmt">// fill the ValuePoints and IndexPoints arrays of Points structure
      for(class="type">int j=Index1; j<Index1+n;j++)
        {
         Points.ValuePoints[k]=ValueVertex.At(j);
         Points.IndexPoints[k]=IndexVertex.At(j);
         k++;
        }
      class="kw">return(true);
     };
     };
  class="kw">return(false);
 };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The NotStartedAndNotFinishedWaves function                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void NotStartedAndNotFinishedWaves(TWave *ParentWave,class="type">int NumWave,TNode *Node,class="type">class="kw">string Subwaves,class="type">int Level)
  {
   class="type">int v1,v2,v3,v4,I;
   TPoints Points;
   TNode *ParentNode,*ChildNode;
   class="type">int IndexWave;
   class="type">class="kw">string NameWave;
   TWave *Wave;
   class="type">int i=class="num">0,pos=class="num">0,start=class="num">0;
   class=class="str">"cmt">// Put the waves, which we will be analyzing to the ListNameWave array
   class="type">class="kw">string ListNameWave[];
   ArrayResize(ListNameWave,ArrayRange(WaveDescription,class="num">0));
   while(pos!=StringLen(Subwaves)-class="num">1)
     {
      pos=StringFind(Subwaves,",",start);
      NameWave=StringSubstr(Subwaves,start,pos-start);
      ListNameWave[i++]=NameWave;
      start=pos+class="num">1;
     }
   class="type">int IndexStart=ParentWave.IndexVertex[NumWave-class="num">1];
   class="type">int IndexFinish=ParentWave.IndexVertex[NumWave];
   class="type">class="kw">double ValueStart = ParentWave.ValueVertex[NumWave - class="num">1];
   class="type">class="kw">double ValueFinish= ParentWave.ValueVertex[NumWave];
   class=class="str">"cmt">// find no less than two points on the price chart and put them into the structure Points
   class=class="str">"cmt">// if they are not found, then exit the function
   if(FindPoints(class="num">2,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
   class=class="str">"cmt">// the loop of unbegun and incomplete waves with the formula "class="num">1<-class="num">2-class="num">3>"
   v1=class="num">0;
   while(v1<=Points.NumPoints-class="num">2)
     {
      v2=v1+class="num">1;
      while(v2<=Points.NumPoints-class="num">1)
        {
         class="type">int j=class="num">0;
         while(j<=i-class="num">1)

三浪与五浪节点的实例化与规则校验

在波浪结构解析里,只有当某条波的 NumWave 等于 3 或 5 时,才值得单独建对象往下拆子波——其余度数大概率只是过渡段。代码里用 FindWaveInWaveDescription 拿到索引后做这个判断,命中才进分支。 进分支后先 new 一个 TWave,把名字、层级、公式串 "1<-2-3>" 写进去,再把起止顶点和对应 K 线索引填进 ValueVertex / IndexVertex 数组。注意顶点 0、3、4、5 初值都是 0,真正有数的是 1 和 2,对应 v1、v2 两个已识别拐点。 填完字段立刻调 WaveRules(Wave),返回 true 才把这条波挂进树(Node.Add),并返回的 ParentNode 上先建序号为 1 的子节点。若 Already() 发现该子波区间没分析过,就递归 NotStartedWaves 往下一层(Level+1)继续拆。外汇与贵金属杠杆高,这类自动数波结果只作概率参考,实盘须自担风险。

MQL5 / C++
  {
      class=class="str">"cmt">// get the name of the wave for analysis from the ListNameWave
      NameWave=ListNameWave[j++];
      class=class="str">"cmt">// find the index of the wave in the structure WaveDescription in order to
      class=class="str">"cmt">// find out the number of its sub-waves and their names
      IndexWave=FindWaveInWaveDescription(NameWave);
      if((WaveDescription[IndexWave].NumWave==class="num">5) || (WaveDescription[IndexWave].NumWave==class="num">3))
        {
         class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed waves
         Wave=new TWave;
         Wave.Name=NameWave;
         Wave.Level=Level;
         Wave.Formula="class="num">1<-class="num">2-class="num">3>";
         Wave.ValueVertex[class="num">0] = class="num">0;
         Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
         Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
         Wave.ValueVertex[class="num">3] = class="num">0;
         Wave.ValueVertex[class="num">4] = class="num">0;
         Wave.ValueVertex[class="num">5] = class="num">0;
         Wave.IndexVertex[class="num">0] = IndexStart;
         Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
         Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
         Wave.IndexVertex[class="num">3] = IndexFinish;
         Wave.IndexVertex[class="num">4] = class="num">0;
         Wave.IndexVertex[class="num">5] = class="num">0;
         class=class="str">"cmt">// check the wave by the rules
         if(WaveRules(Wave)==true)
           {
            class=class="str">"cmt">// if a wave passed the check by rules, add it into the wave tree
            ParentNode=Node.Add(NameWave,Wave);
            I=class="num">1;
            class=class="str">"cmt">// create the first sub-wave in the waves tree
            ChildNode=ParentNode.Add(IntegerToString(I));
            class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
            if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
               NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
            I++;
            class=class="str">"cmt">// create the second sub-wave in the waves tree

◍ 递归拆解子浪与「2<-3-4>」形态匹配

在艾略特波浪的树形结构里,第二、第三子浪是分开挂到父节点下的。代码先用 ParentNode.Add(IntegerToString(I)) 把子浪节点塞进树,再用 Already() 判断这段图表区间是否已被分析过;没分析过就分别调 FinishedWaves 和 NotFinishedWaves 递归下去,Level 参数每次 +1,意味着越深的子浪嵌套层级越高。 若当前浪没通过规则校验,直接走 else delete Wave 释放内存,避免无用的 TWave 对象堆积。这一点在 MT5 上跑大规模历史扫描时很关键——外汇与贵金属波动杂乱,未通过率可能偏高,不释放会拖慢回测。 下半段在处理「2<-3-4>」公式的未完浪循环。v2 从 0 起步,内层 v3=v2+1 逐对取值,j 循环从 ListNameWave 取浪名,FindWaveInWaveDescription 拿到结构索引后,只对 NumWave==5 的浪新建 TWave 并填 ValueVertex:顶点2、3 分别绑定 Points.ValuePoints[v2] 与 [v3],顶点0、1 暂置 0。 把这段贴进 MT5 的 EA 源码,改 WaveDescription 里的子浪定义,就能在 EURUSD 的 M15 上验证树是否按预期展开;贵金属 XAUUSD 跳空多,递归深度建议先限到 Level<=4 观察性能。

MQL5 / C++
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create a third sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
 }
 class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release memory
 else class="kw">delete Wave;
   }
     }
      v2=v2+class="num">2;
   }
  v1=v1+class="num">2;
 }
class=class="str">"cmt">// the loop of unbegun and unfinished waves with the formula "class="num">2<-class="num">3-class="num">4>"
 v2=class="num">0;
 while(v2<=Points.NumPoints-class="num">2)
  {
   v3=v2+class="num">1;
   while(v3<=Points.NumPoints-class="num">1)
    {
     class="type">int j=class="num">0;
     while(j<=i-class="num">1)
      {
       class=class="str">"cmt">// get the name of the wave for analysis from the ListNameWave
       NameWave=ListNameWave[j++];
       class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of its symbols and its names
       IndexWave=FindWaveInWaveDescription(NameWave);
       if(WaveDescription[IndexWave].NumWave==class="num">5)
        {
         class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
         Wave=new TWave;
         Wave.Name=NameWave;
         Wave.Level=Level;
         Wave.Formula="class="num">2<-class="num">3-class="num">4>";
         Wave.ValueVertex[class="num">0] = class="num">0;
         Wave.ValueVertex[class="num">1] = class="num">0;
         Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
         Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];

「波浪顶点归零与子波递归挂载」

这段逻辑出现在母浪通过 WaveRules 校验之后,先把 ValueVertex[4]、ValueVertex[5] 以及 IndexVertex[0]、IndexVertex[5] 置 0,等于把未用的顶点槽位清空,只保留 IndexVertex[1]~[4] 四个有效索引来描述一段从 IndexStart 到 IndexFinish 的行情区间。 校验一旦返回 true,就用 Node.Add(NameWave,Wave) 把当前浪挂进波浪树,拿到 ParentNode。随后 I 从 2 起步,依次对第二、三、四子浪调用 ParentNode.Add(IntegerToString(I)) 生成子节点。 每个子节点生成后都跑一次 Already() 判断该图表区间是否已被分析:第二子浪未分析就进 NotStartedWaves,第三子浪进 FinishedWaves,第四子浪进 NotFinishedWaves,且 Level 参数统一 +1,把递归深度往下传一层。 没过规则检查的浪不会进树,注释里写明要走释放内存的分支。你在 MT5 里改 WaveRules 的容差参数,会直接决定这里 ParentNode 是否生成以及后面三层子浪递归是否被触发。

MQL5 / C++
Wave.ValueVertex[class="num">4] = class="num">0;
Wave.ValueVertex[class="num">5] = class="num">0;
Wave.IndexVertex[class="num">0] = class="num">0;
Wave.IndexVertex[class="num">1] = IndexStart;
Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
Wave.IndexVertex[class="num">4] = IndexFinish;
Wave.IndexVertex[class="num">5] = class="num">0;
class=class="str">"cmt">// check the wave by the rules
if(WaveRules(Wave)==true)
  {
   class=class="str">"cmt">// if the wave passed the check for rules, add it to the waves tree
   ParentNode=Node.Add(NameWave,Wave);
   I=class="num">2;
   class=class="str">"cmt">// create the second sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in th waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fourth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
class=class="str">"cmt">// otherwise, if the wave did not pass the check by rules, release memory

未成形波浪的 3<-4-5> 公式遍历

这段逻辑紧接前面已完成的波浪扫描,转去处理「尚未起步」与「未完成」的波浪组合,核心公式标记为 3<-4-5>。它用三层 while 嵌套:外层 v3 从 0 走到 NumPoints-2,中层 v4 从 v3+1 到 NumPoints-1,内层 j 遍历已有波浪列表,只挑出 NumWave==5 的波浪做母本分析。 对内层命中的五波结构,代码新建 TWave 对象并写入公式与顶点映射:ValueVertex[3]、[4] 分别绑定 v3、v4 处的价格,IndexVertex[2]、[5] 锁死波段起止索引 IndexStart、IndexFinish,其余顶点先置 0 留待后续填充。 随后调用 WaveRules(Wave) 做规则校验,返回 true 才通过 Node.Add 挂入波浪树,并置 I=3 准备生成第三子波。外汇与贵金属市场波动剧烈、杠杆风险高,这类自动识别仅作结构参考,实盘须自行核对。 在 MT5 里把这段贴进 EA 调试,把 Points.NumPoints 调小到 10 以内,能直观看到 v3/v4 组合如何被逐个试错,比读文档更快摸清嵌套边界。

MQL5 / C++
         else class="kw">delete Wave;
              }
           }
         v3=v3+class="num">2;
       }
     v2=v2+class="num">2;
   }
   class=class="str">"cmt">// the loop of the unbegun and the incomplete waves with the formula "class="num">3<-class="num">4-class="num">5>"
   v3=class="num">0;
   while(v3<=Points.NumPoints-class="num">2)
     {
     v4=v3+class="num">1;
     while(v4<=Points.NumPoints-class="num">1)
       {
        class="type">int j=class="num">0;
        while(j<=i-class="num">1)
          {
           class=class="str">"cmt">// get the name of the wave for analysis from the ListNameWave
           NameWave=ListNameWave[j++];
           class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to
class=class="str">"cmt">// find out the number of its symbols and their names
           IndexWave=FindWaveInWaveDescription(NameWave);
           if(WaveDescription[IndexWave].NumWave==class="num">5)
             {
              class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
              Wave=new TWave;
              Wave.Name=NameWave;
              Wave.Level=Level;
              Wave.Formula="class="num">3<-class="num">4-class="num">5>";
              Wave.ValueVertex[class="num">0] = class="num">0;
              Wave.ValueVertex[class="num">1] = class="num">0;
              Wave.ValueVertex[class="num">2] = class="num">0;
              Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
              Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
              Wave.ValueVertex[class="num">5] = class="num">0;
              Wave.IndexVertex[class="num">0] = class="num">0;
              Wave.IndexVertex[class="num">1] = class="num">0;
              Wave.IndexVertex[class="num">2] = IndexStart;
              Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
              Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
              Wave.IndexVertex[class="num">5] = IndexFinish;
              class=class="str">"cmt">// check the wave for the rules
              if(WaveRules(Wave)==true)
                {
                 class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
                 ParentNode=Node.Add(NameWave,Wave);
                 I=class="num">3;
                 class=class="str">"cmt">// create the third sub-wave in the waves tree

◍ 波浪树里第三四五子波的挂接逻辑

在艾略特波浪的自动识别代码里,第三、四、五子波并非一次性展开,而是借助 ParentNode.Add() 逐个挂到波浪树节点上,并用整型下标 I 区分。每挂一个子波节点,都先用 Already() 判断这段图表区间是否已被分析过,未分析才进入对应的递归函数。 第三子波调用 NotStartedWaves(),第四子波走 FinishedWaves(),第五子波走 NotFinishedWaves(),三者都带 Level+1 把递归深度往下推一层。若整段波未通过规则校验,则直接 delete Wave 释放内存,避免脏节点堆积。 外层用 v3=v3+2、v4=v4+2 这类步长为 2 的循环推进,说明锚点选取跳过了相邻 K 线,只在隔一根的位置找潜在拐点。函数开头先用 FindPoints(3,...) 找不少于 3 个价格点塞进 Points 结构,找不到就 return,这是后续所有子波展开的硬前置。 开 MT5 把这段接进你自己的波浪脚本,重点看 Already() 的命中率:若回测中同一区间被重复分析占比偏高,说明 Level 传参或节点标记有漏,应先修再去跑实盘品种。外汇与贵金属波动跳空多,这类自动数波在高波动时段误判概率会明显上升。

MQL5 / C++
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fourth sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fifth sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the fifth wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave has not passed the check by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v4=v4+class="num">2;
   }
   v3=v3+class="num">2;
   }
class=class="str">"cmt">// find no less than three points on the price chart and put them in the Points structure
class=class="str">"cmt">// if they were not found, then exit the function
if(FindPoints(class="num">3,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) class="kw">return;
class=class="str">"cmt">// the loop of unbegun and unfinished waved with the formula "class="num">1<-class="num">2-class="num">3-class="num">4>"
v1=class="num">0;
while(v1<=Points.NumPoints-class="num">3)
   {
   v2=v1+class="num">1;
   while(v2<=Points.NumPoints-class="num">2)
      {
      v3=v2+class="num">1;
      while(v3<=Points.NumPoints-class="num">1)
         {
         class="type">int j=class="num">0;
         while(j<=i-class="num">1)
            {
            class=class="str">"cmt">// get the name of the wave for analysis from the ListNameWave

「五波段的实例化与规则校验」

在波浪结构解析里,当某条命名波在 WaveDescription 中的 NumWave 等于 5 时,说明它是一组驱动五浪,需要单独建对象并填参数。下面这段逻辑就是干这件事的。 代码先通过 FindWaveInWaveDescription 拿到该波在结构表中的索引,确认是五浪后,new 一个 TWave 并写死 Formula 为 "1<-2-3-4>",表示顶点 0 与 4 为起止、中间三折。ValueVertex 里只填了 v1/v2/v3 三个转折价,起止用 0 占位,IndexVertex 同步记录对应 K 线索引。 填完场数据后调用 WaveRules(Wave) 做形态规则检查;返回 true 才用 Node.Add 挂进波浪树,并立刻建序号 1 的第一子浪节点。若 Already() 判定该子浪区间还没分析过,就递归进 NotStartedWaves 往下拆一级。外汇与贵金属行情受杠杆影响大,五浪识别失败率不低,拆浪前建议在 MT5 用自有样本跑一遍 WaveRules 的命中率。 别把 NumWave==5 当通关信号 代码里写死 5 只是结构分支,不代表价格必走完五浪;实盘里楔形或失败五浪都可能让 WaveRules 误收,验证时把 Level 和 Subwaves 打印出来比对最稳。

MQL5 / C++
NameWave=ListNameWave[j++];
class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of its sub-waves and their names
IndexWave=FindWaveInWaveDescription(NameWave);
if(WaveDescription[IndexWave].NumWave==class="num">5)
  {
   class=class="str">"cmt">// create an object of TWave class and fill its fields - parameters of the analyzed wave
   Wave=new TWave;
   Wave.Name=NameWave;
   Wave.Level=Level;
   Wave.Formula="class="num">1<-class="num">2-class="num">3-class="num">4>";
   Wave.ValueVertex[class="num">0] = class="num">0;
   Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
   Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
   Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
   Wave.ValueVertex[class="num">4] = class="num">0;
   Wave.ValueVertex[class="num">5] = class="num">0;
   Wave.IndexVertex[class="num">0] = IndexStart;
   Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
   Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
   Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
   Wave.IndexVertex[class="num">4] = IndexFinish;
   Wave.IndexVertex[class="num">5] = class="num">0;
   class=class="str">"cmt">// check the wave by the rules
   if(WaveRules(Wave)==true)
     {
      class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
      ParentNode=Node.Add(NameWave,Wave);
      I=class="num">1;
      class=class="str">"cmt">// create the first sub-wave in the waves tree
      ChildNode=ParentNode.Add(IntegerToString(I));
      class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
      if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
        NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);

波浪树里第二到第四子波的递归挂接

这段逻辑处在波浪形态识别的递归函数内,负责把父波往下拆出第 2、3、4 子波节点并决定是否继续向下分析。每拆一个子波都先 I++ 自增序号,用 IntegerToString(I) 作为节点名挂到 ParentNode 下,避免手写字符串硬编码。 挂完节点后立刻用 Already() 判断该图表区间是否已被分析过;返回 false 才进入 FinishedWaves 或 NotFinishedWaves。注意第 4 子波调用的是 NotFinishedWaves 而非 FinishedWaves,这对应推动浪末段尚未闭合的判定分支。 若整组波没通过规则校验,直接 else delete Wave 释放对象,防止树结构里堆出废节点。外层 v1/v2/v3 每次 +2 的循环步长,说明扫描的是隔点组合,不是逐根 K 线。 下方注释里的 '2<-3-4-5>' 公式循环,v2 从 0 起、v3=v2+1、v4=v3+1 三层 while 把未开始与未完结的波按点位索引穷举,NumPoints-3 到 NumPoints-1 的边界保证了取 3~5 个拐点时不越界。

MQL5 / C++
I++;
class=class="str">"cmt">// create the second sub-wave in the waved tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the third sub-wave in the waves
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fourth sub-wave of the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
}
class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
else class="kw">delete Wave;
   class=class="str">"cmt">// the loop of unbegun and unfinished waves with the formula "class="num">2<-class="num">3-class="num">4-class="num">5>"
   v2=class="num">0;
   while(v2<=Points.NumPoints-class="num">3)
   {
      v3=v2+class="num">1;
      while(v3<=Points.NumPoints-class="num">2)
      {
         v4=v3+class="num">1;
         while(v4<=Points.NumPoints-class="num">1)
         {
            class="type">int j=class="num">0;

◍ 五浪结构的对象装配与规则校验

在波浪树的递归构造里,当遍历到编号为 5 的波时,代码会把该波封装成 TWave 实例并填入顶点参数。注意 Formula 被硬编码为 "2<-3-4-5>",意味着第 2 顶点留空(值 0),实际只取 v2、v3、v4 三个已识别拐点,对应 ValueVertex[2..4] 来自 Points.ValuePoints 数组。 IndexVertex 同步记录柱线索引:起点 IndexStart 进 [1],终点 IndexFinish 进 [5],中间三折点取自 Points.IndexPoints。这样波的身份(名称、层级、公式、坐标)就完整挂到对象上,后续交给 WaveRules() 做形态过滤。 WaveRules 返回 true 才允许入树:Node.Add 把波挂为父节点,随后立即建子节点 IntegerToString(2) 表示第二子波,若对应区间还没分析就继续向下钻。外汇与贵金属市场波动无序,这种自动识别只是概率筛选,实盘前务必在 MT5 用历史数据回放验证命中率。 别把 NumWave==5 当终点信号 代码里只要编号等于 5 就进封装分支,但真实走势中假五浪极多,WaveRules 不通过就不会入树——直接复制这段逻辑时,先确认你的 FindWaveInWaveDescription 能稳定返回正确 IndexWave,否则数组越界会崩脚本。

MQL5 / C++
while(j<=i-class="num">1)
  {
  class=class="str">"cmt">// get the name of the wave for analysis from the ListNameWave
  NameWave=ListNameWave[j++];
  class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of the symbols and their names
  IndexWave=FindWaveInWaveDescription(NameWave);
  if(WaveDescription[IndexWave].NumWave==class="num">5)
    {
    class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
    Wave=new TWave;
    Wave.Name=NameWave;
    Wave.Level=Level;
    Wave.Formula="class="num">2<-class="num">3-class="num">4-class="num">5>";
    Wave.ValueVertex[class="num">0] = class="num">0;
    Wave.ValueVertex[class="num">1] = class="num">0;
    Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
    Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
    Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
    Wave.ValueVertex[class="num">5] = class="num">0;
    Wave.IndexVertex[class="num">0] = class="num">0;
    Wave.IndexVertex[class="num">1] = IndexStart;
    Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
    Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
    Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
    Wave.IndexVertex[class="num">5] = IndexFinish;
    class=class="str">"cmt">// check the wave by the rules
    if(WaveRules(Wave)==true)
      {
      class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
      ParentNode=Node.Add(NameWave,Wave);
      I=class="num">2;
      class=class="str">"cmt">// create the second sub-wave in the waves tree
      ChildNode=ParentNode.Add(IntegerToString(I));
      class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it

「推动浪子波树的递归挂载逻辑」

这段片段处理的是五浪结构里第 3、4、5 子波的树节点创建与递归分析。每一条子波先以 IntegerToString(I) 挂到父节点下,再用 Already() 判断该图表区间是否已被分析过,未分析才进入对应的 NotStartedWaves / FinishedWaves / NotFinishedWaves 分支,并把递归层级 Level 加 1 往下钻。 注意第三子波走的是 NotStartedWaves,而第四、第五子波分别走 FinishedWaves 与 NotFinishedWaves——这说明算法对未启动与已成型波段的判定函数做了区分,不是统一递归。若整段波未通过规则校验,则直接 delete Wave 释放内存,避免树结构膨胀。 外层还有 v2/v3/v4 各以步长 2 的循环累加,配合最末的 FindPoints(4,...) 约束:至少要在价格图上提取 4 个拐点放入 Points 结构,否则函数直接 return。开 MT5 把这段嵌进你的波浪扫描 EA,先打印各子波 I 值确认节点序,就能验证挂树顺序是否符合预期。

MQL5 / C++
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fourth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fifth sub-wave in the waved tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fifth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave has not passed by the rules, release the memory
   else class="kw">delete Wave;
      }
   }
   v4=v4+class="num">2;
      }
      v3=v3+class="num">2;
   }
   v2=v2+class="num">2;
   }
class=class="str">"cmt">// find no less than four point on the price chart and put them into the structure Points
class=class="str">"cmt">// if we didn&class="macro">#x27;t find any, then exit the function
if(FindPoints(class="num">4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) class="kw">return;
class=class="str">"cmt">// the loop of unbegun and unfinished waves with the formula "class="num">1<-class="num">2-class="num">3-class="num">4-class="num">5>"

五波结构的顶点枚举与对象填充

在波浪识别里,要把一段行情判定为推进五波,必须先穷举四个内部转折点的组合。下面这段逻辑用四层嵌套 while 把候选点 v1~v4 依次错开取位,保证 v1<v2<v3<v4 且各自距数组末端留足 3~0 个点的余量,避免越界。 外层循环 v1 从 0 跑到大 NumPoints-4,v2 从 v1+1 到 NumPoints-3,v3、v4 同理各缩一格。这样在 100 个极值点的样本里,仅四顶点有序组合就可能产生数万次候选,计算量随点数呈四次方增长,实盘建议先对 Points 做稀疏滤波。 内层还有第五层循环 j 遍历已命名波浪列表,通过 FindWaveInWaveDescription 拿到波形元数据;只有当该波 NumWave==5 时才 new 一个 TWave 并填参。Formula 写死为 "1<-2-3-4-5>",ValueVertex[1..4] 直接映射四个候选点价格,IndexVertex 同步记下标,方便后续规则校验。外汇与贵金属波动跳空多,这种枚举对假突破敏感,验证时务必加滑点容差。

MQL5 / C++
  v1=class="num">0;
  while(v1<=Points.NumPoints-class="num">4)
    {
     v2=v1+class="num">1;
     while(v2<=Points.NumPoints-class="num">3)
       {
        v3=v2+class="num">1;
        while(v3<=Points.NumPoints-class="num">2)
          {
           v4=v3+class="num">1;
           while(v4<=Points.NumPoints-class="num">1)
             {
              class="type">int j=class="num">0;
              while(j<=i-class="num">1)
                {
                 class=class="str">"cmt">// get the name of the wave for analysis from the ListNameWave
                 NameWave=ListNameWave[j++];
                 class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
                 IndexWave=FindWaveInWaveDescription(NameWave);
                 if(WaveDescription[IndexWave].NumWave==class="num">5)
                   {
                    class=class="str">"cmt">// create the object TWave class and fill its fields - parameters of the analyzed wave
                    Wave=new TWave;
                    Wave.Name=NameWave;
                    Wave.Level=Level;
                    Wave.Formula="class="num">1<-class="num">2-class="num">3-class="num">4-class="num">5>";
                    Wave.ValueVertex[class="num">0] = class="num">0;
                    Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
                    Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
                    Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
                    Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
                    Wave.ValueVertex[class="num">5] = class="num">0;
                    Wave.IndexVertex[class="num">0] = IndexStart;
                    Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
                    Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
                    Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
                    Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
                    Wave.IndexVertex[class="num">5] = IndexFinish;
                    class=class="str">"cmt">// check the wave by the rules

◍ 波浪树里前四级子浪的挂载逻辑

在艾略特波浪的自动识别里,一段母浪只要过了 WaveRules 校验,就会被挂进波浪树作为父节点,随后立即生成编号 1 到 4 的子节点。代码里用 I 从 1 自增,每轮 Add(IntegerToString(I)) 都先在树里占好坑,再判断是否已分析过。 Already() 返回 false 时才真正下钻:第 1 子浪走 NotStartedWaves,第 2、3 子浪走 FinishedWaves,第 4 子浪在原文处截断未写调用。Level+1 把递归深度往下传一层,保证子浪在自己的层级里继续拆。 你在 MT5 里接这段时,注意第 4 子浪的 Already 判断后没有跟函数调用,是原文截断还是漏写要自己核对;外汇与贵金属波动受杠杆影响大,这类自动数浪仅作概率参考,实盘须严控风险。

MQL5 / C++
if(WaveRules(Wave)==true)
      {
      class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
      ParentNode=Node.Add(NameWave,Wave);
      I=class="num">1;
      class=class="str">"cmt">// create the first sub-wave in the waves tree
      ChildNode=ParentNode.Add(IntegerToString(I));
      class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave has not been analyzed, then analyze it
      if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
         NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
      I++;
      class=class="str">"cmt">// create the second sub-wave in the waves tree
      ChildNode=ParentNode.Add(IntegerToString(I));
      class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
      if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
         FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
      I++;
      class=class="str">"cmt">// create the third sub-wave in the waves tree
      ChildNode=ParentNode.Add(IntegerToString(I));
      class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
      if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
         FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
      I++;
      class=class="str">"cmt">// create the fourth sub-wave in the waved tree
      ChildNode=ParentNode.Add(IntegerToString(I));
      class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it

「五浪树里第四子浪的延迟分析逻辑」

在波浪树的递归构建中,当推进到第五个子浪节点前,代码会先检查第四子浪对应的图表区间是否已被分析。若 Already() 返回 false,说明该区间尚未处理,便调用 NotFinishedWaves() 继续向下递归,而不是强行补全,这避免了重复扫描同一段价格。 具体看这段:ChildNode 通过 ParentNode.Add(IntegerToString(I)) 挂到父节点下,I 此时已是第四子浪序号;紧接着的 if(Already(...)==false) 决定走 NotFinishedWaves 还是跳过。若整波未通过规则校验,则走 else 分支直接 delete Wave 释放内存,防止野指针堆积。 外层循环用 v1=v1+2 这类步长 2 的计数器逐级回退,表明祖辈波浪的遍历也是隔点抽样的,和 FindPoints(1,...) 至少找到 1 个拐点才继续的设定一致。你在 MT5 里跑这套时,把 Already() 的命中率打到日志,就能看出哪些子浪区间被反复延迟分析。

MQL5 / C++
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the 5th sub-wave in the wave tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave did not pass the check by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v4=v4+class="num">2;
   }
   v3=v3+class="num">2;
   }
   v2=v2+class="num">2;
   }
   v1=v1+class="num">2;
   }
class=class="str">"cmt">// find no less than one point on the price chart and record it into the structure Points
class=class="str">"cmt">// if we didn&class="macro">#x27;t find any, then exit the function
if(FindPoints(class="num">1,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
class=class="str">"cmt">// the loop of unbegun and unfinished waves with the formula "class="num">1<-class="num">2>"
v1=class="num">0;
while(v1<=Points.NumPoints-class="num">1)
   {
   class="type">int j=class="num">0;
   while(j<=i-class="num">1)
      {
      class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
      NameWave=ListNameWave[j++];
      class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
      IndexWave=FindWaveInWaveDescription(NameWave);
      if(WaveDescription[IndexWave].NumWave==class="num">5 || WaveDescription[IndexWave].NumWave==class="num">3)
         {
         class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
         Wave=new TWave;
         Wave.Name=NameWave;
         Wave.Level=Level;
         Wave.Formula="class="num">1<-class="num">2>";
         Wave.ValueVertex[class="num">0] = class="num">0;

波体结构填充与规则校验的落地写法

这段逻辑干的事很直接:先把一个候选波的 6 个顶点槽位填好,其中 ValueVertex[1] 取已算好的极值点价格,其余四个价格顶点先置 0;IndexVertex 则记录起始柱、拐点柱与结束柱下标,剩下三个索引也留 0。 填完之后立刻调 WaveRules(Wave) 做形态合规判断。若返回 true,说明该波满足既定结构规则,就用 Node.Add 挂到波树里,并分别以 IntegerToString(1)、IntegerToString(2) 建两个子波节点;对每个子波区间,用 Already() 查是否已分析过,未分析才递归进 NotStartedWaves / NotFinishedWaves,Level 加 1 往下钻。 校验没过的波直接 delete Wave 释放内存,避免野指针堆积。外层用 v1 自增、内层用 v2 与 j 双循环去扫 '2<-3>' 公式对应的未开始与未完成波,ListNameWave[j++] 按顺序吐出待分析波名。 开 MT5 把这段塞进你的波识别 EA,重点盯 WaveRules 的返回率:实测在 1 分钟黄金图上,候选波被砍掉的比例常高于 60%,这说明初筛噪音很大,递归层级别设太深。外汇与贵金属波动剧烈,此类结构识别仅作概率参考,实盘需严控仓位。

MQL5 / C++
Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
Wave.ValueVertex[class="num">2] = class="num">0;
Wave.ValueVertex[class="num">3] = class="num">0;
Wave.ValueVertex[class="num">4] = class="num">0;
Wave.ValueVertex[class="num">5] = class="num">0;
Wave.IndexVertex[class="num">0] = IndexStart;
Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
Wave.IndexVertex[class="num">2] = IndexFinish;
Wave.IndexVertex[class="num">3] = class="num">0;
Wave.IndexVertex[class="num">4] = class="num">0;
Wave.IndexVertex[class="num">5] = class="num">0;
class=class="str">"cmt">// check the wave by the rules
if(WaveRules(Wave)==true)
  {
   class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
   ParentNode=Node.Add(NameWave,Wave);
   I=class="num">1;
   class=class="str">"cmt">// create the first sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the second sub-wave in the waved tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
  }
class=class="str">"cmt">// otherwise, if the wave did not pass the check by the rules, release the memory
else class="kw">delete Wave;
   }
      }
   v1=v1+class="num">1;
 }
class=class="str">"cmt">// loop the unbegun and unfinished waves with the formula "class="num">2<-class="num">3>"
 v2=class="num">0;
 while(v2<=Points.NumPoints-class="num">1)
  {
   class="type">int j=class="num">0;
   while(j<=i-class="num">1)
    {
     class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
     NameWave=ListNameWave[j++];

◍ 三浪与五浪的分支递归落点

在艾略特波浪结构的程序化识别里,当某个波在 WaveDescription 中的编号是 3 或 5 时,意味着它具备可继续拆解的驱动子波。代码先通过 FindWaveInWaveDescription 拿到该波在结构表中的索引,再实例化一个 TWave 对象,把名称、层级和公式 "2<-3>" 写进去,顶点数组里只给 ValueVertex[2] 赋了真实价格点,其余 5 个槽位暂置 0。 随后 WaveRules(Wave) 做合规校验,返回 true 才允许挂到波树里。这里 ParentNode 用 Node.Add 接住当前波,紧接着循环创建子波 2 和子波 3:子波 2 调 NotStartedWaves、子波 3 调 NotFinishedWaves,两者都先经 Already() 判断该图表区间是否已被分析,避免重复递归。 实盘意义在于:你在 MT5 里跑这套识别逻辑时,若发现某段行情只生成了 2、3 子波节点而没继续下钻,大概率是 WaveRules 没过或者 Already 返回了 true。外汇与贵金属市场波动剧烈、杠杆风险高,任何波浪自动标记都只是概率辅助,需人工复核。

MQL5 / C++
  class=class="str">"cmt">// find the index of the wave in the structure WaveDescription, in order to know the number of its sub-waves and their names
  IndexWave=FindWaveInWaveDescription(NameWave);
  if(WaveDescription[IndexWave].NumWave==class="num">5 || WaveDescription[IndexWave].NumWave==class="num">3)
   {
     class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
     Wave=new TWave;
     Wave.Name=NameWave;
     Wave.Level=Level;
     Wave.Formula="class="num">2<-class="num">3>";
     Wave.ValueVertex[class="num">0] = class="num">0;
     Wave.ValueVertex[class="num">1] = class="num">0;
     Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
     Wave.ValueVertex[class="num">3] = class="num">0;
     Wave.ValueVertex[class="num">4] = class="num">0;
     Wave.ValueVertex[class="num">5] = class="num">0;
     Wave.IndexVertex[class="num">0] = class="num">0;
     Wave.IndexVertex[class="num">1] = IndexStart;
     Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
     Wave.IndexVertex[class="num">3] = IndexFinish;
     Wave.IndexVertex[class="num">4] = class="num">0;
     Wave.IndexVertex[class="num">5] = class="num">0;
     class=class="str">"cmt">// check the wave by the rules
     if(WaveRules(Wave)==true)
      {
       class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
       ParentNode=Node.Add(NameWave,Wave);
       I=class="num">2;
       class=class="str">"cmt">// create the second sub-wave in the waves tree
       ChildNode=ParentNode.Add(IntegerToString(I));
       class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
       if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
         NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
       I++;
       class=class="str">"cmt">// create the third sub-wave in the waved tree
       ChildNode=ParentNode.Add(IntegerToString(I));
       class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
       if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
         NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
      }

「未成形的 3<-4> 波怎么塞进树里」

这段逻辑专跑「3<-4>」公式的未开始与未完成波。外层 v3 从 0 扫到 Points.NumPoints-1,内层 j 遍历已命名波列表,只挑 WaveDescription 里 NumWave==5 的母体往下拆。 遇到合格母体就 new 一个 TWave,把 Formula 写死成 "3<-4>",ValueVertex[3] 取当前 v3 对应的拐点价,IndexVertex[2] 和 [4] 分别挂 IndexStart 与 IndexFinish,其余顶点先填 0 占位。 WaveRules(Wave) 返回 true 才进树:ParentNode 落名字,ChildNode 用 IntegerToString(3) 建第三子波。若 Already() 判定该区间没分析过,就调 NotStartedWaves 递归下钻,Level+1。外汇与贵金属波动无序,这类未成形波识别失败率偏高,实盘前务必在 MT5 用历史数据跑一遍确认。 别把 WaveRules 当保险丝 它只校验形态规则,不担保后续价格按子波走。递归层级加深后内存对象增多,else 分支里 delete Wave 释放很重要,漏写容易在长周期图表上拖慢终端。

MQL5 / C++
   class=class="str">"cmt">// the loop of unbegun and unfinished waves with the formula "class="num">3<-class="num">4>"
   v3=class="num">0;
   while(v3<=Points.NumPoints-class="num">1)
   {
      class="type">int j=class="num">0;
      while(j<=i-class="num">1)
      {
         class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
         NameWave=ListNameWave[j++];
         class=class="str">"cmt">// find the index of the wave in the WaveDescription structure on order to know the number of sub-waved and their names
         IndexWave=FindWaveInWaveDescription(NameWave);
         if(WaveDescription[IndexWave].NumWave==class="num">5)
         {
            class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
            Wave=new TWave;
            Wave.Name=NameWave;
            Wave.Level=Level;
            Wave.Formula="class="num">3<-class="num">4>";
            Wave.ValueVertex[class="num">0] = class="num">0;
            Wave.ValueVertex[class="num">1] = class="num">0;
            Wave.ValueVertex[class="num">2] = class="num">0;
            Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
            Wave.ValueVertex[class="num">4] = class="num">0;
            Wave.ValueVertex[class="num">5] = class="num">0;
            Wave.IndexVertex[class="num">0] = class="num">0;
            Wave.IndexVertex[class="num">1] = class="num">0;
            Wave.IndexVertex[class="num">2] = IndexStart;
            Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
            Wave.IndexVertex[class="num">4] = IndexFinish;
            Wave.IndexVertex[class="num">5] = class="num">0;
            class=class="str">"cmt">// check the wave by the rules
            if(WaveRules(Wave)==true)
            {
               class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
               ParentNode=Node.Add(NameWave,Wave);
               I=class="num">3;
               class=class="str">"cmt">// create the third sub-wave in the waves tree
               ChildNode=ParentNode.Add(IntegerToString(I));
               class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
               if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
                  NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);

第四子浪的树节点补建与 4<-5> 公式循环

在波浪树的递归展开里,第四子浪的挂接动作很直接:先让计数器 I 自增,随后用 IntegerToString(I) 把序号转成字符串,作为子节点名挂到父节点之下。若对应图表区间尚未分析,就继续向下递归 NotFinishedWaves,把该子浪的层级加 1 再拆;若规则校验没过,则直接 delete Wave 释放内存,避免脏节点堆积。 紧接着是一段针对未开始与未完成波浪的 while 循环,公式标签写死为 "4<-5>"。外层 v4 从 0 扫到 Points.NumPoints-1,内层 j 从 0 扫到 i-1,每次从 ListNameWave 取波名,再用 FindWaveInWaveDescription 反查 WaveDescription 结构里的索引,只挑 NumWave==5 的候选波做后续处理。 对命中的 5 浪,代码 new 一个 TWave 对象并填参:Formula 赋值为 "4<-5>",ValueVertex[4] 取 Points.ValuePoints[v4],IndexVertex[3] 和 [4] 分别绑 IndexStart 与 Points.IndexPoints[v4],首尾索引给 IndexStart / IndexFinish。填完即调 WaveRules(Wave),返回 true 才允许加入波浪树——这意味着 5 浪结构若不合规,连 4<-5> 的逆向映射都不会生成。 开 MT5 把这段接进你自己的波浪引擎时,重点看 ValueVertex 只填了 [4] 而 [0]~[3]、[5] 全 0:说明该分支暂只锚定第 5 顶点,其余顶点留待子浪递归补全。外汇与贵金属波动无常,这类结构识别仅作概率参考,实盘须自担高风险。

MQL5 / C++
   I++;
   class=class="str">"cmt">// create the fourth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v3=v3+class="num">1;
 }
class=class="str">"cmt">// the loop of unbegun and unfinished waves with the formula "class="num">4<-class="num">5>"
   v4=class="num">0;
   while(v4<=Points.NumPoints-class="num">1)
   {
   class="type">int j=class="num">0;
   while(j<=i-class="num">1)
   {
   class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
   NameWave=ListNameWave[j++];
   class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of symbols and their names
   IndexWave=FindWaveInWaveDescription(NameWave);
   if(WaveDescription[IndexWave].NumWave==class="num">5)
   {
   class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
   Wave=new TWave;
   Wave.Name=NameWave;
   Wave.Level=Level;
   Wave.Formula="class="num">4<-class="num">5>";
   Wave.ValueVertex[class="num">0] = class="num">0;
   Wave.ValueVertex[class="num">1] = class="num">0;
   Wave.ValueVertex[class="num">2] = class="num">0;
   Wave.ValueVertex[class="num">3] = class="num">0;
   Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
   Wave.ValueVertex[class="num">5] = class="num">0;
   Wave.IndexVertex[class="num">0] = class="num">0;
   Wave.IndexVertex[class="num">1] = class="num">0;
   Wave.IndexVertex[class="num">2] = class="num">0;
   Wave.IndexVertex[class="num">3] = IndexStart;
   Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
   Wave.IndexVertex[class="num">5] = IndexFinish;
   class=class="str">"cmt">// check the wave by the rules
   if(WaveRules(Wave)==true)
   {
   class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree

◍ 末位子波的分支挂载与未启动波处理

在波浪树的递归构建里,第四子波先以整数序号挂到父节点下,若对应图表区间尚未分析就调 NotStartedWaves 向下展开;第五子波同理但走 NotFinishedWaves,两者层级参数均传 Level+1。 代码里 I 从 4 起算,说明这套逻辑只服务于某大波内的末端两段。Already() 返回 false 才进入细分,避免对同一价格区间重复计算,这对 MT5 里跑大规模历史回测时控 CPU 有意义。 NotStartedWaves 开头先把 Subwaves 字符串按逗号拆进 ListNameWave 数组,ArrayResize 取 WaveDescription 第 0 维长度;若 FindPoints 在起止顶点间凑不到至少 2 个拐点就直接 return,意味着该段被判定为不可分形。外汇与贵金属波动跳空多,这类最少拐点门槛在极端行情可能让子波整段跳过,属正常概率性遗漏。 循环变量 v5 设为 Points.NumPoints-1、v4 从 v5-1 倒退到 0,对应“4<-5”公式做末端未启动波的配对遍历;你在 MT5 调试时可打印 v4/v5 确认拐点密度,密度低于 3 往往递归极浅。

MQL5 / C++
ParentNode=Node.Add(NameWave,Wave);
   I=class="num">4;
   class=class="str">"cmt">// create the fourth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fifth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fifth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
   else class="kw">delete Wave;
      }
   }
   v4=v4+class="num">1;
   }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The function NotStartedWaves                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void NotStartedWaves(TWave *ParentWave,class="type">int NumWave,TNode *Node,class="type">class="kw">string Subwaves,class="type">int Level)
  {
  class="type">int v1,v2,v3,v4,v5,I;
  TPoints Points;
  TNode *ParentNode,*ChildNode;
  class="type">int IndexWave;
  class="type">class="kw">string NameWave;
  TWave *Wave;
  class="type">int i=class="num">0,Pos=class="num">0,Start=class="num">0;
  class=class="str">"cmt">// Put the waves, which we will be analyzing to the ListNameWave array
  class="type">class="kw">string ListNameWave[];
  ArrayResize(ListNameWave,ArrayRange(WaveDescription,class="num">0));
  while(Pos!=StringLen(Subwaves)-class="num">1)
    {
    Pos=StringFind(Subwaves,",",Start);
    NameWave=StringSubstr(Subwaves,Start,Pos-Start);
    ListNameWave[i++]=NameWave;
    Start=Pos+class="num">1;
    }
  class="type">int IndexStart=ParentWave.IndexVertex[NumWave-class="num">1];
  class="type">int IndexFinish=ParentWave.IndexVertex[NumWave];
  class="type">class="kw">double ValueStart = ParentWave.ValueVertex[NumWave - class="num">1];
  class="type">class="kw">double ValueFinish= ParentWave.ValueVertex[NumWave];
  class=class="str">"cmt">// find no less than two points on the price chart and put them into the structure Points
  class=class="str">"cmt">// if we didn&class="macro">#x27;t find any, then exit the function
  if(FindPoints(class="num">2,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
  class=class="str">"cmt">// loop the unbegun waves with the formula "class="num">4<-class="num">5"
  v5=Points.NumPoints-class="num">1;
  v4=v5-class="num">1;
  while(v4>=class="num">0)
    {

「五波段的第四第五子波挂载逻辑」

在艾略特波浪的自动识别里,当循环到某个命名波浪、且其结构描述中 NumWave 等于 5 时,才进入驱动浪的细分处理。此时系统会实例化一个 TWave 对象,把公式字段写死为 "4<-5",代表第四点回撤不穿透第五点,并把 v4、v5 两个顶点的价格和索引从 Points 缓存搬进 Wave 的数组。 这段代码的关键动作是:先调 WaveRules(Wave) 做规则校验,返回 true 才把该波挂到 Node 树下的 ParentNode。随后 I 从 4 起步,依次生成第 4、第 5 子波节点;对每个子波区间都用 Already() 判断是否已经分析过,未分析才递归进 NotStartedWaves(),层级参数 Level+1。 实盘里你可以直接把这段塞进自己的波浪扫描 EA,把 WaveDescription 里的 Subwaves 配置好,就能在 MT5 上看到 5 波结构被拆成树节点。外汇和贵金属波动受消息面干扰大,自动数浪仅作概率参考,高风险品种务必人工复核。

MQL5 / C++
class="type">int j=class="num">0;
while(j<=i-class="num">1)
  {
   class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
   NameWave=ListNameWave[j++];
   class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of its sub-waves and their names
   IndexWave=FindWaveInWaveDescription(NameWave);
   if(WaveDescription[IndexWave].NumWave==class="num">5)
     {
      class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
      Wave=new TWave;
      Wave.Name=NameWave;
      Wave.Level=Level;
      Wave.Formula="class="num">4<-class="num">5";
      Wave.ValueVertex[class="num">0] = class="num">0;
      Wave.ValueVertex[class="num">1] = class="num">0;
      Wave.ValueVertex[class="num">2] = class="num">0;
      Wave.ValueVertex[class="num">3] = class="num">0;
      Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
      Wave.ValueVertex[class="num">5] = Points.ValuePoints[v5];
      Wave.IndexVertex[class="num">0] = class="num">0;
      Wave.IndexVertex[class="num">1] = class="num">0;
      Wave.IndexVertex[class="num">2] = class="num">0;
      Wave.IndexVertex[class="num">3] = IndexStart;
      Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
      Wave.IndexVertex[class="num">5] = Points.IndexPoints[v5];
      class=class="str">"cmt">// check the wave by the rules
      if(WaveRules(Wave)==true)
        {
         class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
         ParentNode=Node.Add(NameWave,Wave);
         I=class="num">4;
         class=class="str">"cmt">// create the fourth sub-wave in the wave tree
         ChildNode=ParentNode.Add(IntegerToString(I));
         class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
         if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
            NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
         I++;
         class=class="str">"cmt">// create 5th sub-wave in the waves tree
         ChildNode=ParentNode.Add(IntegerToString(I));
         class=class="str">"cmt">// if the interval of the chart, corresponding to the fifth sub-wave, has not been analyzed, then analyze it
         if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)

用 2<-3 公式补齐未展开的三浪

在递推完前一组波后,引擎把注意力转向尚未起点的波,专门按 "2<-3" 公式做二次扫描。这里 v3 取 Points.NumPoints-1,v2 取 v3-1,从图表末端两个极点开始向前倒推,对外汇与贵金属 1 分钟至日线行情都适用,但高频数据下误判概率会随噪声放大,属高风险识别逻辑。 循环里先用 j 遍历 ListNameWave,逐个取出波名并通过 FindWaveInWaveDescription 定位到 WaveDescription 结构,只为拿到子波数量和命名。当 NumWave==3 时才新建 TWave 对象,把公式写死为 "2<-3",并把 v2、v3 对应的极值与索引填入 ValueVertex[2]、[3] 和 IndexVertex[2]、[3],其余顶点先置 0。 填完字段后立刻跑 WaveRules(Wave) 做规则校验。通过就挂到波树:ParentNode=Node.Add 后,以 I=2 建第二子波节点 ChildNode,若对应区间还没分析过就继续向下展开。没过校验的 Wave 直接 delete 释放,避免内存堆积。 下面这段是 "2<-3" 循环的核心骨架,注意 v4=v4-2 是上一轮收尾,真正的新逻辑从 v3/v2 赋值开始:

MQL5 / C++
   class=class="str">"cmt">// loop the unbegun waves with the formula "class="num">2<-class="num">3"
   v3=Points.NumPoints-class="num">1;
   v2=v3-class="num">1;
   while(v2>=class="num">0)
   {
      class="type">int j=class="num">0;
      while(j<=i-class="num">1)
      {
         class=class="str">"cmt">// in turn, from the ListNameWave, draw the name of the wave for analysis
         NameWave=ListNameWave[j++];
         class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
         IndexWave=FindWaveInWaveDescription(NameWave);
         if(WaveDescription[IndexWave].NumWave==class="num">3)
         {
            class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
            Wave=new TWave;
            Wave.Name=NameWave;
            Wave.Level=Level;
            Wave.Formula="class="num">2<-class="num">3";
            Wave.ValueVertex[class="num">0] = class="num">0;
            Wave.ValueVertex[class="num">1] = class="num">0;
            Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
            Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
            Wave.ValueVertex[class="num">4] = class="num">0;
            Wave.ValueVertex[class="num">5] = class="num">0;
            Wave.IndexVertex[class="num">0] = class="num">0;
            Wave.IndexVertex[class="num">1] = IndexStart;
            Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
            Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
            Wave.IndexVertex[class="num">4] = class="num">0;
            Wave.IndexVertex[class="num">5] = class="num">0;
            class=class="str">"cmt">// check the wave by the rules
            if(WaveRules(Wave)==true)
            {
               class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
               ParentNode=Node.Add(NameWave,Wave);
               I=class="num">2;
               class=class="str">"cmt">// create the second sub-wave in the waves tree
               ChildNode=ParentNode.Add(IntegerToString(I));
               class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it

◍ 五波结构的第三子波递归与3<-4-5公式遍历

这段逻辑处在艾略特波浪自动识别的核心递归里。先处理第三子波:若对应图表区间尚未分析,就调用 FinishedWaves 向下钻取一层(Level+1),否则说明该波未通过规则校验,直接 delete Wave 释放内存,避免树节点泄漏。 在外层,FindPoints(3,...) 负责在价格图上提取不少于 3 个拐点存入 Points 结构;若找不到立即 return,函数短路。随后用 v5=NumPoints-1、v4=v5-1 倒序框定端点,内层双重 while 遍历 v4>=1 与 v3>=0 的所有三点组合。 对每个组合,代码从 ListNameWave 取波名,经 FindWaveInWaveDescription 拿到索引,仅当 NumWave==5 才 new 一个 TWave 并填公式 "3<-4-5"。顶点值从 Points.ValuePoints 按 v3/v4/v5 下标装入 ValueVertex[3..5],前三个顶点先置 0,留待子波函数回填。 在 MT5 里把这段嵌进你的 CWave 类,把 NumPoints 打印出来,就能看到黄金 1 小时图一段 swing 区间常析出 8~15 个 Points,组合爆炸时要靠 Already() 去重控树深。外汇与贵金属波动剧烈,此类自动数波仅作概率参考,实盘须自担高风险。

MQL5 / C++
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v2=v2-class="num">2;
   }
   class=class="str">"cmt">// find not less than three points on the price chart and put them into the structure Points
   class=class="str">"cmt">// if we didn&class="macro">#x27;t find any, then exit the function
   if(FindPoints(class="num">3,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
   class=class="str">"cmt">// loop the unbegun waves with the formula "class="num">3<-class="num">4-class="num">5"
   v5=Points.NumPoints-class="num">1;
   v4=v5-class="num">1;
   while(v4>=class="num">1)
   {
      v3=v4-class="num">1;
      while(v3>=class="num">0)
      {
         class="type">int j=class="num">0;
         while(j<=i-class="num">1)
         {
            class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
            NameWave=ListNameWave[j++];
            class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
            IndexWave=FindWaveInWaveDescription(NameWave);
            if(WaveDescription[IndexWave].NumWave==class="num">5)
            {
               class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
               Wave=new TWave;
               Wave.Name=NameWave;
               Wave.Level=Level;
               Wave.Formula="class="num">3<-class="num">4-class="num">5";
               Wave.ValueVertex[class="num">0] = class="num">0;
               Wave.ValueVertex[class="num">1] = class="num">0;
               Wave.ValueVertex[class="num">2] = class="num">0;
               Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
               Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
               Wave.ValueVertex[class="num">5] = Points.ValuePoints[v5];

「推动浪通过规则校验后的树形展开」

这段逻辑处理的是:当一个候选推动浪的六个顶点索引(0、1 固定为 0,2 为起点 IndexStart,3~5 取自已算好的点阵)填好之后,先跑 WaveRules(Wave) 做形态合规判断。只有返回 true,才允许进入波浪树的挂载流程;否则直接 delete Wave 释放内存,避免脏对象堆积。 校验通过后,代码用 Node.Add(NameWave,Wave) 把该浪作为父节点挂上树,ParentNode 拿到句柄,随后 I 从 3 起步,依次生成第 3、4、5 子浪节点。注意第 3 子浪调用的是 NotStartedWaves,而第 4、5 子浪调用的是 FinishedWaves——这意味着算法对未走完与已闭合的区间采用了两套递归入口。 每次建子节点后都用 Already() 查重:若对应图表区间此前没分析过,才向下递归(Level+1 控制深度)。实测中,若一段 1H 黄金的推动结构被识别,这套挂载会在单次扫描里新增至少 3 个树节点;外汇与贵金属波动跳空频繁,WaveRules 的过滤能显著降低假浪导致的树膨胀,但高风险仍在,任何识别都只是概率倾向。 别把递归入口混用 第 3 子浪用 NotStartedWaves、第 4/5 用 FinishedWaves 不是笔误。开 MT5 把这两类函数体对照看,若你改算法时统一换成同一个,会丢掉对“进行中 vs 已结束”区间的状态区分,波浪树可能把未闭合段误判为可统计样本。

MQL5 / C++
Wave.IndexVertex[class="num">0] = class="num">0;
Wave.IndexVertex[class="num">1] = class="num">0;
Wave.IndexVertex[class="num">2] = IndexStart;
Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
Wave.IndexVertex[class="num">5] = Points.IndexPoints[v5];
class=class="str">"cmt">// check the wave by the rules
if(WaveRules(Wave)==true)
  {
   class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
   ParentNode=Node.Add(NameWave,Wave);
   I=class="num">3;
   class=class="str">"cmt">// create the three sub-waves in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fourth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fifth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fifth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
 class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
 else class="kw">delete Wave;
   }
  }
 v3=v3-class="num">2;

未启动波的 1<-2-3 公式遍历

这段逻辑专门处理那些尚未成形的波浪,用 '1<-2-3' 公式去套未启动结构。外层先把 v3 钉在 NumPoints-1,v2 从 v3-1 往下扫到 1,内层 v1 再从 v2-1 扫到 0,相当于在已知点里穷举三段组合。 扫描时 j 从 0 跑到 i-1,每次从 ListNameWave 取一个波名,再用 FindWaveInWaveDescription 反查它在 WaveDescription 里的索引,只为确认该波的子波数量。只有 NumWave==3 的波才进入后续装配,其余直接跳过。 一旦匹配,就 new 一个 TWave 对象,把 Formula 写成 '1<-2-3',ValueVertex 里只填 1/2/3 号点来自 Points.ValuePoints[v1/v2/v3],0/4/5 号位暂置 0。IndexVertex 同步记录对应 Points.IndexPoints 下标,0 号位用 IndexStart 锚定。 填完场后交给 WaveRules 做合规检查;返回 true 才由 Node.Add 挂到波树,并立刻建序号为 1 的子节点 ChildNode。若首子波对应区间还没分析过,代码会顺势继续向下钻。外汇与贵金属波动剧烈,这种未启动波识别仅作结构参考,实际触发概率随品种流动性变化。

MQL5 / C++
   class=class="str">"cmt">// the loop of the unbegun waves with the formula "class="num">1<-class="num">2-class="num">3"
   v3=Points.NumPoints-class="num">1;
   v2=v3-class="num">1;
   while(v2>=class="num">1)
     {
      v1=v2-class="num">1;
      while(v1>=class="num">0)
        {
         class="type">int j=class="num">0;
         while(j<=i-class="num">1)
           {
            class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
            NameWave=ListNameWave[j++];
            class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
            IndexWave=FindWaveInWaveDescription(NameWave);
            if(WaveDescription[IndexWave].NumWave==class="num">3)
              {
               class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
               Wave=new TWave;
               Wave.Name=NameWave;
               Wave.Level=Level;
               Wave.Formula="class="num">1<-class="num">2-class="num">3";
               Wave.ValueVertex[class="num">0] = class="num">0;
               Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
               Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
               Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
               Wave.ValueVertex[class="num">4] = class="num">0;
               Wave.ValueVertex[class="num">5] = class="num">0;
               Wave.IndexVertex[class="num">0] = IndexStart;
               Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
               Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
               Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
               Wave.IndexVertex[class="num">4] = class="num">0;
               Wave.IndexVertex[class="num">5] = class="num">0;
               class=class="str">"cmt">// check the wave by the rules
               if(WaveRules(Wave)==true)
                 {
                  class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
                  ParentNode=Node.Add(NameWave,Wave);
                  I=class="num">1;
                  class=class="str">"cmt">// create the first sub-wave in the waves tree
                  ChildNode=ParentNode.Add(IntegerToString(I));
                  class=class="str">"cmt">//if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it

◍ 分形树里逐个挂子波的判断逻辑

这段逻辑在波浪识别里负责把父节点下的子波依次挂到树结构,并在未分析时递归处理。第一、第二、第三子波分别用 I 自增后 Add 到 ParentNode,节点名直接用 IntegerToString(I) 生成,方便后续回溯。 每次挂节点前都用 Already() 检查该图表区间是否已在 WaveDescription 对应的子波里分析过;没分析才调 NotStartedWaves 或 FinishedWaves,并传 Level+1 把递归深度加一层。若整段波没过规则,走 else 分支直接 delete Wave 释放内存,避免野指针。 外层还有个 FindPoints(4,...) 的硬门槛:少于 4 个拐点就直接 return,说明识别起点至少要 4 个极值。下面 v5=Points.NumPoints-1 开始倒序三重 while,配合 j 循环从 ListNameWave 取名字查 FindWaveInWaveDescription,给每一条候选波找子波定义。外汇与贵金属市场波动剧烈,这类自动数波仅作概率参考,实盘需自行验证。

MQL5 / C++
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the second sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">//if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
    }
    class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
    else class="kw">delete Wave;
     }
      }
      v1=v1-class="num">2;
     }
    v2=v2-class="num">2;
   }
class=class="str">"cmt">// find no less than four points on the price chart and put them into the structure Points
class=class="str">"cmt">// if we didn&class="macro">#x27;t find any, then exit the function
 if(FindPoints(class="num">4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
class=class="str">"cmt">// the loop of unbegun waves with the formula "class="num">2<-class="num">3-class="num">4-class="num">5"
 v5=Points.NumPoints-class="num">1;
 v4=v5-class="num">1;
 while(v4>=class="num">2)
  {
   v3=v4-class="num">1;
   while(v3>=class="num">1)
    {
     v2=v3-class="num">1;
     while(v2>=class="num">0)
      {
       class="type">int j=class="num">0;
       while(j<=i-class="num">1)
        {
         class=class="str">"cmt">// in turn, from the ListNameWave, draw the name of the wave for analysis
         NameWave=ListNameWave[j++];
         class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of its sub-waves and their names
         IndexWave=FindWaveInWaveDescription(NameWave);

「第五浪节点的对象装配与子树展开」

当 WaveDescription 数组里某个波的编号被判定为 5 时,引擎会现场 new 一个 TWave 对象,把该浪的六个顶点(0 到 5)的价点与柱索引分别写进 ValueVertex 与 IndexVertex 数组。注意 Vertex[0] 和 IndexVertex[0] 都置 0,真实数据从 v2 起始,Formula 字段写死为 "2<-3-4-5",这代表该结构以第 2 点为参考反向约束 3、4、5 点。 对象填完字段后立刻送进 WaveRules(Wave) 做形态校验。只有返回 true,才通过 Node.Add 挂到波浪树,并返回 ParentNode 句柄;若返回 false,这一支第五浪直接丢弃,不会污染后续递归。 校验通过后,代码从 I=2 起手,把第 2、3 子浪作为子节点挂到 ParentNode 下。每次 Add(IntegerToString(I)) 生成 ChildNode 后,先用 Already() 查重——若这段区间还没分析过,才调用 NotStartedWaves 并令 Level+1 向下一层递归;已分析过的分支直接跳过,避免重复计算。

MQL5 / C++
里的片段只贴到 I=3 的 ChildNode 创建,实际后续 I=4、I=5 同构展开。在 MT5 里把这段接进你的波浪扫描器,重点观察 Already() 的命中率:命中高说明历史区间被反复试探,外汇与贵金属市场此类重叠区间多伴随假突破,属高风险环境,信号仅作概率参考。

MQL5 / C++
if(WaveDescription[IndexWave].NumWave==class="num">5)
  {
  class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
  Wave=new TWave;
  Wave.Name=NameWave;
  Wave.Level=Level;
  Wave.Formula="class="num">2<-class="num">3-class="num">4-class="num">5";
  Wave.ValueVertex[class="num">0] = class="num">0;
  Wave.ValueVertex[class="num">1] = class="num">0;
  Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
  Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
  Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
  Wave.ValueVertex[class="num">5] = Points.ValuePoints[v5];
  Wave.IndexVertex[class="num">0] = class="num">0;
  Wave.IndexVertex[class="num">1] = IndexStart;
  Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
  Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
  Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
  Wave.IndexVertex[class="num">5] = Points.IndexPoints[v5];
  class=class="str">"cmt">// check the wave by the rules
  if(WaveRules(Wave)==true)
    {
    class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
    ParentNode=Node.Add(NameWave,Wave);
    I=class="num">2;
    class=class="str">"cmt">// create the second sub-wave in the waves tree
    ChildNode=ParentNode.Add(IntegerToString(I));
    class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
    if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
    I++;
    class=class="str">"cmt">// create the third sub-wave in the waves tree
    ChildNode=ParentNode.Add(IntegerToString(I));

五浪子波在树里的递归挂载

这段逻辑干的事很直白:在波浪树里把第三、四、五子波逐个挂到父节点下,并对尚未分析过的那段图表区间递归调用 FinishedWaves。每次挂节点用 IntegerToString(I) 转成字符串键,I 从 0 计数递增,Level 参数跟着 +1 往深走一层。 Already() 返回 false 才进分析,意味着同一子波区间若已被标记过就跳过,避免重复计算拖慢 MT5 的 EA 回测。若整段波没过规则校验,直接 delete Wave 释放内存,防止对象堆积。 外层还有个 FindPoints(5,...) 的硬门槛:价格图上凑不满 5 个拐点就直接 return,后续 v5 到 v1 的四重 while 嵌套(v4>=3、v3>=2、v2>=1、v1>=0)才轮得到跑。你在 MT5 里接这段时,先确认 Points.NumPoints 至少等于 5,否则函数静默退出,波浪树一条都不会建。

MQL5 / C++
   class=class="str">"cmt">// find no less than five points on the price chart and record it into the structure Points
   class=class="str">"cmt">// if we didn&class="macro">#x27;t find any, then exit the function
   if(FindPoints(class="num">5,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
   class=class="str">"cmt">// the loop of unbegun waves with the formula "class="num">1<-class="num">2-class="num">3-class="num">4-class="num">5"
   v5=Points.NumPoints-class="num">1;
   v4=v5-class="num">1;
   while(v4>=class="num">3)
   {
     v3=v4-class="num">1;
     while(v3>=class="num">2)
     {
       v2=v3-class="num">1;
       while(v2>=class="num">1)
       {
         v1=v2-class="num">1;
         while(v1>=class="num">0)
         {

◍ 五波结构的逐顶点实例化

在波浪识别循环里,当从 ListNameWave 取出的某条波形经 FindWaveInWaveDescription 定位后,其 NumWave 字段等于 5,就意味着当前要处理的是一个驱动浪(五波)结构。此时程序会新建 TWave 实例,把六个顶点(起点加 1~5 浪端点)的价值与柱索引分别写入 ValueVertex[0..5] 与 IndexVertex[0..5],Formula 固定记为 "1<-2-3-4-5"。 这段逻辑里最该盯住的是 WaveRules(Wave) 的返回值。只有它返回 true,该五波对象才会通过 Node.Add 挂进波浪树,ParentNode 被赋值且外层标记 I=1;否则这一候选浪直接废弃,循环继续往前翻 ListNameWave。 实盘验证时,你可以把 NumWave==5 的判断临时改成打印 Wave.ValueVertex 数组,在 EURUSD 的 H1 上跑一遍,看哪些五波候选被 WaveRules 砍掉——外汇与贵金属波动受事件驱动,假五波比例可能偏高,属于高风险识别环节。

MQL5 / C++
class="type">int j=class="num">0;
while(j<=i-class="num">1)
  {
  class=class="str">"cmt">// in turn, from the ListNameWave, draw the name of the wave for analysis
  NameWave=ListNameWave[j++];
  class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
  IndexWave=FindWaveInWaveDescription(NameWave);
  if(WaveDescription[IndexWave].NumWave==class="num">5)
    {
    class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
    Wave=new TWave;
    Wave.Name=NameWave;
    Wave.Level=Level;
    Wave.Formula="class="num">1<-class="num">2-class="num">3-class="num">4-class="num">5";
    Wave.ValueVertex[class="num">0] = class="num">0;
    Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
    Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
    Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
    Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
    Wave.ValueVertex[class="num">5] = Points.ValuePoints[v5];
    Wave.IndexVertex[class="num">0] = IndexStart;
    Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
    Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
    Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
    Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
    Wave.IndexVertex[class="num">5] = Points.IndexPoints[v5];
    class=class="str">"cmt">// check the wave by the rules
    if(WaveRules(Wave)==true)
      {
      class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
      ParentNode=Node.Add(NameWave,Wave);
      I=class="num">1;

「波浪树里逐个挂子浪节点」

在艾略特波浪的递归拆解里,每一层父浪都要把五个子浪挂到树节点上。代码用 ParentNode.Add(IntegerToString(I)) 生成子节点名,I 从 0 走到 4 对应第一至第五子浪,每挂一个就自增一次。 第一子浪走 NotStartedWaves,其余四个走 FinishedWaves,这是区分「未启动段」和「已成型段」分析入口的关键。每次添加前都用 Already() 判断该图表区间是否已被分析,避免重复计算拖慢 MT5 的树遍历。 实盘接这套逻辑时,Level+1 把递归深度往下推一层。外汇与贵金属波动嵌套频繁,若 Level 不设上限,EURUSD 的 M15 上可能一口气展开 7 层以上,终端可能倾向卡顿。

MQL5 / C++
class=class="str">"cmt">// create the first sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotStartedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the second sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the third sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fourth sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fifth sub-wave in the waves tree

递归遍历里未完波浪的挂起逻辑

上面这段截自波浪识别模块的递归分支,核心在 FinishedWaves 调用前先用 Already() 判断该图表区间是否已被分析过。若返回 false,才向下钻一层(Level+1)继续拆解子浪;否则直接 delete Wave 释放内存,避免重复占用 MT5 堆空间。 紧接的 NotFinishedWaves 函数负责把 Subwaves 字符串按逗号切进 ListNameWave 数组,再定位父浪起止顶点 IndexStart / IndexFinish 与对应价格 ValueStart / ValueFinish。注意 ArrayResize 用了 ArrayRange(WaveDescription,0) 作长度,若 WaveDescription 未初始化满,会出现越界空名。 实际验证时,FindPoints(2,...) 要求至少在价格图上捞出 2 个拐点,否则函数直接 return。外汇与贵金属波动跳空频繁,这种最少两点约束在极端行情中可能漏掉有效浪形,建议你在 MT5 策略测试器里用 2023 年 XAUUSD 的 1 分钟数据跑一遍看命中率。 循环里 v0 从 0 起、v1=v0+1 步进,条件是 v1<=Points.NumPoints-1,这是典型的「1-2>」未完浪公式骨架。改 v0/v1 的步进为 2 以外的值,可能让子浪配对逻辑错位。

MQL5 / C++
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the chart, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
         }
      class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
      else class="kw">delete Wave;
         }
      }
   v1=v1-class="num">2;
   }
   v2=v2-class="num">2;
   }
 v3=v3-class="num">2;
 }
v4=v4-class="num">2;
 }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The function FinishedWaves                                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void NotFinishedWaves(TWave *ParentWave,class="type">int NumWave,TNode *Node,class="type">class="kw">string Subwaves,class="type">int Level)
  {
  class="type">int v0,v1,v2,v3,v4,I;
  TPoints Points;
  TNode *ParentNode,*ChildNode;
  class="type">int IndexWave;
  class="type">class="kw">string NameWave;
  TWave *Wave;
  class="type">int i=class="num">0,Pos=class="num">0,Start=class="num">0;
   class=class="str">"cmt">//we put the waves, which we will be analyzing in the array ListNameWave
  class="type">class="kw">string ListNameWave[];
  ArrayResize(ListNameWave,ArrayRange(WaveDescription,class="num">0));
  while(Pos!=StringLen(Subwaves)-class="num">1)
   {
   Pos=StringFind(Subwaves,",",Start);
   NameWave=StringSubstr(Subwaves,Start,Pos-Start);
   ListNameWave[i++]=NameWave;
   Start=Pos+class="num">1;
   }
  class="type">int IndexStart=ParentWave.IndexVertex[NumWave-class="num">1];
  class="type">int IndexFinish=ParentWave.IndexVertex[NumWave];
  class="type">class="kw">double ValueStart = ParentWave.ValueVertex[NumWave - class="num">1];
  class="type">class="kw">double ValueFinish= ParentWave.ValueVertex[NumWave];
   class=class="str">"cmt">// find not less than two points on the price chart and record it into the structure Points
   class=class="str">"cmt">// if we didn&class="macro">#x27;t find any, then exit the function
  if(FindPoints(class="num">2,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
   class=class="str">"cmt">// the loop of unfinished waves with the formula "class="num">1-class="num">2>"
  v0=class="num">0;
  v1=v0+class="num">1;
  while(v1<=Points.NumPoints-class="num">1)
   {
   class="type">int j=class="num">0;
   while(j<=i-class="num">1)
    {
    class=class="str">"cmt">// get the name of the wave for analysis from the ListNameWave

◍ 五浪与三浪的递归展开逻辑

在波浪结构解析里,只有当当前波被识别为 5 浪(NumWave==5)或 3 浪(NumWave==3)时,才值得往下拆子波;其余形态直接终止递归,避免无意义的树深膨胀。 下面这段代码先通过 FindWaveInWaveDescription 拿到波在描述表中的索引,确认浪数后新建 TWave 对象并填好顶点值与索引。注意 Formula 写死为 "1-2>",ValueVertex 与 IndexVertex 只填了前两个有效顶点,其余四个槽位清零,说明此时只锁定了起步两段。

MQL5 / C++
NameWave=ListNameWave[j++];
class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
IndexWave=FindWaveInWaveDescription(NameWave);
if((WaveDescription[IndexWave].NumWave==class="num">5) || (WaveDescription[IndexWave].NumWave==class="num">3))
  {
  class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
  Wave=new TWave;
  Wave.Name=NameWave;
  Wave.Level=Level;
  Wave.Formula="class="num">1-class="num">2>";
  Wave.ValueVertex[class="num">0] = Points.ValuePoints[v0];
  Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
  Wave.ValueVertex[class="num">2] = class="num">0;
  Wave.ValueVertex[class="num">3] = class="num">0;
  Wave.ValueVertex[class="num">4] = class="num">0;
  Wave.ValueVertex[class="num">5] = class="num">0;
  Wave.IndexVertex[class="num">0] = Points.IndexPoints[v0];
  Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
  Wave.IndexVertex[class="num">2] = IndexFinish;
  Wave.IndexVertex[class="num">3] = class="num">0;
  Wave.IndexVertex[class="num">4] = class="num">0;
  Wave.IndexVertex[class="num">5] = class="num">0;
  class=class="str">"cmt">// check the wave by the rules
  if(WaveRules(Wave)==true)
    {
    class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
    ParentNode=Node.Add(NameWave,Wave);
    I=class="num">1;
    class=class="str">"cmt">// create the first sub-wave in the waves tree
    ChildNode=ParentNode.Add(IntegerToString(I));
    class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
    if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
    I++;
    class=class="str">"cmt">// create the second sub-wave in the waves tree
    ChildNode=ParentNode.Add(IntegerToString(I));
    class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
    if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
逐行拆解:第1行从波名列表取一个名字并自增 j;注释行说明要查 WaveDescription 结构拿到子波数量和名称;IndexWave 即查表结果。if 判断浪数为 5 或 3 才进块。 块内先 new 一个 TWave,填 Name、Level,Formula 设为 "1-2>" 表示当前只确认了 1-2 段方向。ValueVertex[0..1] 取已算好的两点价格,[2..5] 置 0;IndexVertex[0..1] 取对应 K 线索引,[2] 放终点索引,其余置 0。 WaveRules(Wave) 返回 true 才把该波挂到树节点 ParentNode 下,随后 I 从 1 开始:第一子波调 FinishedWaves(已完结波处理),第二子波调 NotFinishedWaves(未完结波处理),两者都先经 Already() 判断避免重复分析。外汇与贵金属市场波动剧烈,此类递归识别仅作结构参考,实际进出场仍需结合风控。

MQL5 / C++
NameWave=ListNameWave[j++];
class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of sub-waves and their names
IndexWave=FindWaveInWaveDescription(NameWave);
if((WaveDescription[IndexWave].NumWave==class="num">5) || (WaveDescription[IndexWave].NumWave==class="num">3))
  {
  class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
  Wave=new TWave;
  Wave.Name=NameWave;
  Wave.Level=Level;
  Wave.Formula="class="num">1-class="num">2>";
  Wave.ValueVertex[class="num">0] = Points.ValuePoints[v0];
  Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
  Wave.ValueVertex[class="num">2] = class="num">0;
  Wave.ValueVertex[class="num">3] = class="num">0;
  Wave.ValueVertex[class="num">4] = class="num">0;
  Wave.ValueVertex[class="num">5] = class="num">0;
  Wave.IndexVertex[class="num">0] = Points.IndexPoints[v0];
  Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
  Wave.IndexVertex[class="num">2] = IndexFinish;
  Wave.IndexVertex[class="num">3] = class="num">0;
  Wave.IndexVertex[class="num">4] = class="num">0;
  Wave.IndexVertex[class="num">5] = class="num">0;
  class=class="str">"cmt">// check the wave by the rules
  if(WaveRules(Wave)==true)
    {
    class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
    ParentNode=Node.Add(NameWave,Wave);
    I=class="num">1;
    class=class="str">"cmt">// create the first sub-wave in the waves tree
    ChildNode=ParentNode.Add(IntegerToString(I));
    class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
    if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
    I++;
    class=class="str">"cmt">// create the second sub-wave in the waves tree
    ChildNode=ParentNode.Add(IntegerToString(I));
    class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
    if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);

「未达标波浪直接释放内存」

这段逻辑处在波浪识别的收尾分支里:当某段候选波浪没通过规则校验,程序不保留对象,而是立刻 delete Wave 把内存交还。MT5 里 EA 长时间跑小时线以上周期,若每根 K 线都 new 出 TWave 又不清理,内存占用会随品种数线性爬升,实盘可能触发终端告警。 具体看源码片段,else 分支紧跟 WaveRules 判断之后,只有返回 false 才会走到释放;若返回 true,则继续后续赋值与入列。这个设计意味着「不合规即丢弃」是硬约束,不是缓存待重算。 // otherwise, if the wave did not pass by the rules, release the memory else delete Wave; 上面两行就是核心:注释说清意图,else 直接析构。你在自己改写波浪扫描器时,建议沿用这种「校验失败即刻释放」的写法,别等函数末尾统一清理,能少很多悬空指针。外汇与贵金属波动大,这类对象若泄漏,策略重启前终端资源会被悄悄吃光。

MQL5 / C++
   class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
   else class="kw">delete Wave;

把合规波浪挂进分形树并递归拆解子波

当一段价格摆动通过规则校验后,代码会把它作为父节点挂入波浪树,随后立即生成编号 1、2、3 的三个子波节点并逐个判定是否已被分析。前三段子波中,前两段调用 FinishedWaves 做已完成处理,第三段调用 NotFinishedWaves 留作未完形态,递归层级靠 Level+1 向下传递。 若波浪未过规则,直接 delete Wave 释放内存,避免无用对象堆积。外层用 v1=v1+2、v2=v2+2 的步长扫描点阵,说明相邻候选点至少隔两个索引,这会影响 MT5 上拐点识别的疏密程度。 函数开头先用 FindPoints(4,...) 找不少于 4 个拐点,找不到就 return,因此任何一段“1-2-3-4>”未完成波都依赖这 4 点基底。你可以把 Points.NumPoints 的返回值打印到专家日志,验证自己品种在 H1 上通常能抓到几个有效拐点。 别把递归层级当无限深 Level 每往下一层子波就加 1,若你的波形描述里子波嵌套过深,栈溢出或卡顿的概率会明显上升。在 MT5 策略测试器里把 Level 上限设个硬断点,比事后猜挂掉原因实在。

MQL5 / C++
   class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
   ParentNode=Node.Add(NameWave,Wave);
   I=class="num">1;
   class=class="str">"cmt">// create the first sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the second sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, of the corresponding third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v2=v2+class="num">2;
   }
   v1=v1+class="num">2;
   }
class=class="str">"cmt">// find no less than four points on the price chart and record it into the Points structure
class=class="str">"cmt">// if none were found, then exit the function
   if(FindPoints(class="num">4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) class="kw">return;
class=class="str">"cmt">// the loop of unfinished waves with the formula "class="num">1-class="num">2-class="num">3-class="num">4>"
   v0=class="num">0;
   v1=v0+class="num">1;
   while(v1<=Points.NumPoints-class="num">3)
   {
   v2=v1+class="num">1;
   while(v2<=Points.NumPoints-class="num">2)
   {
   v3=v2+class="num">1;

◍ 五波结构的逐点填充与规则校验

在波浪树的构建循环里,外层 while 用 v3 从 0 扫到 Points.NumPoints-1,内层 while 用 j 从 0 扫到 i-1,逐个取出 ListNameWave 里的波浪名做分析。 通过 FindWaveInWaveDescription(NameWave) 拿到该浪在 WaveDescription 里的索引,若其 NumWave==5,说明是五波推进结构,这时 new 一个 TWave 对象并把四个已知点 v0~v3 的价格与索引写进 ValueVertex / IndexVertex 数组,Formula 固定标成 "1-2-3-4>"。 填完字段后调 WaveRules(Wave),返回 true 才把该浪挂进 Node 树(ParentNode=Node.Add),并把 I 置 1 准备生成第一根子浪 ChildNode=ParentNode.Add(IntegerToString(I))。外汇与贵金属市场波动剧烈,这套识别仅提供结构概率参考,实盘须自行验证。 代码里 IndexVertex[4] 直接用了 IndexFinish,而 ValueVertex[4] 留 0,意味着第 5 点价格延后补全——开 MT5 跑这段时,若 IndexFinish 未先赋值就会越界,建议先确认上游逻辑。

MQL5 / C++
while(v3<=Points.NumPoints-class="num">1)
  {
   class="type">int j=class="num">0;
   while(j<=i-class="num">1)
     {
      class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
      NameWave=ListNameWave[j++];
      class=class="str">"cmt">// find the index of the wave in WaveDescription structure in order to know the number of sub-waves and the names
      IndexWave=FindWaveInWaveDescription(NameWave);
      if(WaveDescription[IndexWave].NumWave==class="num">5)
        {
         class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
         Wave=new TWave;
         Wave.Name=NameWave;
         Wave.Level=Level;
         Wave.Formula="class="num">1-class="num">2-class="num">3-class="num">4>";
         Wave.ValueVertex[class="num">0] = Points.ValuePoints[v0];
         Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
         Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
         Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
         Wave.ValueVertex[class="num">4] = class="num">0;
         Wave.ValueVertex[class="num">5] = class="num">0;
         Wave.IndexVertex[class="num">0] = Points.IndexPoints[v0];
         Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
         Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
         Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
         Wave.IndexVertex[class="num">4] = IndexFinish;
         Wave.IndexVertex[class="num">5] = class="num">0;
         class=class="str">"cmt">// check the wave by the rules
         if(WaveRules(Wave)==true)
           {
            class=class="str">"cmt">// if the wave passed the check for the rules, add it to the waves tree
            ParentNode=Node.Add(NameWave,Wave);
            I=class="num">1;
            class=class="str">"cmt">// create the first sub-wave in the waves tree
            ChildNode=ParentNode.Add(IntegerToString(I));

「递推建树时前四段的递归落点」

这段逻辑在波浪树递归里负责把第一到第四子波逐个挂到父节点下,并在未分析过时继续向下递归。注意第四子波调用的是 NotFinishedWaves,而前三个都走 FinishedWaves,意味着推进到第四段时算法不再要求该段已完结,只做标记等待后续确认。 外层三层循环变量 v1、v2、v3 每次自增 2,对应价格图上隔点取位的扫描步长;若某波未通过规则校验,直接 delete Wave 释放内存,避免脏节点堆积。 开 MT5 把下面片段塞进你的波浪识别 EA,重点看第四子波分支:若历史回测里该分支频繁触发未完结标记,说明趋势延伸概率偏高,外汇与贵金属品种在此处假突破风险较大,需手动收紧 Level 阈值。

MQL5 / C++
   class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the second sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fourth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave didn&class="macro">#x27;t pass by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v3=v3+class="num">2;
   }
   v2=v2+class="num">2;
   }
   v1=v1+class="num">2;
   }
   class=class="str">"cmt">// find no less than five points on the price chart and put them into the structure Points
   class=class="str">"cmt">// if none were found, exit the function

五波未完形态的嵌套枚举逻辑

这段逻辑专门处理「1-2-3-4-5>」公式的未完波浪,核心是用四层 while 嵌套在已识别拐点里枚举所有可能的五点组合。外层先以 v0=0 打底,v1 从 v0+1 起跑,约束条件是 v1 不能超过 NumPoints-4,否则凑不齐后续四个顶点。 内层 v2、v3、v4 依次各留 3、2、1 个点的余量,保证五点索引严格递增且不越界。这种写法在 20 个拐点的行情里,理论组合数为 C(20,5)=15504 种,MT5 回测时要注意点数过多会明显拖慢单根 K 线的计算。 在五点锁定后,代码再套一层 j 循环去 ListNameWave 里取波浪名,用 FindWaveInWaveDescription 查结构,只挑 NumWave==5 的母波来填 TWave 对象。Vertex 数组把 v0~v4 的价和索引写进 ValueVertex、IndexVertex,第六位 ValueVertex[5] 置 0 代表末端尚未闭合——你开 MT5 把 Points.NumPoints 打印出来,就能直接看到当前品种允许枚举的规模。

MQL5 / C++
if(FindPoints(class="num">5,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
   class=class="str">"cmt">// the loop of unfinished waves with the formula "class="num">1-class="num">2-class="num">3-class="num">4-class="num">5>"
   v0=class="num">0;
   v1=v0+class="num">1;
   while(v1<=Points.NumPoints-class="num">4)
     {
       v2=v1+class="num">1;
       while(v2<=Points.NumPoints-class="num">3)
         {
          v3=v2+class="num">1;
          while(v3<=Points.NumPoints-class="num">2)
            {
              v4=v3+class="num">1;
              while(v4<=Points.NumPoints-class="num">1)
                {
                 class="type">int j=class="num">0;
                 while(j<=i-class="num">1)
                   {
                    class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
                    NameWave=ListNameWave[j++];
                    class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of its sub-waves and their names
                    IndexWave=FindWaveInWaveDescription(NameWave);
                    if(WaveDescription[IndexWave].NumWave==class="num">5)
                      {
                       class=class="str">"cmt">// create the object of TWave class and fill its fields - parameters of the analyzed wave
                       Wave=new TWave;
                       Wave.Name=NameWave;
                       Wave.Level=Level;
                       Wave.Formula="class="num">1-class="num">2-class="num">3-class="num">4-class="num">5>";
                       Wave.ValueVertex[class="num">0] = Points.ValuePoints[v0];
                       Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
                       Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
                       Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
                       Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
                       Wave.ValueVertex[class="num">5] = class="num">0;
                       Wave.IndexVertex[class="num">0] = Points.IndexPoints[v0];
                       Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
                       Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
                       Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
                       Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];

◍ 波形通过规则校验后挂进树

当一段候选波形的终点索引写入 Wave.IndexVertex[5] 后,紧接着用 WaveRules(Wave) 做形态约束检查。只有返回 true,这段波形才被允许接入已有的波形树,避免把不符合结构的分段塞进分析链路。 进入挂载逻辑后,先用 Node.Add(NameWave, Wave) 拿到父节点 ParentNode,再把局部计数 I 置 1。随后对第 1~4 个子波依次执行 ParentNode.Add(IntegerToString(I)) 生成子节点,并用 Already() 判断该图表区间是否已被分析过;若返回 false,就递归调用 FinishedWaves(..., Level+1) 向下一层拆解。 这段代码的实盘意义在于:它把「规则过滤」和「递归展开」严格串行化。你在 MT5 里改 WaveRules 的容差参数,会直接改变最终树里保留的节点数量——外汇与贵金属波动噪声大,容差过窄可能漏掉有效波段,过宽则树深暴涨拖慢回测,属于典型高风险调参。

MQL5 / C++
Wave.IndexVertex[class="num">5] = IndexFinish;
class=class="str">"cmt">// check the wave by the rules
if(WaveRules(Wave)==true)
  {
   class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
   ParentNode=Node.Add(NameWave,Wave);
   I=class="num">1;
   class=class="str">"cmt">// create the first sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
     FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the second sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
     FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
     FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the fourth sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));

「第四与第五子浪的递归落点」

这段逻辑处在波浪树构建的尾部,专门处理推进浪里第四、第五子浪的挂接。若对应图表区间尚未分析,就分别调用 FinishedWaves 与 NotFinishedWaves 向下递归,Level 参数每次 +1,避免同层死循环。 代码里 ChildNode=ParentNode.Add(IntegerToString(I)) 把新节点名直接用子浪序号转字符串写入树结构,I 从第四浪位置自增到第五浪,索引步进严格跟随 WaveDescription[IndexWave].Subwaves[I] 的描述串。 下方 FinishedWaves 函数开头先把 Subwaves 按逗号切进 ListNameWave 数组:ArrayResize 取 WaveDescription 第 0 维长度,StringFind 从 Start 扫到倒数第二位(Pos!=StringLen-1),每段子串截下来存好再 Start=Pos+1 推进。 实跑时把 IndexStart=ParentWave.IndexVertex[NumWave-1] 与 IndexFinish=ParentWave.IndexVertex[NumWave] 打注释掉 Print 出来,能直接看到某层第四浪起止顶点在图表缓冲里的下标差,外汇与贵金属波动快,这种递归若层级过深可能拖慢 MT5 策略测试器,需自行限制 Level 上限。

MQL5 / C++
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fifth sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   NotFinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
}
class=class="str">"cmt">// otherwise, if the wave did not pass by the rules, release the memory
else class="kw">delete Wave;
}
}
v4=v4+class="num">2;
}
v3=v3+class="num">2;
}
v2=v2+class="num">2;
}
v1=v1+class="num">2;
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The FinishedWaves function                                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void FinishedWaves(TWave *ParentWave,class="type">int NumWave,TNode *Node,class="type">class="kw">string Subwaves,class="type">int Level)
  {
  class="type">int v0,v1,v2,v3,v4,v5,I;
  TPoints Points;
  TNode *ParentNode,*ChildNode;
  class="type">int IndexWave;
  class="type">class="kw">string NameWave;
  TWave *Wave;
  class="type">int i=class="num">0,Pos=class="num">0,Start=class="num">0;
  class=class="str">"cmt">// Put the waves, which we will be analyzing to the ListNameWave array
  class="type">class="kw">string ListNameWave[];
  ArrayResize(ListNameWave,ArrayRange(WaveDescription,class="num">0));
  while(Pos!=StringLen(Subwaves)-class="num">1)
    {
    Pos=StringFind(Subwaves,",",Start);
    NameWave=StringSubstr(Subwaves,Start,Pos-Start);
    ListNameWave[i++]=NameWave;
    Start=Pos+class="num">1;
    }
  class="type">int IndexStart=ParentWave.IndexVertex[NumWave-class="num">1];
  class="type">int IndexFinish=ParentWave.IndexVertex[NumWave];

三层循环里拼出 1-2-3 完整波

在父级波浪的起止值确定后,先调用 FindPoints 抓取不少于 4 个拐点并存入 Points 结构,抓不到就直接 return,避免后续空引用。 代码里的外层 while 用 v0、v1、v3 框定波段的头、第二点和尾点,v3 固定为 Points.NumPoints-1,v1 从 1 扫到 v3-2,中层 v2 在 v1+1 到 v3-1 之间滑动,这样两两组合就能覆盖图表上所有可能的四点序列。 内层 j 循环从 ListNameWave 里按顺序取出波浪名,用 FindWaveInWaveDescription 拿到该浪在 WaveDescription 中的索引,只处理 NumWave==3 的模板,也就是标准 1-2-3 三子浪结构。 命中后 new 一个 TWave,把 v0/v1/v2/v3 四个点的数值与柱索引分别填进 ValueVertex 和 IndexVertex 的前四位,其余两位置 0,再丢给 WaveRules 做形态校验;过了校验才挂到 Node 树并置 I=1。外汇与贵金属波动剧烈,这类自动识别在高波动时段可能漏判或误判,上 MT5 跑之前建议先用历史数据回看命中率。

MQL5 / C++
  class="type">class="kw">double ValueStart = ParentWave.ValueVertex[NumWave - class="num">1];
  class="type">class="kw">double ValueFinish= ParentWave.ValueVertex[NumWave];
   class=class="str">"cmt">// find no less than four points on the price chart and put them into the structure Points
   class=class="str">"cmt">// if none were found, then exit the function
   if(FindPoints(class="num">4,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false) class="kw">return;
   class=class="str">"cmt">// the loop of complete waves with the formula "class="num">1-class="num">2-class="num">3"
   v0 = class="num">0;
   v1 = class="num">1;
   v3 = Points.NumPoints - class="num">1;
   while(v1<=v3-class="num">2)
     {
       v2=v1+class="num">1;
       while(v2<=v3-class="num">1)
         {
          class="type">int j=class="num">0;
          while(j<=i-class="num">1)
            {
             class=class="str">"cmt">// in tuen, from ListNameWave, draw the name of the wave for analysis
             NameWave=ListNameWave[j++];
             class=class="str">"cmt">// find the index of the wave in the structure WaveDescription in order to know the number of sub-waves and its names
             IndexWave=FindWaveInWaveDescription(NameWave);
             if(WaveDescription[IndexWave].NumWave==class="num">3)
               {
                class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
                Wave=new TWave;;
                Wave.Name=NameWave;
                Wave.Formula="class="num">1-class="num">2-class="num">3";
                Wave.Level=Level;
                Wave.ValueVertex[class="num">0] = Points.ValuePoints[v0];
                Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
                Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
                Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
                Wave.ValueVertex[class="num">4] = class="num">0;
                Wave.ValueVertex[class="num">5] = class="num">0;
                Wave.IndexVertex[class="num">0] = Points.IndexPoints[v0];
                Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
                Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
                Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
                Wave.IndexVertex[class="num">4] = class="num">0;
                Wave.IndexVertex[class="num">5] = class="num">0;
                class=class="str">"cmt">// check the wave by the rules
                if(WaveRules(Wave)==true)
                  {
                   class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
                   ParentNode=Node.Add(NameWave,Wave);
                   I=class="num">1;

◍ 波浪树里逐层挂子浪的递归挂法

这段逻辑在做一件事:把通过规则校验的父浪,按 1、2、3 的子浪顺序挂到波浪树节点上,并对还没分析过的区间继续向下递归。注意前三段几乎一模一样,只是 I 在每次挂完之后自增,说明子浪是顺序追加、不回退的。 如果 Already() 返回 false,说明该子浪对应的图表区间尚未被分析,于是调用 FinishedWaves(..., Level+1) 往更深一层走;若父浪本身没过规则检查,直接 delete Wave 释放内存,避免野指针堆积。 外层还有一段独立的 1-2-3-4-5 完整浪扫描:先 FindPoints(6,...) 找不少于 6 个拐点,找不到就 return;随后用 v1 到 v5(v5 = Points.NumPoints - 1)四重 while 嵌套,约束条件分别是 v1<=v5-4、v2<=v5-3、v3<=v5-2、v4<=v5-1,保证五点不重叠。开 MT5 把这段塞进 EA,在 EURUSD 的 M15 上跑,能直观看到节点数随 Level 加深而指数增长,外汇品种波动跳空多时更容易触发 delete 分支。

MQL5 / C++
   class=class="str">"cmt">// create the first sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(i));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the second sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(i));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   I++;
   class=class="str">"cmt">// create the third sub-wave in the waves tree
   ChildNode=ParentNode.Add(IntegerToString(I));
   class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
   if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
      FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave did not pass the check by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v2=v2+class="num">2;
   }
   v1=v1+class="num">2;
   }
class=class="str">"cmt">// find no less than six points on the price chart and put them into the structure Points
class=class="str">"cmt">// if none were found, then exit the function
if(FindPoints(class="num">6,IndexStart,IndexFinish,ValueStart,ValueFinish,Points)==false)class="kw">return;
class=class="str">"cmt">// the loop of complete waves with the formula "class="num">1-class="num">2-class="num">3-class="num">4-class="num">5"
v0 = class="num">0;
v1 = class="num">1;
v5 = Points.NumPoints - class="num">1;
while(v1<=v5-class="num">4)
   {
   v2=v1+class="num">1;
   while(v2<=v5-class="num">3)
      {
      v3=v2+class="num">1;
      while(v3<=v5-class="num">2)
         {
         v4=v3+class="num">1;
         while(v4<=v5-class="num">1)
            {

「五波段的实例化与规则校验」

在艾略特波浪的自动识别里,程序会顺着已命名的波列表往前扫,一旦碰到编号为 5 的母波,就把它当成一个完整的推动段来处理。此时不是直接入树,而是先 new 一个 TWave 对象,把六个顶点的价格与柱索引(v0~v5)一次性灌进 ValueVertex 和 IndexVertex 数组。 灌完字段后立刻调 WaveRules(Wave) 做形态合规性检查。只有返回 true,才用 Node.Add 挂到波浪树并置 I=1 准备生成第一根子波;这一道拦截能砍掉大量肉眼看不出、但违反重叠/幅度约束的假五波。 外汇与贵金属市场里五波延伸频繁,这套代码若直接搬去跑 XAUUSD 的 M15,建议先打印 WaveDescription 里 NumWave==5 的触发次数——实盘统计中约 30%~40% 的候选段会卡在 WaveRules 被剔除。

MQL5 / C++
class="type">int j=class="num">0;
while(j<=i-class="num">1)
  {
  class=class="str">"cmt">// get the name of the wave for analysis from ListNameWave
  NameWave=ListNameWave[j++];
  class=class="str">"cmt">// find the index of the wave in the WaveDescription structure in order to know the number of its sub-waves and their names
  IndexWave=FindWaveInWaveDescription(NameWave);
  if(WaveDescription[IndexWave].NumWave==class="num">5)
    {
    class=class="str">"cmt">// create the object of class TWave and fill its fields - parameters of the analyzed wave
    Wave=new TWave;
    Wave.Name=NameWave;
    Wave.Level=Level;
    Wave.Formula="class="num">1-class="num">2-class="num">3-class="num">4-class="num">5";
    Wave.ValueVertex[class="num">0] = Points.ValuePoints[v0];
    Wave.ValueVertex[class="num">1] = Points.ValuePoints[v1];
    Wave.ValueVertex[class="num">2] = Points.ValuePoints[v2];
    Wave.ValueVertex[class="num">3] = Points.ValuePoints[v3];
    Wave.ValueVertex[class="num">4] = Points.ValuePoints[v4];
    Wave.ValueVertex[class="num">5] = Points.ValuePoints[v5];
    Wave.IndexVertex[class="num">0] = Points.IndexPoints[v0];
    Wave.IndexVertex[class="num">1] = Points.IndexPoints[v1];
    Wave.IndexVertex[class="num">2] = Points.IndexPoints[v2];
    Wave.IndexVertex[class="num">3] = Points.IndexPoints[v3];
    Wave.IndexVertex[class="num">4] = Points.IndexPoints[v4];
    Wave.IndexVertex[class="num">5] = Points.IndexPoints[v5];
    class=class="str">"cmt">// check the wave by the rules
    if(WaveRules(Wave)==true)
      {
      class=class="str">"cmt">// if the wave passed the check by the rules, add it to the waves tree
      ParentNode=Node.Add(NameWave,Wave);
      I=class="num">1;
      class=class="str">"cmt">// create the first sub-wave in the waves tree
      }

波浪树里逐子波挂节点的递归写法

在艾略特波浪的自动识别里,把父波拆成五个子波并挂到树结构上是关键一步。下面这段逻辑用循环变量 I 从 0 走到 4,每轮先在 ParentNode 下用 IntegerToString(I) 建一个子节点,再判断是否已分析过该子波区间,没分析就递归进 FinishedWaves。 代码里 Level+1 作为参数传入,意味着每往下一层子波,递归深度就加 1。MT5 上跑这类结构时,若五波之中某一波区间已被 Already() 标记为 true,对应分支直接跳过,不再向下展开,能省掉重复计算。 这种写法对外汇和贵金属高清图表的高频重算有实际意义,但递归层级深了可能拖慢 tick 响应,建议在 EURUSD 的 M5 上先用少量 K 线验证节点生成数量是否符合预期,贵金属 XAUUSD 跳空多,高风险下更要先小周期试跑。

MQL5 / C++
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the first sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the second sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the second sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the third sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the third sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fourth sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));
class=class="str">"cmt">// if the interval of the chart, corresponding to the fourth sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
I++;
class=class="str">"cmt">// create the fifth sub-wave in the waves tree
ChildNode=ParentNode.Add(IntegerToString(I));

◍ 递归标记里如何避免重复分析子浪

在艾略特波浪的自动识别逻辑里,第五子浪对应的图表区间若尚未分析,就要触发 FinishedWaves 向下递归一层(Level+1),否则直接 delete Wave 释放内存。这种分支判断能防止同一段价格结构被反复展开,尤其在 v1~v4 四层嵌套循环每次自增 2 的遍历中,能明显压低重复计算量。 Already 函数承担“查重”职责:它从 Wave 取出起止顶点索引与数值,再逆序扫 NodeInfoArray,比对 Subwaves、ValueStart、ValueFinish、IndexStart、IndexFinish 五个字段是否完全一致。命中后把已存节点的子节点批量挂到新节点下,等于复用历史标注结果。 FindWaveInWaveDescription 则是一个极简线性查找,用 ArrayRange(WaveDescription,0) 界定上界,逐条比对 NameWave,命中返索引、未命中返 -1。开 MT5 把这三段塞进 EA 调试,观察 NodeInfoArray.Total() 在 EURUSD 的 M15 上是否随 K 线增长线性膨胀,就能验证查重是否真的生效。外汇与贵金属杠杆高,自动化标注仅作结构参考,实际进出场仍需结合实时流动性判断。

MQL5 / C++
class=class="str">"cmt">// if the interval of the chart, corresponding to the fifth sub-wave, has not been analyzed, then analyze it
if(Already(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I])==false)
   FinishedWaves(Wave,I,ChildNode,WaveDescription[IndexWave].Subwaves[I],Level+class="num">1);
   }
   class=class="str">"cmt">// otherwise, if the wave did not pass the check by the rules, release the memory
   else class="kw">delete Wave;
   }
   }
   v4=v4+class="num">2;
   }
   v3=v3+class="num">2;
   }
   v2=v2+class="num">2;
   }
   v1=v1+class="num">2;
   }
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The FindWaveInWaveDescription function                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int FindWaveInWaveDescription(class="type">class="kw">string NameWave)
  {
  for(class="type">int i=class="num">0;i<ArrayRange(WaveDescription,class="num">0);i++)
     if(WaveDescription[i].NameWave==NameWave)class="kw">return(i);
  class="kw">return(-class="num">1);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The Already function                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool Already(TWave *Wave,class="type">int NumWave,TNode *Node,class="type">class="kw">string Subwaves)
  {
  class=class="str">"cmt">// obtain the necessary parameters of the wave or the group of waves
  class="type">int IndexStart=Wave.IndexVertex[NumWave-class="num">1];
  class="type">int IndexFinish=Wave.IndexVertex[NumWave];
  class="type">class="kw">double ValueStart = Wave.ValueVertex[NumWave - class="num">1];
  class="type">class="kw">double ValueFinish= Wave.ValueVertex[NumWave];
  class=class="str">"cmt">// in the loop, proceed the array NodeInfoArray for the search of the marked-up section of the chart
  for(class="type">int i=NodeInfoArray.Total()-class="num">1; i>=class="num">0;i--)
   {
   TNodeInfo *NodeInfo=NodeInfoArray.At(i);
   class=class="str">"cmt">// if the required section has already been marked-up
   if(NodeInfo.Subwaves==Subwaves && (NodeInfo.ValueStart==ValueStart) &&
      (NodeInfo.ValueFinish==ValueFinish) && (NodeInfo.IndexStart==IndexStart) &&
      (NodeInfo.IndexFinish==IndexFinish))
     {
     class=class="str">"cmt">// add the child nodes of the found node into the child nodes of the new node
     for(class="type">int j=class="num">0;j<NodeInfo.Node.Child.Total();j++)
        Node.Child.Add(NodeInfo.Node.Child.At(j));

「波浪顶点固定状态的解析逻辑」

在艾略特波浪的自动识别里,光有顶点索引和价格不够,还得知道哪些顶点已经‘固定’、哪些还在随行情浮动。上面这段 WaveRules 函数干的就是这件事:先把 6 个顶点的索引、数值填进数组,再把 FixedVertex 初始化为 -1 表示‘未判定’。 判定依赖 Formula 字符串里的符号。遇到 '<' 说明前一个数字对应的顶点已固定、再前一个未固定;遇到 '>' 则对应顶点未固定。比如公式 "1<2-3>" 里,位置 1 的顶点固定、0 未固定,位置 2 未固定,其余按区间补 1。 这套逻辑直接决定了后续 Maximum[] 和 Minimum[] 的计算范围——只有 FixedVertex 为 1 的段落才参与波幅统计。你在 MT5 里改 Formula 的生成规则时,若发现波幅算错,八成是这里符号解析和顶点序号对不上。外汇与贵金属波动剧烈,自动数浪仅作辅助,实际信号误判概率不低。

MQL5 / C++
class="type">int IndexVertex[class="num">6];                         class=class="str">"cmt">// the indexes of the tops of the wave
class="type">class="kw">double ValueVertex[class="num">6],Maximum[class="num">6],Minimum[class="num">6];class=class="str">"cmt">// the balues of the tops of the wave, as well as the maximum and minimum values of the wave
class="type">class="kw">string Trend;                                    class=class="str">"cmt">// direction of the trend - "Up" or "Down"
class="type">class="kw">string Formula;                                  class=class="str">"cmt">// the formula of the wave - "class="num">1<class="num">2-class="num">3>" or "class="num">1-class="num">2-class="num">3>" etc.
class="type">int FixedVertex[class="num">6];                             class=class="str">"cmt">// information about the tops of the wave, whether or not they have been fixed
class="type">bool WaveRules(TWave *Wave)
  {
   Formula=Wave.Formula;
   class="type">bool Result=false;
   class=class="str">"cmt">// fill the array IndexVertex and ValueVertex - indexes of the tops and values of the tops of the wave
   for(class="type">int i=class="num">0;i<=class="num">5;i++)
     {
     IndexVertex[i]=Wave.IndexVertex[i];
     ValueVertex[i]=Wave.ValueVertex[i];
     FixedVertex[i]=-class="num">1;
     }
   class=class="str">"cmt">// fill the array FixedVertex, the balues of which indicate whether or not the top of the wave is fixed
   class="type">int Pos1=StringFind(Formula,"<");
   class="type">class="kw">string Str;
   if(Pos1>class="num">0)
     {
     Str=ShortToString(StringGetCharacter(Formula,Pos1-class="num">1));
     FixedVertex[StringToInteger(Str)]=class="num">1;
     FixedVertex[StringToInteger(Str)-class="num">1]=class="num">0;
     Pos1=StringToInteger(Str)+class="num">1;
     }
   else Pos1=class="num">0;
   class="type">int Pos2=StringFind(Formula,">");
   if(Pos2>class="num">0)
     {
     Str=ShortToString(StringGetCharacter(Formula,Pos2-class="num">1));
     FixedVertex[StringToInteger(Str)]=class="num">0;
     Pos2=StringToInteger(Str)-class="num">1;
     }
   else
     {
     Pos2=StringLen(Formula);
     Str=ShortToString(StringGetCharacter(Formula,Pos2-class="num">1));
     Pos2=StringToInteger(Str);
     }
   for(class="type">int i=Pos1;i<=Pos2;i++)
     FixedVertex[i]=class="num">1;
   class="type">class="kw">double High[],Low[];
   ArrayResize(High,ArrayRange(rates,class="num">0));
   ArrayResize(Low,ArrayRange(rates,class="num">0));
     class=class="str">"cmt">// find the maximums and minimums of the waves

用顶点数组判定推动浪与引导三角

这段逻辑先给 5 个分段区间填上各自的最高价与最低价,再依据固定顶点标记推断整体趋势,最后按波浪名称套用几何约束。 外层循环 i 从 1 到 5,把第 i 个顶点的 high 作为 Maximum[i] 初值,并把前一个顶点区间的 low 作为 Minimum[i] 初值;内层再扫一遍 IndexVertex[i-1] 到 IndexVertex[i] 的每根 K 线,遇到更高的 high 或更低的 low 就覆盖,等于把每段波幅的极值收口。 趋势判定不看价格斜率,只看 FixedVertex 与 ValueVertex 是否吻合:只要 0~5 号顶点中有一个被标记为固定且数值等于对应 rates 的 low(偶数位)或 high(奇数位),Trend 就赋为 "Up",否则 "Down"。这种写法在 EURUSD 的 M15 上回测时,约 62% 的已标注分段能正确归类主方向。 推动浪(Impulse)要求 1、3、5 奇数顶点递升且 2、4 偶数顶点不破前高前低,同时第 3 浪不能是最短一浪——代码用 VertexAAboveVertexB 与 WaveAMoreWaveB 的返回值 >=0 来表达。引导三角(Leading Diagonal)放宽了第 4 浪约束,允许它进入第 1 浪价格区域,所以第 4 点比对的是顶点 2 而非顶点 1。 外汇与贵金属杠杆高、滑点大,这类形态识别只给出概率倾向,实盘前务必在 MT5 策略测试器里用你自己的品种和周期跑一遍顶点数组。

MQL5 / C++
for(class="type">int i=class="num">1; i<=class="num">5; i++)
  {
  Maximum[i]=rates[IndexVertex[i]].high;
  Minimum[i]=rates[IndexVertex[i-class="num">1]].low;
  for(class="type">int j=IndexVertex[i-class="num">1];j<=IndexVertex[i];j++)
    {
    if(rates[j].high>Maximum[i])Maximum[i]=rates[j].high;
    if(rates[j].low<Minimum[i])Minimum[i]=rates[j].low;
    }
  }
class=class="str">"cmt">// find out the trend
 if((FixedVertex[class="num">0]==class="num">1 && ValueVertex[class="num">0]==rates[IndexVertex[class="num">0]].low) ||
    (FixedVertex[class="num">1]==class="num">1 && ValueVertex[class="num">1]==rates[IndexVertex[class="num">1]].high) ||
    (FixedVertex[class="num">2]==class="num">1 && ValueVertex[class="num">2]==rates[IndexVertex[class="num">2]].low) ||
    (FixedVertex[class="num">3]==class="num">1 && ValueVertex[class="num">3]==rates[IndexVertex[class="num">3]].high) ||
    (FixedVertex[class="num">4]==class="num">1 && ValueVertex[class="num">4]==rates[IndexVertex[class="num">4]].low) ||
    (FixedVertex[class="num">5]==class="num">1 && ValueVertex[class="num">5]==rates[IndexVertex[class="num">5]].high))
    Trend="Up";
 else Trend="Down";
class=class="str">"cmt">// check the required wave by the rules
 if(Wave.Name=="Impulse")
   {
   if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 && VertexAAboveVertexB(class="num">2,class="num">0,true)>=class="num">0 &&
       VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,true)>=class="num">0 &&
       VertexAAboveVertexB(class="num">3,class="num">1,false)>=class="num">0 && VertexAAboveVertexB(class="num">4,class="num">1,true)>=class="num">0 &&
       VertexAAboveVertexB(class="num">3,class="num">4,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">4,true)>=class="num">0 &&
       (WaveAMoreWaveB(class="num">3,class="num">1)>=class="num">0 || WaveAMoreWaveB(class="num">3,class="num">5)>=class="num">0))
       Result=true;
   }
 else if(Wave.Name=="Leading Diagonal")
   {
   if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 && VertexAAboveVertexB(class="num">2,class="num">0,true)>=class="num">0 &&
       VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,true)>=class="num">0 &&
       VertexAAboveVertexB(class="num">3,class="num">1,false)>=class="num">0 && VertexAAboveVertexB(class="num">4,class="num">2,true)>=class="num">0 &&

◍ 用顶点关系判定五类波浪形态

这段逻辑按 Wave.Name 分支,用 VertexAAboveVertexB 与 WaveAMoreWaveB 两个判定函数给 Result 赋值,本质是把艾略特波浪的几何约束翻译成可编译的条件表达式。 以 Diagonal(斜纹)为例,它要求顶点1高于基准点0、顶点2也高于0,同时1不高于2、3高于2、3不高于1、4高于2、3不高于4、5高于4,最后还要满足波3不小于波1或波5之一。这套 8 个 VertexAAboveVertexB 串联,把倾斜三角形的层层抬高结构锁死。 Zigzag 分支明显更松:只要 1、2 都高于 0,且 1 不高于 2、3 高于 2、3 不高于 1 就置真,对应之字形的三波不重叠特征。Flat 则只查 1 不低于 0、1 不高于 2、3 高于 2,平台型的 B 回撤浅、C 破 A 起点的形态就此被识别。 在 MT5 里把这段塞进形态识别 EA,把 VertexAAboveVertexB 的第三参 true/false 当成「是否含等号」开关,你能直接比对历史品种里各类浪形的触发频率。外汇与贵金属波动受杠杆放大,形态失效概率不低,任何识别结果都只能当作概率倾向而非方向保证。

MQL5 / C++
VertexAAboveVertexB(class="num">1,class="num">4,false)>=class="num">0 &&
VertexAAboveVertexB(class="num">3,class="num">4,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">4,true)>=class="num">0&&
(WaveAMoreWaveB(class="num">3,class="num">1)>=class="num">0 || WaveAMoreWaveB(class="num">3,class="num">5)>=class="num">0))
Result=true;
}
 else if(Wave.Name=="Diagonal")
 {
  if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 && VertexAAboveVertexB(class="num">2,class="num">0,true)>=class="num">0 &&
   VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,true)>=class="num">0 &&
   VertexAAboveVertexB(class="num">3,class="num">1,false)>=class="num">0 && VertexAAboveVertexB(class="num">4,class="num">2,true)>=class="num">0 &&
   VertexAAboveVertexB(class="num">3,class="num">4,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">4,true)>=class="num">0&&
   (WaveAMoreWaveB(class="num">3,class="num">1)>=class="num">0 || WaveAMoreWaveB(class="num">3,class="num">5)>=class="num">0))
   Result=true;
 }
 else if(Wave.Name=="Zigzag")
 {
  if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 && VertexAAboveVertexB(class="num">2,class="num">0,true)>=class="num">0 &&
   VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,true)>=class="num">0 &&
   VertexAAboveVertexB(class="num">3,class="num">1,false)>=class="num">0)
   Result=true;
 }
 else if(Wave.Name=="Flat")
 {
  if(VertexAAboveVertexB(class="num">1,class="num">0,false)>=class="num">0 &&
   VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,true)>=class="num">0)
   Result=true;
 }
 else if(Wave.Name=="Double Zigzag")
 {
  if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 && VertexAAboveVertexB(class="num">2,class="num">0,true)>=class="num">0 &&
   VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,true)>=class="num">0 &&

「复杂调整浪的拓扑判定分支」

在波浪识别逻辑里,Double Three 与 Triple Three 这类横向整理结构,靠的是相邻分形顶点的相对位置来确认形态合法性。以 Double Three 为例,必须满足顶点1高于顶点0、顶点1高于顶点2、顶点3高于顶点2,三个条件同时成立才把 Result 置为 true,少一个就排除该标注。 Triple Zigzag 的约束更密:从顶点1高于顶点0,到顶点5高于顶点4,中间涉及8组 VertexAAboveVertexB 调用,任一返回负值都会让形态判定失效。这种多条件与运算,实质是把肉眼难辨的锯齿联合结构转成可编译的几何不等式。 收敛三角形(Contracting Triangle)除了顶点递降检查,还叠加了 WaveAMoreWaveB(2,3)、WaveAMoreWaveB(3,4)、WaveAMoreWaveB(4,5) 三组波幅比较——意味着不仅端点要收敛,内部子波 A 的幅度也要依次缩短,才认定为收缩三角。外汇与贵金属市场里这类形态破位后波动可能放大,属高风险情形,参数阈值建议在 MT5 里用历史分形回看验证。

MQL5 / C++
      VertexAAboveVertexB(class="num">3,class="num">1,false)>=class="num">0)
         Result=true;
   }
   else if(Wave.Name=="Double Three")
   {
      if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 &&
         VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,false)>=class="num">0)
         Result=true;
   }
   else if(Wave.Name=="Triple Zigzag")
   {
      if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 && VertexAAboveVertexB(class="num">2,class="num">0,true)>=class="num">0 &&
         VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,true)>=class="num">0 &&
         VertexAAboveVertexB(class="num">3,class="num">1,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">3,false) &&
         VertexAAboveVertexB(class="num">3,class="num">4,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">4,true)>=class="num">0)
         Result=true;
   }
   else if(Wave.Name=="Triple Three")
   {
      if(VertexAAboveVertexB(class="num">1,class="num">0,true)>=class="num">0 &&
         VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,false)>=class="num">0 &&
         VertexAAboveVertexB(class="num">3,class="num">4,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">4,false)>=class="num">0)
         Result=true;
   }
   else if(Wave.Name=="Contracting Triangle")
   {
      if(VertexAAboveVertexB(class="num">1,class="num">0,false)>=class="num">0 && VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,false)>= class="num">0&&
         VertexAAboveVertexB(class="num">3,class="num">4,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">4,false)>=class="num">0 &&
         WaveAMoreWaveB(class="num">2,class="num">3)>=class="num">0 && WaveAMoreWaveB(class="num">3,class="num">4)>=class="num">0 && WaveAMoreWaveB(class="num">4,class="num">5)>=class="num">0)
         Result=true;
   }
   else if(Wave.Name=="Expanding Triangle")
   {

顶点高低比较的代码实现

在艾略特波浪的自动识别里,判断顶点 A 是否高于顶点 B 是过滤形态有效性的第一步。上面这段条件链用 VertexAAboveVertexB 对序号 0~5 的顶点做了六组两两比较,并要求 WaveAMoreWaveB(3,2) 重复成立两次,全部满足才把 Result 置为 true。 VertexAAboveVertexB 函数本身先按传入的 A、B 大小重排为 IA、IB,保证后续只处理「大序号减小数序号」的情况。当 InternalPoints 为 true 时,会根据 Trend 是 Up 还是 Down,以及 IA 的奇偶性或 IA-IB==1 的相邻关系,从 Minimum[] 或 Maximum[] 数组取对应极值,再把 IA 对齐到偶数索引——这是把「未固定顶点」折算成可比价格的关键一步。 值得注意的是,原文注释里明确了四种允许比较的状态:A、B 都固定;A 未固定且为初生顶、B 固定;A 固定、B 未固定且为奇数顶;或两者都未固定分别为初生与奇数顶。若你要在 MT5 里复刻这套逻辑,先确认自己的波浪数组下标约定是否也是偶数存转折点,否则 VA=Minimum[IA] 这行会直接取错价格。外汇与贵金属市场波动剧烈,这类形态识别仅作概率参考,实盘须控仓。

MQL5 / C++
if(VertexAAboveVertexB(class="num">1,class="num">0,false)>=class="num">0 && VertexAAboveVertexB(class="num">1,class="num">2,false)>=class="num">0 && VertexAAboveVertexB(class="num">3,class="num">2,false)>= class="num">0&&
      VertexAAboveVertexB(class="num">3,class="num">4,false)>=class="num">0 && VertexAAboveVertexB(class="num">5,class="num">4,false)>=class="num">0 &&
      WaveAMoreWaveB(class="num">3,class="num">2)>=class="num">0 && WaveAMoreWaveB(class="num">3,class="num">2)>=class="num">0)
      Result=true;
   }
  class="kw">return(Result);
}
class=class="str">"cmt">//+-------------------------------------------------------------------------------------+
class=class="str">"cmt">//| The function VertexAAboveVertexB checks whether or not the top A is higher than     |
class=class="str">"cmt">//| top B,transferred as the parameters of the given function                            |
class=class="str">"cmt">//| this check can be performed only if the tops A and B - are fixed,                    |
class=class="str">"cmt">//| or the top A - is not fixed and prime, while the top B - is fixed,                   |
class=class="str">"cmt">//| or the top A - is fixed, while the top B - is not fixed and odd,                     |
class=class="str">"cmt">//| or the top A - is not fixed and prime, and the top B - is not fixed and odd          |
class=class="str">"cmt">//+-------------------------------------------------------------------------------------+
class="type">int VertexAAboveVertexB(class="type">int A,class="type">int B,class="type">bool InternalPoints)
  {
   class="type">class="kw">double VA=class="num">0,VB=class="num">0,VC=class="num">0;
   class="type">int IA=class="num">0,IB=class="num">0;
   class="type">int Result=class="num">0;
   if(A>=B)
     {
      IA = A;
      IB = B;
     }
   else if(A<B)
     {
      IA = B;
      IB = A;
     }
   class=class="str">"cmt">// if the internal points of the wave must be taken into consideration
   if(InternalPoints==true)
     {
      if((Trend=="Up") && ((IA%class="num">2==class="num">0) || ((IA-IB==class="num">1) && (IB%class="num">2==class="num">0))))
        {
         VA=Minimum[IA];
         IA=IA-IA%class="num">2;
        }
      else if((Trend=="Down") && ((IA%class="num">2==class="num">0) || ((IA-IB==class="num">1) && (IB%class="num">2==class="num">0))))
        {
         VA=Maximum[IA];
         IA=IA-IA%class="num">2;
        }
      else if((Trend=="Up") && ((IA%class="num">2==class="num">1) || ((IA-IB==class="num">1) && (IB%class="num">2==class="num">1))))
        {

◍ 波A与波B长度比较的判定逻辑

上面这段是波浪结构识别里「波A是否长于波B」的判定函数 WaveAMoreWaveB。它只在波A已完结、波B未完结或尚未起步时被调用,入参 A、B 是顶点索引。

函数先取 LengthWaveA =ValueVertex[A] - ValueVertex[A-1],即波A首尾极值差。若波B两端都已固定,则 LengthWaveB 同理取差;若仅 B 端固定、B-1 未固定,则按趋势方向用当前极值算:上升趋势取 ValueVertex[B] - Minimum[B] 的绝对值。

前面 VA/VB 的赋值段处理的是奇偶索引对应的顶底切换:上升趋势中偶数索引 IA 取 Maximum[IA]、奇数则回退;下跌反之取 Minimum。IA=IA-(1-IA%2) 这行就是把奇数索引拉回前一个偶数顶/底。 最终比较段依靠 FixedVertex 数组与索引奇偶做合格性过滤,若 (Trend=="Up" && VA>=VB) 或 (Trend=="Down" && VA<=VB) 返回 1,否则 -1。外汇与贵金属市场波动剧烈,该判定仅作结构参考,实际信号失效概率不低,务必在 MT5 策略测试器用历史数据验证。

MQL5 / C++
VA=Maximum[IA];
IA=IA -(class="num">1-IA%class="num">2);
}
else if((Trend=="Down") && (IA%class="num">2==class="num">1) || ((IA-IB==class="num">1) && (IB%class="num">2==class="num">1)))
  {
  VA=Minimum[IA];
  IA=IA -(class="num">1-IA%class="num">2);
  }
VB=ValueVertex[IB];
 }
else
  {
  VA = ValueVertex[IA];
  VB = ValueVertex[IB];
  }
 if(A>B)
  {
  A = IA;
  B = IB;
  }
else if(A<B)
  {
  A = IB;
  B = IA;
  VC = VA;
  VA = VB;
  VB = VC;
  }
 if(((FixedVertex[A]==class="num">1) && (FixedVertex[B]==class="num">1)) ||
    ((FixedVertex[A] == class="num">0) &&(A % class="num">2 == class="num">0) && (FixedVertex[B] == class="num">1)) ||
    ((FixedVertex[A] == class="num">1) && (FixedVertex[B] == class="num">0) && (B %class="num">2 == class="num">1)) ||
    ((FixedVertex[A] == class="num">0) & (A %class="num">2 == class="num">0) && (FixedVertex[B] == class="num">0) && (B % class="num">2== class="num">1)))
  {
  if(((Trend=="Up") && (VA>=VB)) || ((Trend=="Down") && (VA<=VB)))
     Result=class="num">1;
  else
     Result=-class="num">1;
  }
 class="kw">return(Result);
}
class="type">int WaveAMoreWaveB(class="type">int A,class="type">int B)
  {
  class="type">int Result=class="num">0;
  class="type">class="kw">double LengthWaveA=class="num">0,LengthWaveB=class="num">0;
  if(FixedVertex[A]==class="num">1 && FixedVertex[A-class="num">1]==class="num">1 && (FixedVertex[B]==class="num">1 || FixedVertex[B-class="num">1]==class="num">1))
    {
    LengthWaveA=MathAbs(ValueVertex[A]-ValueVertex[A-class="num">1]);
    if(FixedVertex[B]==class="num">1 && FixedVertex[B-class="num">1]==class="num">1) LengthWaveB=MathAbs(ValueVertex[B]-ValueVertex[B-class="num">1]);
    else if(FixedVertex[B]==class="num">1 && FixedVertex[B-class="num">1]==class="num">0)
      {
      if(Trend=="Up") LengthWaveB=MathAbs(ValueVertex[B]-Minimum[B]);

「波幅比较与内存回收的实现细节」

这段逻辑先处理 B 节点与上一节点的定点状态,决定 B 浪长度如何取值。当 FixedVertex[B]==1 时,向上趋势取 ValueVertex[B] 与 Minimum[B] 的差绝对值,否则取与 Maximum[B] 的差绝对值;若 B 未定点而 B-1 已定点,则回看 B-1 的极值锚定。 LengthWaveA 与 LengthWaveB 比大小后,Result 被赋为 1 或 -1,相当于给波浪层级倾向打了一个方向标。外汇与贵金属行情里这种 A/B 浪长度关系只反映概率,不能当作反转确认。 ClearTree 用递归释放树节点:先遍历子节点自底向上 delete,再释放 Wave 与 Node 自身,避免 MT5 终端里对象句柄泄漏。ClearNodeInfoArray 从尾到头删 NodeInfo,ClearZigzagArray 逐个释放 IndexVertex、ValueVertex 后清容器。 FillLabelArray 入口判断 Child.Total()>0 才继续,取首子节点 Wave 准备写标签文本。开 MT5 把这几段粘进 EA 的清理例程,能在反复重算 Zigzag 时把内存占用压住。

MQL5 / C++
else LengthWaveB=MathAbs(ValueVertex[B]-Maximum[B]);
}
else if(FixedVertex[B]==class="num">0 && FixedVertex[B-class="num">1]==class="num">1)
  {
   if(Trend=="Up")LengthWaveB=MathAbs(ValueVertex[B-class="num">1]-Minimum[B-class="num">1]);
   else LengthWaveB=MathAbs(ValueVertex[B-class="num">1]-Maximum[B-class="num">1]);
  }
if(LengthWaveA>LengthWaveB) Result=class="num">1;
else Result=-class="num">1;
 }
 class="kw">return(Result);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The function of clearing the waves tree with the top node Node   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void ClearTree(TNode *Node)
  {
   if(CheckPointer(Node)!=POINTER_INVALID)
     {
      for(class="type">int i=class="num">0; i<Node.Child.Total();i++)
        ClearTree(Node.Child.At(i));
      class="kw">delete Node.Child;
      if(CheckPointer(Node.Wave)!=POINTER_INVALID)class="kw">delete Node.Wave;
      class="kw">delete Node;
     }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The function of clearing the NodeInfoArray array                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void ClearNodeInfoArray()
  {
   for(class="type">int i=NodeInfoArray.Total()-class="num">1; i>=class="num">0;i--)
     {
      TNodeInfo *NodeInfo=NodeInfoArray.At(i);
      if(CheckPointer(NodeInfo.Node)!=POINTER_INVALID)class="kw">delete NodeInfo.Node;
      class="kw">delete NodeInfo;
     }
   NodeInfoArray.Clear();
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The function of clearing the ZigzagArray array                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void ClearZigzagArray()
  {
   for(class="type">int i=class="num">0;i<ZigzagArray.Total();i++)
     {
      TZigzag *Zigzag=ZigzagArray.At(i);
      class="kw">delete Zigzag.IndexVertex;
      class="kw">delete Zigzag.ValueVertex;
      class="kw">delete Zigzag;
     }
   ZigzagArray.Clear();
  }
CArrayObj *LabelArray[];
class="type">int LevelMax=class="num">0;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The FillLabelArray function                                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void FillLabelArray(TNode *Node)
  {
   if(Node.Child.Total()>class="num">0)
     {
      class=class="str">"cmt">// obtain the first node
      TNode *ChildNode=Node.Child.At(class="num">0);
      class=class="str">"cmt">// obtain the structure, in which the information about the wave is stored
      TWave *Wave=ChildNode.Wave;
      class="type">class="kw">string Text;

顶点标注的波浪命名映射

在 MT5 自定义指标里给波浪顶点打标签,核心是根据 Wave 结构体的 Name 字段区分推动与修正,再把对应字母或数字写进 Label.Text。推动类(Impulse、Leading Diagonal、Diagonal)的第一个顶点标「1」,第二个标「2」;简单修正类(Zigzag、Flat、两类 Triangle)则分别标「A」「B」;复合修正(Double/Triple Zigzag、Double/Triple Three)首顶标「W」、次顶标「X」。 代码用 Wave.ValueVertex[1]>0 判断第一个顶是否存在,存在才进标注逻辑。通过 LabelArray[Wave.IndexVertex[1]] 拿到该价格柱上的标签数组,若指针无效就 new 一个 CArrayObj 挂上去,再把新建的 TLabel(含 Text、Level、Value)Add 进去。LevelMax 会在每次写入时刷新为当前最大层级,便于后续按层渲染。 第二个顶的判断完全对称:Wave.ValueVertex[2]>0 成立时走同样流程,只是 Text 取值换成「2 / B / X」。实盘加载后,你可以在 EURUSD 的 H1 上看到这些字符直接落在波峰,外汇与贵金属波动剧烈,标注仅辅助结构识别,不预示方向。

MQL5 / C++
  class=class="str">"cmt">// if there is a first top
  if(Wave.ValueVertex[class="num">1]>class="num">0)
    {
     class=class="str">"cmt">// mark the top according to the wave
     if(Wave.Name=="Impulse" || Wave.Name=="Leading Diagonal" || Wave.Name=="Diagonal")
        Text="class="num">1";
     else if(Wave.Name=="Zigzag" || Wave.Name=="Flat" || Wave.Name=="Expanding Triangle" ||
Wave.Name=="Contracting Triangle")
        Text="A";
     else if(Wave.Name=="Double Zigzag" || Wave.Name=="Double Three" ||
Wave.Name=="Triple Zigzag" || Wave.Name=="Triple Three")
        Text="W";
     class=class="str">"cmt">// obtain the array of the ArrayObj tops, which have the index Wave.IndexVertex[class="num">1] on the price chart 
     CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[class="num">1]];
     if(CheckPointer(ArrayObj)==POINTER_INVALID)
       {
        ArrayObj=new CArrayObj;
        LabelArray[Wave.IndexVertex[class="num">1]]=ArrayObj;
       }
     class=class="str">"cmt">// put the information about the top with the index Wave.IndexVertex[class="num">1] into the array ArrayObj
     TLabel *Label=new TLabel;
     Label.Text=Text;
     Label.Level=Wave.Level;
     if(Wave.Level>LevelMax)LevelMax=Wave.Level;
     Label.Value=Wave.ValueVertex[class="num">1];
     ArrayObj.Add(Label);
      }
    if(Wave.ValueVertex[class="num">2]>class="num">0)
      {
     if(Wave.Name=="Impulse" || Wave.Name=="Leading Diagonal" || Wave.Name=="Diagonal")
        Text="class="num">2";
     else if(Wave.Name=="Zigzag" || Wave.Name=="Flat" || Wave.Name=="Expanding Triangle" ||
 Wave.Name=="Contracting Triangle")
        Text="B";
     else if(Wave.Name=="Double Zigzag" || Wave.Name=="Double Three" ||
Wave.Name=="Triple Zigzag" || Wave.Name=="Triple Three")
        Text="X";
     CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[class="num">2]];
     if(CheckPointer(ArrayObj)==POINTER_INVALID)
       {
        ArrayObj=new CArrayObj;
        LabelArray[Wave.IndexVertex[class="num">2]]=ArrayObj;
       }
     TLabel *Label=new TLabel;
     Label.Text=Text;
     Label.Level=Wave.Level;
     if(Wave.Level>LevelMax)LevelMax=Wave.Level;
     Label.Value=Wave.ValueVertex[class="num">2];

◍ 顶点三到五的波浪标签映射

在艾略特波浪自动标注的底层实现里,第 3、4、5 个顶点(Vertex[3]~Vertex[5])的字符标记不是写死的,而是按波浪族类动态指派。顶点值大于 0 才进入标注逻辑,说明该顶点在行情结构上被算法确认存在。 以 Vertex[3] 为例:若 Wave 属于 Impulse、Leading Diagonal 或 Diagonal,标"3";属于 Zigzag、Flat 及两类 Triangle,标"C";属于 Double/Triple Zigzag 与 Three,标"Y"。Vertex[4] 对 Triple 类另标"XX",Vertex[5] 对推动浪标"5"——这套映射直接决定 MT5 图形上你看到的字母数字组合。 每段都先按 IndexVertex 取对应数组指针,CheckPointer 返回 POINTER_INVALID 时才 new 一个 CArrayObj 挂进去,避免重复分配。LevelMax 实时追踪最大层级,影响后续标签纵向避让。外汇与贵金属品种上跑这套逻辑时,请记住杠杆品种波动跳空可能让顶点识别失真,标注仅作概率参考。

MQL5 / C++
   ArrayObj.Add(Label);
   }
   if(Wave.ValueVertex[class="num">3]>class="num">0)
     {
      if(Wave.Name=="Impulse" || Wave.Name=="Leading Diagonal" || Wave.Name=="Diagonal")
         Text="class="num">3";
      else if(Wave.Name=="Zigzag" || Wave.Name=="Flat" ||
Wave.Name=="Expanding Triangle" || Wave.Name=="Contracting Triangle")
         Text="C";
      else if(Wave.Name=="Double Zigzag" || Wave.Name=="Double Three" ||
Wave.Name=="Triple Zigzag" || Wave.Name=="Triple Three")
         Text="Y";
      CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[class="num">3]];
      if(CheckPointer(ArrayObj)==POINTER_INVALID)
        {
         ArrayObj=new CArrayObj;
         LabelArray[Wave.IndexVertex[class="num">3]]=ArrayObj;
        }
      TLabel *Label=new TLabel;
      Label.Text=Text;
      Label.Level=Wave.Level;
      if(Wave.Level>LevelMax)LevelMax=Wave.Level;
      Label.Value=Wave.ValueVertex[class="num">3];
      ArrayObj.Add(Label);
     }
   if(Wave.ValueVertex[class="num">4]>class="num">0)
     {
      if(Wave.Name=="Impulse" || Wave.Name=="Leading Diagonal" || Wave.Name=="Diagonal")
         Text="class="num">4";
      else if(Wave.Name=="Expanding Triangle" || Wave.Name=="Contracting Triangle")
         Text="D";
      else if(Wave.Name=="Triple zigzag" || Wave.Name=="Triple Three")
         Text="XX";
      CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[class="num">4]];
      if(CheckPointer(ArrayObj)==POINTER_INVALID)
        {
         ArrayObj=new CArrayObj;
         LabelArray[Wave.IndexVertex[class="num">4]]=ArrayObj;
        }
      TLabel *Label=new TLabel;
      Label.Text=Text;
      Label.Level=Wave.Level;
      if(Wave.Level>LevelMax)LevelMax=Wave.Level;
      Label.Value=Wave.ValueVertex[class="num">4];
      ArrayObj.Add(Label);
     }
   if(Wave.ValueVertex[class="num">5]>class="num">0)
     {
      if(Wave.Name=="Impulse" || Wave.Name=="Leading Diagonal" || Wave.Name=="Diagonal")
         Text="class="num">5";

「把波浪顶点映射到图表文字标签」

在递归填充完 LabelArray 之后,真正把Wave结构里的顶点画成可读标记,靠的是 CreateLabels()。它先抓取当前图表可视区的价格上下界与窗口像素高度,算出每像素对应的价格跨度 PriceInPixels=(PriceMax-PriceMin)/WindowHeight,这一步决定了后续文字在纵轴上的偏移密度。 遍历 LabelArray 时,索引 i 代表同一根顶点柱上的多个波浪标注。若 CheckPointer(LabelArray[i])!=POINTER_INVALID,说明该柱确有标签对象,便按 j 从 ArrayObj.Total()-1 倒序取出 TLabel,用 LevelMax-Label.Level 把嵌套层级翻转为自上而下的显示行数,避免子浪把父浪文字盖住。 对每个 Label 取 Text、Value 与默认 Size=8,准备向图表写 Text 对象。外汇与贵金属波动剧烈,PriceMax/Min 随缩放实时变,重画前不清旧对象可能叠字,建议在回调开头用 ObjectsDeleteAll() 按前缀清理。

MQL5 / C++
else if(Wave.Name=="Expanding Triangle" || Wave.Name=="Contracting Triangle")
      Text="E";
     else if(Wave.Name=="Triple Zigzag" || Wave.Name=="Triple Three")
      Text="Z";
     CArrayObj *ArrayObj=LabelArray[Wave.IndexVertex[class="num">5]];
     if(CheckPointer(ArrayObj)==POINTER_INVALID)
       {
        ArrayObj=new CArrayObj;
        LabelArray[Wave.IndexVertex[class="num">5]]=ArrayObj;
       }
     TLabel *Label=new TLabel;
     Label.Text=Text;
     Label.Level=Wave.Level;
     if(Wave.Level>LevelMax)LevelMax=Wave.Level;
     Label.Value=Wave.ValueVertex[class="num">5];
     ArrayObj.Add(Label);
     }
      class=class="str">"cmt">// proceed the child nodes of the current node
      for(class="type">int j=class="num">0;j<ChildNode.Child.Total();j++)
       FillLabelArray(ChildNode.Child.At(j));
     }
   }
class="type">class="kw">double PriceInPixels;
CArrayObj ObjTextArray; class=class="str">"cmt">// declare the array, which will store the graphical objects of "Text" type
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The function CreateLabels                                       |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CreateLabels()
  {
   class="type">class="kw">double PriceMax =ChartGetDouble(class="num">0,CHART_PRICE_MAX,class="num">0);
   class="type">class="kw">double PriceMin = ChartGetDouble(class="num">0,CHART_PRICE_MIN);
   class="type">int WindowHeight=ChartGetInteger(class="num">0,CHART_HEIGHT_IN_PIXELS);
   PriceInPixels=(PriceMax-PriceMin)/WindowHeight;
   class="type">int n=class="num">0;
   class=class="str">"cmt">// loop the LabelArray array 
   for(class="type">int i=class="num">0;i<ArrayRange(LabelArray,class="num">0);i++)
    {
     class=class="str">"cmt">// if there are tops with the same index i
     if(CheckPointer(LabelArray[i])!=POINTER_INVALID)
      {
       class=class="str">"cmt">// obtain the tops with the same indexes i
       CArrayObj *ArrayObj=LabelArray[i];
       class=class="str">"cmt">// loop the tops and display them on the chart
       for(class="type">int j=ArrayObj.Total()-class="num">1;j>=class="num">0;j--)
        {
         TLabel *Label=ArrayObj.At(j);
         class="type">int Level=LevelMax-Label.Level;
         class="type">class="kw">string Text=Label.Text;
         class="type">class="kw">double Value=Label.Value;
         class="type">class="kw">color Color;
         class="type">int Size=class="num">8;

艾略特波浪标记的大小写与括号层级

在 MT5 里做波浪自动标注时,靠 Level 变量模 3 的余数来切换显示形态:余数 2 套绿色方括号、余数 1 套蓝色圆括号、余数 0 直接红色无包裹。这样同一段价格走势上能叠出三级嵌套结构,肉眼区分推动浪与修正浪的子级。 当 (Level/3)%2==0 时,代码把大写字母转小写、数字转罗马数字小写(如 1→i、A→a、W→w),用来标记偶数大层的细分。注意这里是整数除法,Level=6 时 (6/3)%2=0 触发,Level=3 时 (3/3)%2=1 不触发,差一层符号风格就变。 外汇与贵金属品种波动快,这种标注只是辅助读图,层级误判概率不低,实盘前建议在 EURUSD 的 M15 上回看至少 200 根 K 线验证映射是否如预期。

MQL5 / C++
if((Level/class="num">3)%class="num">2==class="num">0)
  {
   if(Text=="class="num">1") Text="i";
   else if(Text == "class="num">2") Text = "ii";
   else if(Text == "class="num">3") Text = "iii";
   else if(Text == "class="num">4") Text = "iv";
   else if(Text == "class="num">5") Text = "v";
   else if(Text == "A") Text = "a";
   else if(Text == "B") Text = "b";
   else if(Text == "C") Text = "c";
   else if(Text == "D") Text = "d";
   else if(Text == "E") Text = "e";
   else if(Text == "W") Text = "w";
   else if(Text=="X") Text="x";
   else if(Text == "XX") Text = "xx";
   else if(Text == "Y") Text = "y";
   else if(Text == "Z") Text = "z";
  }
if(Level%class="num">3==class="num">2)
  {
   Color=Green;
   Text="["+Text+"]";
  }
if(Level%class="num">3==class="num">1)
  {
   Color=Blue;
   Text="("+Text+")";
  }
if(Level%class="num">3==class="num">0)
   Color=Red;
class="type">int Anchor;
if(Value==rates[i].high)
  {
   for(class="type">int k=ArrayObj.Total()-j-class="num">1;k>=class="num">0;k--)

◍ 标签随图表缩放自动贴位

在 MT5 里手绘波浪文字标签后,最烦的是缩放图表时标签飘到 K 线实体里。上面这段逻辑把标签锚点分了上下两类:当 Value 等于某根 K 线最高价时,循环累加 15*PriceInPixels 并设 ANCHOR_UPPER;等于最低价时反向减并设 ANCHOR_LOWER,相当于在价格轴上预留 15 像素的呼吸空间。 CorrectLabel 函数才是缩放自适应的核心。它先取 CHART_PRICE_MAX、CHART_PRICE_MIN 和 CHART_HEIGHT_IN_PIXELS,算出当前每像素对应价格 CurrentPriceInPixels,再遍历 ObjTextArray 里所有文本对象。 对每个标签,它用时间反查 rates 数组找到对应 K 线:若标签价低于该 K 线最低价,按 (low-PriceValue)/PriceInPixels 算原偏移像素,再用 CurrentPriceInPixels 换算新价格重设;高于最高价则对称处理。这样拖图表缩放时,标签和影线的相对像素距离不变,不会糊成一团。外汇与贵金属波动剧烈,图表频繁缩放下这套逻辑能省掉大量手动微调,但标签位置仍可能受极端跳空影响,需实盘验证。

MQL5 / C++
Value=Value+class="num">15*PriceInPixels;
 Anchor=ANCHOR_UPPER;
 }
 else if(Value==rates[i].low)
 {
 for(class="type">int k=ArrayObj.Total()-j-class="num">1;k>=class="num">0;k--)
 Value=Value-class="num">15*PriceInPixels;
 Anchor=ANCHOR_LOWER;
 }
 CChartObjectText *ObjText=new CChartObjectText;
ObjText.Create(class="num">0,"wave"+IntegerToString(n),class="num">0,rates[i].time,Value);
ObjText.Description(Text);
ObjText.Color(Color);
ObjText.SetInteger(OBJPROP_ANCHOR,Anchor);
ObjText.FontSize(class="num">8);
ObjText.Selectable(true);
ObjTextArray.Add(ObjText);
n++;
 }
 }
 }
 ChartRedraw();
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The CorrectLabel function |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CorrectLabel()
 {
 class="type">class="kw">double PriceMax=ChartGetDouble(class="num">0,CHART_PRICE_MAX,class="num">0);
 class="type">class="kw">double PriceMin = ChartGetDouble(class="num">0,CHART_PRICE_MIN);
 class="type">int WindowHeight=ChartGetInteger(class="num">0,CHART_HEIGHT_IN_PIXELS);
 class="type">class="kw">double CurrentPriceInPixels=(PriceMax-PriceMin)/WindowHeight;
 class=class="str">"cmt">// loop all of the text objects(wave tops) and change their price size
 for(class="type">int i=class="num">0;i<ObjTextArray.Total();i++)
  {
   CChartObjectText *ObjText=ObjTextArray.At(i);
   class="type">class="kw">double PriceValue=ObjText.Price(class="num">0);
   class="type">class="kw">datetime PriceTime=ObjText.Time(class="num">0);
   class="type">int j;
   for(j=class="num">0;j<ArrayRange(rates,class="num">0);j++)
    {
     if(rates[j].time==PriceTime)
      break;
    }
   class="type">class="kw">double OffsetInPixels;
   if(rates[j].low>=PriceValue)
    {
     OffsetInPixels=(rates[j].low-PriceValue)/PriceInPixels;
     ObjText.Price(class="num">0,rates[j].low-OffsetInPixels*CurrentPriceInPixels);
    }
   else if(rates[j].high<=PriceValue)
    {
     OffsetInPixels=(PriceValue-rates[j].high)/PriceInPixels;
     ObjText.Price(class="num">0,rates[j].high+OffsetInPixels*CurrentPriceInPixels);
    }
  }

「像素价格缓存的收尾赋值」

在指标渲染循环里,常把实时报价换算成的像素坐标暂存到一个变量,便于后续绘图比对。 上述片段中的 PriceInPixels=CurrentPriceInPixels; 就是在该作用域结束前,把当前帧算出的像素价格写回对外暴露的缓存变量。 在 MT5 里接这段逻辑时,可打开自己指标源码确认 CurrentPriceInPixels 的赋值时机;若它依赖 ChartTimePriceToXY,则报价跳动越快,像素值刷新越频繁,高频行情下可能出现 1~2 像素的绘制抖动,属正常现象。

MQL5 / C++
  PriceInPixels=CurrentPriceInPixels;
}

EA 面板按钮与图表对象回收怎么写

自动波浪分析 EA 在 OnInit 里一次性画出四个控制按钮:Begin analysis 触发自动数浪,Show results 把波浪标记画到图上,Clear chart 清内存并删标记,Correct the marks 允许手动改标。按钮横向排布,每个宽 150 像素、高 20 像素,X 坐标从 0 起每 150 递进,挂在主图左上角(锚点 0,0 区域)。 点击动作不走定时器,全在 OnChartEvent 里按对象名分发,所以按钮 Create 时的 ID 字符串必须和事件处理里的比对逻辑一致,否则点了没反应。 OnDeinit 负责拆台:先清波浪树、节点信息数组、之字形数组,再双层循环释放 LabelArray 里每个 CArrayObj 内的 TLabel 指针,最后删图表全部图形对象。外汇与贵金属波动剧烈,EA 异常卸载时若漏掉指针 delete,MT5 终端可能残留隐式内存占用,建议手动拖入品种验证一次卸载日志。 下面这段是初始化与去供应的核心骨架,逐行看:前 9 行 include 把对象库、动态数组和波浪分析自定义头文件拉进来;CChartObjectButton 指针组声明四个按钮;State 标记分析阶段。OnInit 里 State 置 0,new 出按钮并 Create(0,"ID",0,X,0,150,20) —— 参数依次是图表ID、对象名、子窗口、X、Y、宽、高;Description 设 hover 文本;ChartRedraw 强制重绘。OnDeinit 里 ClearTree 等自定义函数释放业务数据,LabelArray 用 CheckPointer 防无效指针后逐层 delete,避免 MT5 报 ghost object。

MQL5 / C++
class="macro">#include <Object.mqh>
class="macro">#include <Arrays\List.mqh>
class="macro">#include <Arrays\ArrayObj.mqh>
class="macro">#include <Arrays\ArrayInt.mqh>
class="macro">#include <Arrays\ArrayDouble.mqh>
class="macro">#include <Arrays\ArrayString.mqh>
class="macro">#include <ChartObjects\ChartObjectsTxtControls.mqh>
class="macro">#include <Elliott wave\Data structures.mqh>
class="macro">#include <Elliott wave\Analysis functions.mqh>
class="macro">#include <Elliott wave\Rules functions.mqh>
CChartObjectButton *ButtonStart,*ButtonShow,*ButtonClear,*ButtonCorrect;
class="type">int State;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   State=class="num">0;
   class=class="str">"cmt">// create control buttons
   ButtonStart=new CChartObjectButton;
   ButtonStart.Create(class="num">0,"Begin analysis",class="num">0,class="num">0,class="num">0,class="num">150,class="num">20);
   ButtonStart.Description("Begin analysis");
   ButtonShow=new CChartObjectButton;
   ButtonShow.Create(class="num">0,"Show results",class="num">0,class="num">150,class="num">0,class="num">150,class="num">20);
   ButtonShow.Description("Show results");
   ButtonClear=new CChartObjectButton;
   ButtonClear.Create(class="num">0,"Clear chart",class="num">0,class="num">300,class="num">0,class="num">150,class="num">20);
   ButtonClear.Description("Clear chart");
   ButtonCorrect=new CChartObjectButton;
   ButtonCorrect.Create(class="num">0,"Correct the marks",class="num">0,class="num">450,class="num">0,class="num">150,class="num">20);
   ButtonCorrect.Description("Correct the marks");
   ChartRedraw();
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
   class=class="str">"cmt">//clear waves tree
   ClearTree(FirstNode);
   class=class="str">"cmt">//clear NodeInfoArray
   ClearNodeInfoArray();
   class=class="str">"cmt">//clear ZigzagArray
   ClearZigzagArray();
   class=class="str">"cmt">//clear LabelArray
   for(class="type">int i=class="num">0;i<ArrayRange(LabelArray,class="num">0);i++)
     {
      CArrayObj *ArrayObj=LabelArray[i];
      if(CheckPointer(ArrayObj)!=POINTER_INVALID)
        {
         for(class="type">int j=class="num">0;j<ArrayObj.Total();j++)
           {
            TLabel *Label=ArrayObj.At(j);
            class="kw">delete Label;
           }
         ArrayObj.Clear();
         class="kw">delete ArrayObj;
        }
     }
   class=class="str">"cmt">//class="kw">delete all of the graphical elements from the chart

◍ 按钮点击顺序错乱时的拦截逻辑

这段释放与事件代码来自一个波浪标注面板的析构与图表交互部分。先倒序遍历 ObjTextArray 并 delete 每个文本对象,再 Clear 数组、释放四个按钮指针,最后 ChartRedraw 一次,避免 MT5 图表残留悬空对象。 事件函数 OnChartEvent 里用 sparam 匹配按钮名,并用 State 变量锁流程:点 Begin analysis 前若 State 不是 0,弹窗要求先 Clear char;Show results 要求 State 先为 1;Clear chart 与 Correct the mark 都要求 State 先为 2,否则提示先按 Show results。 State 实质是 0→1→2 的状态机。若你在 MT5 里复刻这类标注工具,直接抄这套 if 判断就能挡掉大部分误操作导致的空指针崩溃。外汇与贵金属图表上跑这类 EA 属高风险,State 错乱可能画出误导性的波浪线。 Begin analysis 正常触发时,先 CopyRates 填 rates 数组,再 FillZigzagArray(0, Bars(_Symbol,_Period)-1) 抓 Zigzag 顶点,然后 new 一个 TWave 挂到 FirstNode,并预置 11 种波浪名称字符串待后续递归搜索。

MQL5 / C++
  for(class="type">int i=ObjTextArray.Total()-class="num">1;i>=class="num">0;i--)
    {
      CChartObjectText *ObjText=ObjTextArray.At(i);
      class="kw">delete ObjText;
    }
  ObjTextArray.Clear();
  class="kw">delete ButtonStart;
  class="kw">delete ButtonShow;
  class="kw">delete ButtonClear;
  class="kw">delete ButtonCorrect;
  ChartRedraw();
}
class="type">MqlRates rates[];
TNode *FirstNode;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| ChartEvent function                                              |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnChartEvent(const class="type">int id,
                const class="type">long &lparam,
                const class="type">class="kw">double &dparam,
                const class="type">class="kw">string &sparam)
  {
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Begin analysis" && State!=class="num">0)
     MessageBox("First press the button \"Clear class="type">char\"");
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Show results" && State!=class="num">1)
     MessageBox("First press the button \"Begin analysis\"");
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Clear chart" && State!=class="num">2)
     MessageBox("First press the button \"Show results\"");
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Correct the mark" && State!=class="num">2)
     MessageBox("First press the button \"Show results\"");
  class=class="str">"cmt">//if the "Begin analysis" is pressed
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Begin analysis" && State==class="num">0)
    {
      class=class="str">"cmt">//fill the rates array
      CopyRates(NULL,class="num">0,class="num">0,Bars(_Symbol,_Period),rates);
      class=class="str">"cmt">//fill the array ZigzagArray
      FillZigzagArray(class="num">0,Bars(_Symbol,_Period)-class="num">1);
      class=class="str">"cmt">//create the first node
      TWave *Wave=new TWave;
      Wave.IndexVertex[class="num">0] = class="num">0;
      Wave.IndexVertex[class="num">1] = Bars(_Symbol,_Period)-class="num">1;
      Wave.ValueVertex[class="num">0] = class="num">0;
      Wave.ValueVertex[class="num">1] = class="num">0;
      FirstNode=new TNode;
      FirstNode.Child=new CArrayObj;
      FirstNode.Wave=Wave;
      FirstNode.Text="First node";
      class="type">class="kw">string NameWaves="Impulse,Leading Diagonal,Diagonal,Zigzag,Flat,Double Zigzag,Triple Zigzag,
Double Three,Triple Three,Contracting Triangle,Expanding triangle";
      class=class="str">"cmt">//call the search for unbegun and incomplete waves function

「按钮事件驱动的三段式状态机」

这段交互逻辑把波浪分析面板拆成了四个按钮事件,靠一个整型变量 State 在 0/1/2 之间跳转来锁住当前阶段。State=0 是空闲,跑完分析置 1,标完图置 2,清图又回到 0,避免用户在错误阶段误触按钮。 点 Start 后先调 NotStartedAndNotFinishedWaves 补全未起未结的波浪,弹 MessageBox 提示 Analysis is complete,State 改 1 并禁用按钮重绘图表。Show results 仅在 State==1 时生效:按 rates 行数扩 LabelArray,FillLabelArray 填节点,CreateLabels 把波浪标注画上去,State 进 2。 Clear chart 只在 State==2 清理——ClearTree 拆树、清三个缓存数组,再双层循环 delete LabelArray 里的 CArrayObj 和 TLabel 防内存泄漏,顺手删 ObjTextArray 的文本对象,State 归 0。Correct the marks 同样锁 State==2,调 CorrectLabel 后禁按钮重绘。外汇与贵金属图表上跑这套 UI 属高风险操作,参数或点错阶段都可能让标注错乱。 直接在 MT5 里给这四个 if 块打断点,切 State 值看按钮可用性变化,比读文档更快摸清边界。

MQL5 / C++
    NotStartedAndNotFinishedWaves(Wave,class="num">1,FirstNode,NameWaves,class="num">0);
    MessageBox("Analysis is complete");
    State=class="num">1;
    ButtonStart.State(false);
    ChartRedraw();
   }
  class=class="str">"cmt">// if "Show results" is pressed
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Show results" && State==class="num">1)
   {
    ArrayResize(LabelArray,ArrayRange(rates,class="num">0));
    class=class="str">"cmt">//fill the LabelArray array
    FillLabelArray(FirstNode);
    class=class="str">"cmt">//show the mark-up of the waves on the chart
    CreateLabels();
    State=class="num">2;
    ButtonShow.State(false);
    ChartRedraw();
   }
  class=class="str">"cmt">//if "Clear chart" is pressed"
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Clear chart" && State==class="num">2)
   {
    class=class="str">"cmt">//clear the waves tree
    ClearTree(FirstNode);
    class=class="str">"cmt">//clear the NodeInfoArray array
    ClearNodeInfoArray();
    class=class="str">"cmt">//clear the ZigzagArray array
    ClearZigzagArray();
    class=class="str">"cmt">//clear LabelArray
    for(class="type">int i=class="num">0;i<ArrayRange(LabelArray,class="num">0);i++)
     {
      CArrayObj *ArrayObj=LabelArray[i];
      if(CheckPointer(ArrayObj)!=POINTER_INVALID)
       {
        for(class="type">int j=class="num">0;j<ArrayObj.Total();j++)
         {
          TLabel *Label=ArrayObj.At(j);
          class="kw">delete Label;
         }
        ArrayObj.Clear();
        class="kw">delete ArrayObj;
       }
     }
    class=class="str">"cmt">// class="kw">delete mark-up from the chart
    for(class="type">int i=ObjTextArray.Total()-class="num">1;i>=class="num">0;i--)
     {
      CChartObjectText *ObjText=ObjTextArray.At(i);
      ObjText.Delete();
     }
    ObjTextArray.Clear();
    State=class="num">0;
    ButtonClear.State(false);
    ChartRedraw();
   }
  if(id==CHARTEVENT_OBJECT_CLICK && sparam=="Correct the marks" && State==class="num">2)
   {
    CorrectLabel();
    ButtonCorrect.State(false);
    ChartRedraw();
   }
  }

自动波浪标记的五个硬伤与绕法

用 MQL5 写的艾略特自动标记,规则校验只卡形态不卡量价关系,时间和价格的斐波那契比例完全没参与判断,漏掉了很多该剔除的错标。 图表里经常出现没连上的空白段,根源是指定区间取点太少,推动波只找 6 个点就容易断。实战里把取样点提到 8 个以上,空隙概率会明显下降。 标记输出太裸:不画通道、不估目标、不给你切波浪树里的其他分型,屏幕上永远只渲染内存里存的第一种解,其余全占着 RAM 不出力。 性能瓶颈也实打实:月线到日线还行,图 18 的 EURUSD 月线能跑出结果;但小时图柱数一大,单次标记可能耗上几个小时,基本没法盯盘用。外汇和贵金属波动受事件驱动,自动标浪只是辅助,错标风险高,真要信得先手算几段验证。

◍ 别急着下结论

这套基于 MQL5 的艾略特波浪自动标注算法,落地时并不干净。社区反馈里,光是编译环节就有人报出 15 个错误加 25 个警告,根源多在 Zigzag 函数名与变量重名、以及第 511 行附近的非预期 token。手动把函数改名为 Zigzagf 并同步调用点后,有用户说标记错误率明显下降,但离“可用”还远。 代码本身也有逻辑疑点:WaveRules 里对发散三角形的检查出现了连续两次判断同一条件的写法,且 High、Low 数组在函数内从未被读取。这些不是笔误级别的小事,而是会影响波浪识别准确性的结构问题。外汇与贵金属市场波动剧烈、杠杆风险极高,自动数浪结论只能当辅助参考。 如果想自己验证,先把附带的 elliott_wave_en.zip(约 150 KB)在 MT5 里跑通编译,再对照下面这段做核对: WaveAMoreWaveB(3,2)>=0 && WaveAMoreWaveB(3,2)>=0 double High[],Low[]; ArrayResize(High,ArrayRange(rates,0)); ArrayResize(Low,ArrayRange(rates,0)); 前两行是在重复判断同一返回值,后四行声明的数组若不被使用,就可以先注释掉观察输出差异。算法有改进空间,但别把它当成数浪的终点。

MQL5 / C++
WaveAMoreWaveB(class="num">3,class="num">2)>=class="num">0 && WaveAMoreWaveB(class="num">3,class="num">2)>=class="num">0
class="type">class="kw">double High[],Low[];
  ArrayResize(High,ArrayRange(rates,class="num">0));
  ArrayResize(Low,ArrayRange(rates,class="num">0));
让小布替你跑这套
这些波浪结构的诊断与标记逻辑,小布盯盘的 AIGC 已内置到对应品种页,打开即可看自动数浪参考,你只管判断概率与风控。

常见问题

在波浪识别函数中比较三个推动子波的长度,若第三波长度小于第一或第五波则判定规则违例,标记该候选结构无效。
引导楔形的第四波终点必须超过第一波顶部但不超第三波起点,而推动波第四波仅要求不超第一波顶部,约束更松。
小布内置的是通用诊断,省去编译维护;自建程序可按品种微调规则权重,但需处理事件函数与历史重算开销。
用来周期性重算最近 N 根 Bar 的波浪划分,避免每 tick 重跑全历史,降低 CPU 占用。
可加入多时间帧确认、波动率过滤假突破,以及把三角形调整波的容差做成可配置参数。