MQL5 中艾略特波浪自动分析的实施·综合运用
(3/3)·从波浪规则编码到事件处理与程序改良,把理论模型真正跑成可用指标
- 多层 zigzag 顶部的数组填充逻辑
- 从锯齿数组里抠出指定区间的拐点
- 未启动与未完成波的节点挂载逻辑
- 三浪与五浪节点的实例化与规则校验
- 递归拆解子浪与「2<-3-4>」形态匹配
- 波浪顶点归零与子波递归挂载
- 未成形波浪的 3<-4-5> 公式遍历
- 波浪树里第三四五子波的挂接逻辑
- 五波段的实例化与规则校验
- 波浪树里第二到第四子波的递归挂接
- 五浪结构的对象装配与规则校验
- 推动浪子波树的递归挂载逻辑
- 五波结构的顶点枚举与对象填充
- 波浪树里前四级子浪的挂载逻辑
- 五浪树里第四子浪的延迟分析逻辑
- 波体结构填充与规则校验的落地写法
- 三浪与五浪的分支递归落点
- 未成形的 3<-4> 波怎么塞进树里
- 第四子浪的树节点补建与 4<-5> 公式循环
- 末位子波的分支挂载与未启动波处理
- 五波段的第四第五子波挂载逻辑
- 用 2<-3 公式补齐未展开的三浪
- 五波结构的第三子波递归与3<-4-5公式遍历
- 推动浪通过规则校验后的树形展开
- 未启动波的 1<-2-3 公式遍历
- 分形树里逐个挂子波的判断逻辑
- 第五浪节点的对象装配与子树展开
- 五浪子波在树里的递归挂载
- 五波结构的逐顶点实例化
- 波浪树里逐个挂子浪节点
- 递归遍历里未完波浪的挂起逻辑
- 五浪与三浪的递归展开逻辑
- 未达标波浪直接释放内存
- 把合规波浪挂进分形树并递归拆解子波
- 五波结构的逐点填充与规则校验
- 递推建树时前四段的递归落点
- 五波未完形态的嵌套枚举逻辑
- 波形通过规则校验后挂进树
- 第四与第五子浪的递归落点
- 三层循环里拼出 1-2-3 完整波
- 波浪树里逐层挂子浪的递归挂法
- 五波段的实例化与规则校验
- 波浪树里逐子波挂节点的递归写法
- 递归标记里如何避免重复分析子浪
- 波浪顶点固定状态的解析逻辑
- 用顶点数组判定推动浪与引导三角
- 用顶点关系判定五类波浪形态
- 复杂调整浪的拓扑判定分支
- 顶点高低比较的代码实现
- 波A与波B长度比较的判定逻辑
- 波幅比较与内存回收的实现细节
- 顶点标注的波浪命名映射
- 顶点三到五的波浪标签映射
- 把波浪顶点映射到图表文字标签
- 艾略特波浪标记的大小写与括号层级
- 标签随图表缩放自动贴位
- 像素价格缓存的收尾赋值
- EA 面板按钮与图表对象回收怎么写
- 按钮点击顺序错乱时的拦截逻辑
- 按钮事件驱动的三段式状态机
- 自动波浪标记的五个硬伤与绕法
- 别急着下结论
多层 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 已无新顶点,可据此给循环加退出条件避免空转。外汇与贵金属波动随机性高,该结构仅用于形态分层,不预示方向。
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 用历史数据跑一遍确认。
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 约束,就能收紧/放宽子波识别的灵敏度。
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)继续拆。外汇与贵金属杠杆高,这类自动数波结果只作概率参考,实盘须自担风险。
{
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 观察性能。
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 是否生成以及后面三层子浪递归是否被触发。
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 组合如何被逐个试错,比读文档更快摸清嵌套边界。
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 传参或节点标记有漏,应先修再去跑实盘品种。外汇与贵金属波动跳空多,这类自动数波在高波动时段误判概率会明显上升。
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 打印出来比对最稳。
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 个拐点时不越界。
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,否则数组越界会崩脚本。
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 值确认节点序,就能验证挂树顺序是否符合预期。
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 同步记下标,方便后续规则校验。外汇与贵金属波动跳空多,这种枚举对假突破敏感,验证时务必加滑点容差。
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 判断后没有跟函数调用,是原文截断还是漏写要自己核对;外汇与贵金属波动受杠杆影响大,这类自动数浪仅作概率参考,实盘须严控风险。
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() 的命中率打到日志,就能看出哪些子浪区间被反复延迟分析。
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%,这说明初筛噪音很大,递归层级别设太深。外汇与贵金属波动剧烈,此类结构识别仅作概率参考,实盘需严控仓位。
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。外汇与贵金属市场波动剧烈、杠杆风险高,任何波浪自动标记都只是概率辅助,需人工复核。
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 释放很重要,漏写容易在长周期图表上拖慢终端。
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 顶点,其余顶点留待子浪递归补全。外汇与贵金属波动无常,这类结构识别仅作概率参考,实盘须自担高风险。
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 往往递归极浅。
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 波结构被拆成树节点。外汇和贵金属波动受消息面干扰大,自动数浪仅作概率参考,高风险品种务必人工复核。
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 赋值开始:
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() 去重控树深。外汇与贵金属波动剧烈,此类自动数波仅作概率参考,实盘须自担高风险。
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 已结束”区间的状态区分,波浪树可能把未闭合段误判为可统计样本。
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。若首子波对应区间还没分析过,代码会顺势继续向下钻。外汇与贵金属波动剧烈,这种未启动波识别仅作结构参考,实际触发概率随品种流动性变化。
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,给每一条候选波找子波定义。外汇与贵金属市场波动剧烈,这类自动数波仅作概率参考,实盘需自行验证。
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 向下一层递归;已分析过的分支直接跳过,避免重复计算。
…
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,否则函数静默退出,波浪树一条都不会建。
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 砍掉——外汇与贵金属波动受事件驱动,假五波比例可能偏高,属于高风险识别环节。
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 层以上,终端可能倾向卡顿。
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 以外的值,可能让子浪配对逻辑错位。
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 只填了前两个有效顶点,其余四个槽位清零,说明此时只锁定了起步两段。
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);
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 直接析构。你在自己改写波浪扫描器时,建议沿用这种「校验失败即刻释放」的写法,别等函数末尾统一清理,能少很多悬空指针。外汇与贵金属波动大,这类对象若泄漏,策略重启前终端资源会被悄悄吃光。
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 上限设个硬断点,比事后猜挂掉原因实在。
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 未先赋值就会越界,建议先确认上游逻辑。
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 阈值。
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 打印出来,就能直接看到当前品种允许枚举的规模。
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 的容差参数,会直接改变最终树里保留的节点数量——外汇与贵金属波动噪声大,容差过窄可能漏掉有效波段,过宽则树深暴涨拖慢回测,属于典型高风险调参。
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 上限。
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 跑之前建议先用历史数据回看命中率。
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 分支。
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 被剔除。
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 跳空多,高风险下更要先小周期试跑。
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 线增长线性膨胀,就能验证查重是否真的生效。外汇与贵金属杠杆高,自动化标注仅作结构参考,实际进出场仍需结合实时流动性判断。
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 的生成规则时,若发现波幅算错,八成是这里符号解析和顶点序号对不上。外汇与贵金属波动剧烈,自动数浪仅作辅助,实际信号误判概率不低。
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 策略测试器里用你自己的品种和周期跑一遍顶点数组。
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 当成「是否含等号」开关,你能直接比对历史品种里各类浪形的触发频率。外汇与贵金属波动受杠杆放大,形态失效概率不低,任何识别结果都只能当作概率倾向而非方向保证。
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 里用历史分形回看验证。
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] 这行会直接取错价格。外汇与贵金属市场波动剧烈,这类形态识别仅作概率参考,实盘须控仓。
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 策略测试器用历史数据验证。
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 时把内存占用压住。
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 上看到这些字符直接落在波峰,外汇与贵金属波动剧烈,标注仅辅助结构识别,不预示方向。
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 实时追踪最大层级,影响后续标签纵向避让。外汇与贵金属品种上跑这套逻辑时,请记住杠杆品种波动跳空可能让顶点识别失真,标注仅作概率参考。
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() 按前缀清理。
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 线验证映射是否如预期。
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 换算新价格重设;高于最高价则对称处理。这样拖图表缩放时,标签和影线的相对像素距离不变,不会糊成一团。外汇与贵金属波动剧烈,图表频繁缩放下这套逻辑能省掉大量手动微调,但标签位置仍可能受极端跳空影响,需实盘验证。
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 像素的绘制抖动,属正常现象。
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。
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 种波浪名称字符串待后续递归搜索。
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 值看按钮可用性变化,比读文档更快摸清边界。
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)); 前两行是在重复判断同一返回值,后四行声明的数组若不被使用,就可以先注释掉观察输出差异。算法有改进空间,但别把它当成数浪的终点。
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));