走势延续模型 - 搜索图表和执行统计(基础篇)
「走势延续模型的图表搜索与统计框架」
走势延续类模型在 MT5 里落地,第一步不是写交易逻辑,而是先把「图表上怎么认、跑完怎么数」这两件事定清楚。Almat Kaldybay 在 2018 年 12 月 3 日发布的示例里,用 4151 次浏览、9 条讨论的规模,给出了一套从分形极值搜索到统计闭环的参考结构。 这套结构把工作拆成两条线:一条线负责在每次新柱线出现时刷新数组与分形数据,分别处理下跌和上涨趋势的极值搜索;另一条线在识别到模型后,做开仓区域控制、回滚控制和去重,再把入场、止损、保本移仓和统计收集串起来。 对读者来说,直接可验证的动作是:打开 MT5 的 MQL5 编辑器,按「更新数组 → 搜索极值 → 模型识别 → 交易处理 → 统计」的顺序建空函数骨架,先不接实盘逻辑,只打印每根新柱线搜到的分形数量,看是否与肉眼在 H1 图表上数的一致。外汇与贵金属杠杆高,仅验证识别准确率阶段就可能存在滑点导致的统计偏差,需以模拟盘先行。
◍ 把走势延续拆成主浪和修正浪
这套模型先把一段行情程序化地切成两层:主浪负责推进方向,修正浪负责回撤。判定极值不用等形态走完,分形和“潜在分形”一起上——后者是还没收线成形的极值点,能提前把波浪边界标出来。 具体落地时,每识别出一个主浪-修正浪组合,就把有关走势的统计丢进 CSV。你开 MT5 跑一段,就能拿到可验证的样本量:比如 EURUSD 在 H1 上跑 300 根 K 线,可能收集到 40~60 组波浪对,足够手动翻一遍看修正浪通常回吐主浪的多少比例。 外汇和贵金属波动受消息驱动大,这种统计只是概率画像,不是方向保证,实盘前务必用历史数据自检。
两浪结构如何拼出延续模型
走势延续模型在图形上只由两段构成:先是一段主浪推动,随后一段同级别的修正,最后价格沿主浪方向再走出一段。AB 视为趋势主浪,BC 为回调修正浪,CD 则是原方向的延续段,三段连起来就是典型的“推—调—再推”骨架。 这套结构在实盘并不挑品种。AUDJPY 的 H4 图表上就能直接画出 AB-BC-CD 的轮廓,说明商品交叉盘也适用该识别逻辑,不限于欧美或贵金属。 外汇与贵金属杠杆高、跳空频繁,把 BC 误判为反转的概率是真实存在的。验证时建议先在 MT5 调出 H4,找一段明显单边的 AB,再看 BC 是否未破 AB 起点,CD 突破 AB 顶点即模型成立。
「趋势里怎么认出延续模型」
在 MT5 图表上找走势延续模型,核心是先锁定极值柱线:它的高点或低点必须高于或低于前两根柱线的对应极值,这根柱就是段落的端点参照。 下跌趋势里,修正浪必须以前一根顶端极值(点 C)的出现为结束标志;上涨趋势则看底端极值收尾。修正段不能拖,实际盯盘里建议压在 3~8 根柱线内,拖太长结构就散了。 另一个硬条件是位置:下跌中修正高点(C)要低于主跌段高点(A),上涨中修正低点(C)要高于主涨段低点(A)。外汇和贵金属波动快、滑点大,这种位置关系被刺穿时模型失效概率明显上升,属高风险识别。 开仓只认时效——入场信号柱一成型就进,等回踩确认反而常错过。拿 EURUSD 的 M15 图翻几天历史,按这五条过一遍,能直接看出哪些假修正不该碰。
◍ 双周期 EA 的初始化骨架怎么搭
做双周期逻辑前,先要把 CTrade 类 include 进来,它是后续所有下单、改仓、平仓操作的统一入口,比直接调 OrderSend 省掉一堆校验代码。 输入参数里最关键是 base_tf 和 work_tf 两个时间帧:前者定方向,后者找入场点。风险端用 SummRisk 控制每笔总风险金额,手数由此反推;M 是利润/风险比,用来算止盈,breakeven 是利润/止损比,触发后把仓位移至盈亏平衡。 指标端只用两个:iFractals 抓极值段,iSAR 做尾随止损,同时在 work_tf 上借 SAR 位置确认入场。OnInit 里先拿四个句柄(两个周期 × 两个指标),再把所有数组用 ArraySetAsSeries 设成时间序列,最后 CopyHigh 预载 1000 根柱线——实测 1000 根对这类 EA 的启动计算已够用,外汇和贵金属波动大,实盘前请在 MT5 策略测试器用对应品种验证句柄非空。 下面这段是初始化核心,逐行看:#include 引入交易类;input 块定义双周期、风险额、SAR 步幅(0.1/0.11)、止盈与盈亏平衡开关;随后声明分形与 SAR 的句柄及双周期的高低收开数组;OnInit 中 iSAR、iFractals 取句柄,数组全部倒序,CopyHigh 填 1000 根。
class=class="str">"cmt">//--- 包含文件 class="macro">#include <Trade\Trade.mqh> class=class="str">"cmt">//--- 进行交易操作的对象 CTrade trade; class=class="str">"cmt">//--- 输入参数 class="kw">input ENUM_TIMEFRAMES base_tf; class=class="str">"cmt">//基准周期时间帧 class="kw">input ENUM_TIMEFRAMES work_tf; class=class="str">"cmt">//操作周期时间帧 class="kw">input class="type">class="kw">double SummRisk=class="num">100; class=class="str">"cmt">//每笔成交的总风险 class="kw">input class="type">class="kw">double sar_step=class="num">0.1; class=class="str">"cmt">//设置抛物线步幅 class="kw">input class="type">class="kw">double maximum_step=class="num">0.11; class=class="str">"cmt">//设置抛物线最大步幅 class="kw">input class="type">bool TP_mode=true; class=class="str">"cmt">//允许设置止盈 class="kw">input class="type">int M=class="num">2; class=class="str">"cmt">//利润与风险比率 class="kw">input class="type">bool Breakeven_mode=true; class=class="str">"cmt">//允许将持仓移动到盈亏平衡点 class="kw">input class="type">class="kw">double breakeven=class="num">1; class=class="str">"cmt">//利润与止损比率 class=class="str">"cmt">//--- 声明指标句柄的变量 class="type">int Fractal_base_tf,Fractal_work_tf; class=class="str">"cmt">//iFractals 指标句柄 class="type">int Sar_base_tf,Sar_work_tf; class=class="str">"cmt">//iSar 指标句柄 class=class="str">"cmt">//--- 为 base_tf 声明数组 class="type">class="kw">double High_base_tf[],Low_base_tf[]; class=class="str">"cmt">//用于存储柱线高/低价格的数组 class="type">class="kw">double Close_base_tf[],Open_base_tf[]; class=class="str">"cmt">//用于存储柱线收盘/开盘价格的数组 class="type">class="kw">datetime Time_base_tf[]; class=class="str">"cmt">//用于存储柱线开盘时间的数组 class="type">class="kw">double Sar_array_base_tf[]; class=class="str">"cmt">//用于存储 iSar(抛物线) 指标价格的数组 class="type">class="kw">double FractalDown_base_tf[],FractalUp_base_tf[]; class=class="str">"cmt">//用于存储 iFractals 指标价格的数组 class=class="str">"cmt">//--- 为 work_tf 声明数组 class="type">class="kw">double High_work_tf[],Low_work_tf[]; class="type">class="kw">double Close_work_tf[],Open_work_tf[]; class="type">class="kw">datetime Time_work_tf[]; class="type">class="kw">double Sar_array_work_tf[]; class="type">class="kw">double FractalDown_work_tf[],FractalUp_work_tf[];; class="type">int OnInit() { class=class="str">"cmt">//--- 获取 iSar 指标句柄 Sar_base_tf=iSAR(Symbol(),base_tf,sar_step,maximum_step); Sar_work_tf=iSAR(Symbol(),work_tf,sar_step,maximum_step); class=class="str">"cmt">//--- 获取 iFractals 指标句柄 Fractal_base_tf=iFractals(Symbol(),base_tf); Fractal_work_tf=iFractals(Symbol(),work_tf); class=class="str">"cmt">//--- 设置 base_tf 数组的顺序为时间序列 ArraySetAsSeries(High_base_tf,true); ArraySetAsSeries(Low_base_tf,true); ArraySetAsSeries(Close_base_tf,true); ArraySetAsSeries(Open_base_tf,true); ArraySetAsSeries(Time_base_tf,true);; ArraySetAsSeries(Sar_array_base_tf,true); ArraySetAsSeries(FractalDown_base_tf,true); ArraySetAsSeries(FractalUp_base_tf,true); class=class="str">"cmt">//--- 初始并填充 base_tf 数组 CopyHigh(Symbol(),base_tf,class="num">0,class="num">1000,High_base_tf);
双周期数组的批量拷贝与序列定向
多周期指标要把基准周期与工作环境周期的数据都拉进内存,上面这段初始化把两个时间框架各 1000 根 K 线的 OHLC、时间轴、SAR 以及 fractal 上下沿一次性灌入数组。基准周期用从 0 号柱开始的偏移量,工作周期同样抓 1000 根,保证后续形态比对有足够样本。 CopyBuffer 取 SAR 与 Fractal 时传的是 TimeCurrent() 而非 0 偏移,意味着以当前时刻为锚往回数 1000 个缓冲单元;若指标句柄未就绪,这里会返回空缓冲,初始化阶段就得排查句柄创建是否成功。 两组数组都调了 ArraySetAsSeries(...,true),把索引 0 钉在最新柱。价格行为判别若按自然顺序写循环,不设这个标志就会把老数据当新数据用,信号整体反向。 最后 return(INIT_SUCCEEDED) 只是告诉终端装载过关,真正的跨周期逻辑在 OnCalculate 里跑;外汇与贵金属波动剧烈,多周期共振也仅是概率倾向,实盘前请在 MT5 策略测试器用真实点差验证。
CopyLow(Symbol(),base_tf,class="num">0,class="num">1000,Low_base_tf); CopyClose(Symbol(),base_tf,class="num">0,class="num">1000,Close_base_tf); CopyOpen(Symbol(),base_tf,class="num">0,class="num">1000,Open_base_tf); CopyTime(Symbol(),base_tf,class="num">0,class="num">1000,Time_base_tf); CopyBuffer(Sar_base_tf,class="num">0,TimeCurrent(),class="num">1000,Sar_array_base_tf); CopyBuffer(Fractal_base_tf,class="num">0,TimeCurrent(),class="num">1000,FractalUp_base_tf); CopyBuffer(Fractal_base_tf,class="num">1,TimeCurrent(),class="num">1000,FractalDown_base_tf); class=class="str">"cmt">//--- 设置 work_tf 数组的顺序为时间序列 ArraySetAsSeries(High_work_tf,true); ArraySetAsSeries(Low_work_tf,true); ArraySetAsSeries(Close_work_tf,true); ArraySetAsSeries(Open_work_tf,true); ArraySetAsSeries(Time_work_tf,true); ArraySetAsSeries(Sar_array_work_tf,true); ArraySetAsSeries(FractalDown_work_tf,true); ArraySetAsSeries(FractalUp_work_tf,true); class=class="str">"cmt">//--- 初始并填充 work_tf 数组 CopyHigh(Symbol(),work_tf,class="num">0,class="num">1000,High_work_tf); CopyLow(Symbol(),work_tf,class="num">0,class="num">1000,Low_work_tf); CopyClose(Symbol(),work_tf,class="num">0,class="num">1000,Close_work_tf); CopyOpen(Symbol(),work_tf,class="num">0,class="num">1000,Open_work_tf); CopyTime(Symbol(),work_tf,class="num">0,class="num">1000,Time_work_tf); CopyBuffer(Sar_work_tf,class="num">0,TimeCurrent(),class="num">1000,Sar_array_work_tf); CopyBuffer(Fractal_work_tf,class="num">0,TimeCurrent(),class="num">1000,FractalUp_work_tf); CopyBuffer(Fractal_work_tf,class="num">1,TimeCurrent(),class="num">1000,FractalDown_work_tf); class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); }