使用 MQL5 和 MQL4 开发的选择与导航工具: 增加自动模式搜索和显示侦测到的交易品种·综合运用
🔍

使用 MQL5 和 MQL4 开发的选择与导航工具: 增加自动模式搜索和显示侦测到的交易品种·综合运用

(3/3)· 从抛物线到自定义选项卡,十类日内形态一键筛出,告别手动翻数百张图表

进阶 第 3/3 篇
在 MT5 点开自动挑选选项卡后若空白或按钮消失,多因历史深度不足触发后台补数据,等十五到二十秒即可。虚拟机内存吃紧时调低图表最大柱数能避开内存中断,这比逐个品种翻图省事得多。

「抓 M5 上的抛物线弧形起点」

一段单向行情之后,价格反向走动且每根新柱的低点逐级抬高(或高点逐级压低),这种形态就是抛物线弧形的开端。经验上,这类结构出现后价格倾向于延续新方向,止损可以放在前一根柱的低点附近,仓位风险相对可控。 原文给出的判定很具体:以多头为例,最近两根 M5 柱低点连续高于前一根,而再往前三根低点依次持平或更低,即「三跌两涨」算作多头弧形触发。外汇与贵金属杠杆高,这类信号只是概率优势,不是确定性反转。 下面这段代码在 M5 周期取 6 根 K 线,分别判断低点上移和高点下移两种弧形。直接在 MT5 脚本里跑,能扫出当前品种是否处于弧形初段。 代码逐行拆解:CopyRates 取 M5 最近 6 根 rates;第一重 if 判多头——rates[0].low>rates[1].low 且 rates[1].low>rates[2].low,同时 rates[2]~rates[5] 低点逐根不大于前一根(即前三根走平或下行);符合条件且非跳过品种则记录「品种 (M5)」与标记 0。else if 对称处理空头:高点连续两降、前三根走高或持平,同样入列。

MQL5 / C++
                if(CopyRates(addonName, PERIOD_M5, class="num">0, class="num">6, rates)==class="num">6){
                    if( rates[class="num">0].low>rates[class="num">1].low && rates[class="num">1].low>rates[class="num">2].low && rates[class="num">2].low<=rates[class="num">3].low && rates[class="num">3].low<=rates[class="num">4].low && rates[class="num">4].low<=rates[class="num">5].low ){
                        if(!skip_symbol(addonName)){
                            addonArr.Add(addonName+" (M5)");
                            arrTT.Add(class="num">0);
                        }
                    }else if( rates[class="num">0].high<rates[class="num">1].high && rates[class="num">1].high<rates[class="num">2].high && rates[class="num">2].high>=rates[class="num">3].high && rates[class="num">3].high>=rates[class="num">4].high && rates[class="num">4].high>=rates[class="num">5].high ){
                        if(!skip_symbol(addonName)){
                            addonArr.Add(addonName+" (M5)");
                            arrTT.Add(class="num">0);
                        }
                    }
                }

用跳空百分比筛出异动品种

做股票策略时若依赖向上或向下跳空,直接看跳空扫描页比手动翻行情快得多。该页只列出当日(D1)较前一交易日收盘出现明显裂口的标的,默认阈值设为至少 1% 的跳空幅度。 阈值由 Minimum gap size 参数控制,单位是当前开盘价的百分比。把数值调小能看到更多毛刺,调大则只留真正夸张的缺口,外汇和贵金属跳空虽少但开盘裂口风险极高,参数别设太松。 下面这段逻辑就是扫描核心:取两个日线柱,比较今开与昨收的偏离是否超过设定百分比,且不在跳过列表里就收集标的。 别把 1% 当通用标准 股票波动和汇金品种完全不同,做贵金属跨节跳空时 1% 可能天天命中,建议先在 MT5 里把 gap_min 从 1 改到 3 跑一周观察噪音量。

MQL5 / C++
                if(CopyRates(addonName, PERIOD_D1, class="num">0, class="num">2, rates)==class="num">2){
                    if( rates[class="num">0].open>rates[class="num">1].close+(rates[class="num">0].open*(gap_min/class="num">100)) || rates[class="num">0].open<rates[class="num">1].close-(rates[class="num">0].open*(gap_min/class="num">100)) ){
                        if(!skip_symbol(addonName)){
                            addonArr.Add(addonName+" (M5)");
                            arrTT.Add(class="num">0);
                        }
                    }
                }

◍ 四周高低点的扫描逻辑

做横截面扫描时,把视野拉到周线级别能避开日线噪音。这里的核心动作是:取交易品种最近 4 根周线柱(PERIOD_W1,索引 0 到 3),判断当前周收盘价是否落在 4 周区间的最高或最低端。 代码先用 CopyRates 拉 4 根周线,返回值不等于 4 就直接跳过。若本周 close 既不等于 high 也不等于 low,说明价格只是在区间内晃,newMin 和 newMax 同时置 false,不进入候选。 只有当本周收在最高或最低时,才进 for 循环拿前 3 周做比对:只要本周 high 低于任一周 high,newMax 废掉;只要本周 low 高于任一周 low,newMin 废掉。双重过滤后若仍为真,且不被 skip_symbol 排除,就塞进 addonArr 并标 " (M5)"、arrTT 加 0。 在 MT5 里跑这段,你能立刻得到一份「价格刚触碰四周边界」的品种清单。外汇与贵金属波动受杠杆与消息驱动,边界突破后回撤概率不低,真要跟单请先开模拟验证。

MQL5 / C++
                if(CopyRates(addonName, PERIOD_W1, class="num">0, class="num">4, rates)==class="num">4){
                    class="type">bool newMin=true;
                    class="type">bool newMax=true;
                    if( rates[class="num">0].close!=rates[class="num">0].high && rates[class="num">0].close!=rates[class="num">0].low ){
                         newMin=false;
                         newMax=false;
                    }else{
                         for( class="type">int j=class="num">1; j<class="num">4; j++ ){
                              if( rates[class="num">0].high < rates[j].high ){
                                   newMax=false;
                              }
                              if( rates[class="num">0].low > rates[j].low ){
                                   newMin=false;
                              }
                         }
                    }
                    if( newMin || newMax ){
                         if(!skip_symbol(addonName)){
                              addonArr.Add(addonName+" (M5)");
                              arrTT.Add(class="num">0);
                         }
                    }
                }

「用周线 52 根判年高年低」

年度高低点的判定,本质是拿当前周线收盘位置去和过去一年的周线极值比。代码取的是 PERIOD_W1 周期、从 0 号柱往前数 52 根(约一年交易周),用 CopyRates 拉满这 52 根 K 线数据,返回数不等于 52 就直接跳过。 先盯当前周线本体:若 close 既不是 high 也不是 low,说明这周没创年极值的相,newMin 和 newMax 直接双否。只有 close 顶到 high 或 low 时,才进循环拿 0 号柱和 1~51 号柱逐根比——只要历史上任一周 high 更高就推翻 newMax,任一周 low 更低就推翻 newMin。 两个标志任一为真且不被 skip_symbol 过滤,就把品种名加 '(M5)' 塞进数组。外汇和贵金属波动受宏观事件驱动,年高低破位后反向插针概率不低,真要跟单得先在 MT5 里把这段跑一遍看信号密度。 下面这段是核心判定逻辑,逐行拆一下: if(CopyRates(addonName, PERIOD_W1, 0, 52, rates)==52) // 向品种 addonName 取周线最近52根,成功才继续 bool newMin=true; bool newMax=true; // 先假设本周同时是年最低和年最高 if( rates[0].close!=rates[0].high && rates[0].close!=rates[0].low ){ // 本周收线不在极值上 newMin=false; newMax=false; // 直接排除年高低可能 }else{ // 收线触到 high 或 low 才值得比 for( int j=1; j<52; j++ ){ // 遍历前51周 if( rates[0].high < rates[j].high ) newMax=false; // 历史有更高周高,今年最高不成立 if( rates[0].low > rates[j].low ) newMin=false; // 历史有更低周低,今年最低不成立 } }

if( newMinnewMax ){ // 任一成立

if(!skip_symbol(addonName)){ // 不在跳过名单 addonArr.Add(addonName+" (M5)"); // 记录品种 arrTT.Add(0); // 时间标签占位 } }

MQL5 / C++
if(CopyRates(addonName, PERIOD_W1, class="num">0, class="num">52, rates)==class="num">52){
      class="type">bool newMin=true;
      class="type">bool newMax=true;
      if( rates[class="num">0].close!=rates[class="num">0].high && rates[class="num">0].close!=rates[class="num">0].low ){
         newMin=false;
         newMax=false;
      }else{
         for( class="type">int j=class="num">1; j<class="num">52; j++ ){
            if( rates[class="num">0].high < rates[j].high ){
               newMax=false;
            }
            if( rates[class="num">0].low > rates[j].low ){
               newMin=false;
            }
         }
      }
      if( newMin || newMax ){
         if(!skip_symbol(addonName)){
            addonArr.Add(addonName+" (M5)");
            arrTT.Add(class="num">0);
         }
      }
   }

用取整价筛出潜在磁吸品种

不少交易者把以 00 或 50 结尾的价格(如 125.00、79.50)视作天然的支撑阻力带,认为价格靠近这些整数位时容易出现停顿或反转。这种心理价位在外汇和贵金属上同样存在,但波动杠杆高、滑点风险大,靠近并不代表一定会回头。 下面这段逻辑只处理两位小数品种(如多数外汇对),通过 M5 收盘价小数部分判断是否在取整区间:0.46~0.54 算贴近 .50,小于 0.04 或大于 0.96 算贴近 .00。命中且未被 skip_symbol 排除的,就加入监控列表。 代码逐行拆解:

  • switch((int)SymbolInfoInteger(addonName, SYMBOL_DIGITS)):取品种小数位数,按位数分支。
  • case 0: break;:无小数位的品种直接跳过。
  • case 2::两位小数品种进入判断。
  • if(CopyRates(addonName, PERIOD_M5, 0, 1, rates)==1):取 M5 最新 1 根 K 线数据。
  • double tmpRound=rates[0].close - (int)rates[0].close:取收盘价小数部分。
- if((tmpRound>0.46 && tmpRound<0.54)tmpRound>0.96tmpRound<0.04):判定是否落在 .50 或 .00 邻近带。
  • if(!skip_symbol(addonName)):确认该品种未被手动跳过。
  • addonArr.Add(addonName+" (M5)"); arrTT.Add(0);:加入监控数组并置计时。

如果你跑 EURUSD 这类两位品种,把这段接进自己的扫描器,就能在 MT5 里实时捞出“价格正贴着整数口”的标的,再结合手动价态确认。

MQL5 / C++
                class="kw">switch((class="type">int) SymbolInfoInteger(addonName, SYMBOL_DIGITS)){
                    case class="num">0:
                        break;
                    case class="num">2:
                        if(CopyRates(addonName, PERIOD_M5, class="num">0, class="num">1, rates)==class="num">1){
                            class="type">class="kw">double tmpRound=rates[class="num">0].close - (class="type">int) rates[class="num">0].close;
                            if( (tmpRound>class="num">0.46 && tmpRound<class="num">0.54) || tmpRound>class="num">0.96 || tmpRound<class="num">0.04 ){
                                if(!skip_symbol(addonName)){
                                    addonArr.Add(addonName+" (M5)");
                                    arrTT.Add(class="num">0);
                                }
                            }
                        }
                        break;
                }

◍ 单向碾压的标的怎么捞出来

有些交易品种在一段时期内几乎只朝一个方向走,这种单向性强的资产对外汇、贵金属交易者来说值得单独盯——但符合这样特征的品种通常不多,属于小众筛选需求。 逻辑上用两个参数卡住:mostly_count 控制回看天数(默认 15,即在 D1 周期看最近 15 根日线),mostly_percent 控制单向占比阈值(默认 90,意味着 15 天里至少有 90% 的天数收阳或收阴才入选)。实际跑下来,90% 太严,能命中的符号极少,把百分比调到 70~80 区间更可能出结果。 代码里先 CopyRates 拉日线,逐根比 close 和 open 统计 mostlyLong / mostlyShort。若某一方向占比 ≥ mostly_percent 就加入监控数组。外汇与贵金属波动受杠杆和事件驱动影响大,这类单边品种反转风险高,参数验证请在 MT5 策略测试器或自定义脚本里实跑。

MQL5 / C++
sinput class="type">class="kw">string        delimeter_08=""; class=class="str">"cmt">// --- 额外的多数上涨/下跌选项卡 ---
input class="type">int            mostly_count=class="num">15; class=class="str">"cmt">// Check the last specified number of days(检查最近指定的天数)
input class="type">int            mostly_percent=class="num">90; class=class="str">"cmt">// Specified percentage in one direction exceeded(指定在一个方向上超过的百分比)
                 if(CopyRates(addonName, PERIOD_D1, class="num">1, mostly_count, rates)==mostly_count){
                     class="type">int mostlyLong=class="num">0;
                     class="type">int mostlyShort=class="num">0;
                     for( class="type">int j=class="num">0; j<mostly_count; j++ ){
                         if(rates[j].close>rates[j].open){
                             mostlyLong++;
                         }else if(rates[j].close<rates[j].open){
                             mostlyShort++;
                         }
                     }
                     if( !mostlyLong || !mostlyShort ){
                         addonArr.Add(addonName);
                         arrTT.Add(class="num">0);
                     }else if( ((mostlyLong*class="num">100)/(mostlyLong+mostlyShort)) >= mostly_percent ){
                         addonArr.Add(addonName);
                         arrTT.Add(class="num">0);
                     }else if( ((mostlyShort*class="num">100)/(mostlyLong+mostlyShort)) >= mostly_percent ){
                         addonArr.Add(addonName);
                         arrTT.Add(class="num">0);
                     }
                 }

「用逐柱高低点扫出慢速积累」

积累行情的典型特征是价格朝一个方向挪动得很慢,但每一根都在悄悄抬高低点或者压低高点。这种结构持续一段时间后,往往倾向出现一根同向大柱完成突破,外汇与贵金属市场里这类形态伴随的滑点和反转风险都偏高。 下面这段逻辑就是在一组柱里逐根比对高低点:只要存在连续新高或连续新低,就判定该品种处于单向积累。默认取日线最近 15 根做检查,你可以直接改 alltime_count 看不同样本长度下的命中率。 代码逐行拆解: sinput string delimeter_09=""; // 分隔符占位,无实际过滤作用 input ENUM_TIMEFRAMES alltime_period=PERIOD_D1; // 取日线周期 input int alltime_count=15; // 检查最近 15 根柱 if(CopyRates(addonName, alltime_period, 1, alltime_count, rates)==alltime_count){ // 成功拷贝 15 根汇率数据才继续 bool alltimeHigh=true; // 先假设全是新高 bool alltimeLow=true; // 先假设全是新低 for(int j=1; j<alltime_count; j++){ // 从第 2 根开始比前一根 if(rates[j].high>rates[j-1].high){ alltimeHigh=false; } // 有更高高就推翻新高假设 if(rates[j].low<rates[j-1].low){ alltimeLow=false; } // 有更低低就推翻新低假设 }

if( alltimeHighalltimeLow ){ // 任一成立说明单向积累

addonArr.Add(addonName); // 记录品种名 arrTT.Add(0); // 标记类型 0 } } 把 alltime_period 换成 PERIOD_H4 再跑一遍,能更早发现日内积累,但假信号概率会上升,需要配合成交量或 ATR 过滤。

MQL5 / C++
sinput class="type">class="kw">string        delimeter_09=""; class=class="str">"cmt">// --- 额外的 总有新高/低选项卡 ---
input ENUM_TIMEFRAMES alltime_period=PERIOD_D1; class=class="str">"cmt">// 时段
input class="type">int             alltime_count=class="num">15; class=class="str">"cmt">// Check the last specified number of bars(检查最近指定的柱数)
                     if(CopyRates(addonName, alltime_period, class="num">1, alltime_count, rates)==alltime_count){
                        class="type">bool alltimeHigh=true;
                        class="type">bool alltimeLow=true;
                        for( class="type">int j=class="num">1; j<alltime_count; j++ ){
                          if(rates[j].high>rates[j-class="num">1].high){
                             alltimeHigh=false;
                          }
                          if(rates[j].low<rates[j-class="num">1].low){
                             alltimeLow=false;
                          }
                        }
                        if( alltimeHigh || alltimeLow ){
                          addonArr.Add(addonName);
                          arrTT.Add(class="num">0);
                        }
                     }

收盘钉在极值边上的品种怎么捞

做品种扫描时,最后一个实用维度是「交易日收在当日高/低附近」。逻辑很直接:若收盘价贴着当天极值,说明对手盘没来得及把计划打完,次日沿原方向延续的概率倾向更高——外汇和贵金属波动受 session 切换影响大,这类形态只是候选而非信号,实盘仍属高风险。 实际写 EA 扫描别死磕绝对触碰。价格离高点差几个点、甚至十几个点都算「没离开极值区」,硬等 close==high 会漏掉一堆。用偏移容差参数把边界放宽,才是能跑的过滤条件。 下面这段是日线级别判定的核心:取 D1 的 close 与 high/low 比,加容差后命中就塞进待观察数组。highclose_offset 默认 0,建议 EURUSD 这类点值小的给 3~5 点,XAUUSD 给 10~15 点更稳。 别把收盘贴极值当圣经 容差设太大(比如 50 点)会把普通震荡收盘也收编,扫描列表膨胀后反而没法盯。先在 MT5 用单品种手动验一遍再批量跑。

MQL5 / C++
<span class="keyword">sinput</span> <span class="keyword">class="type">class="kw">string</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delimeter_10=<span class="class="type">class="kw">string">""</span>; <span class="comment">class=class="str">"cmt">// --- 额外的 最高价=收盘价 选项卡 ---</span>
<span class="keyword">input</span> <span class="macro">ENUM_TIMEFRAMES</span> highclose_period=<span class="macro">PERIOD_D1</span>; <span class="comment">class=class="str">"cmt">// 时段</span>
<span class="keyword">input</span> <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;highclose_offset=<span class="number">class="num">0</span>; <span class="comment">class=class="str">"cmt">// 最高价/最低价偏移点数</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">if</span>(<span class="functions">CopyRates</span>(addonName, highclose_period, <span class="number">class="num">0</span>, <span class="number">class="num">1</span>, rates)==<span class="number">class="num">1</span>){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">if</span>( rates[<span class="number">class="num">0</span>].close+highclose_offset &gt;= rates[<span class="number">class="num">0</span>].high ){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addonArr.Add(addonName);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arrTT.Add(<span class="number">class="num">0</span>);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<span class="keyword">else</span> <span class="keyword">if</span>( rates[<span class="number">class="num">0</span>].close-highclose_offset &lt;= rates[<span class="number">class="num">0</span>].low ){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addonArr.Add(addonName);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;arrTT.Add(<span class="number">class="num">0</span>);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }

◍ 往面板里塞自己的筛选选项卡

这套工具没把模式写死,懂 MQL5 的人完全可以自己扩。想在面板里多一个自动挑品种的标签页,不用动整体架构,两处改动就能跑起来。 第一步,把新标签的名字填进 panelNamesAddon 这个名称数组,同时把数组声明的大小加 1,否则越界读不到。第二步,到 show_symbols 函数的 switch 里补一个 case,编号用现有最大数字加 1,把品种遍历和判定逻辑写进这个 case 内。 下面这段是 case 骨架,直接照着填判定条件即可:遍历临时品种池 tmpSymbols,逐个取名字做检查,不合条件就跳过,合条件自然留在结果里。 外汇与贵金属波动剧烈、杠杆风险高,自建筛选只解决「找品种」,不解决「何时下手」,上线前请在 MT5 策略测试器用历史数据验一遍命中率。

MQL5 / C++
                case index: class=class="str">"cmt">// 选项卡名称
                    for( class="type">int i=class="num">0; i<tmpSymbols.Total(); i++ ){
                        addonName=tmpSymbols[i];
                        class=class="str">"cmt">// 检查代码
                        }
                    
                    break;

「跨平台实用工具的取舍思路」

这套查找工具给出了 ex5 与 ex4 两套产物:finder.ex5 体积 270.41 KB、finder.mq5 源码 186.66 KB,finder4.ex4 为 178.96 KB、finder4.mq4 同源 186.66 KB。同一套逻辑在 MQL4 与 MQL5 下都能编译运行,说明绕开 MQL5 特有的类体系、用两版语言都支持的基础写法,确实能把工具覆盖面拉到两个平台。 外汇与贵金属交易本身杠杆高、滑点跳空频繁,任何工具只降低操作成本,不替你过滤风险。 如果接下来要改这类跨平台脚本,先把用到的数组和文件读写换成两版都兼容的写法,再分别用 MT4、MT5 各编译一次,比急着上 CIndicator 之类 MQL5 专属类更实在。

把重复劳动交给小布
这些形态扫描逻辑小布盯盘已内置到对应品种页,打开即可看到实时命中的交易品种,你只管做决策。

常见问题

MT5 在品种历史深度不够时会向服务器请求并构建所需时间框架,而 MQL4 需用户预先准备历史,故前者首次打开可能延迟十五到二十秒。
限制终端的图表最大柱数参数,尤其在 RAM 仅 1GB 的虚拟机环境,可减少同时加载多周期历史带来的内存压力。
可以,小布盯盘的品种页已集成类似形态扫描,无需自行写 MQL 也能看到命中列表与参数。
将保存选项卡名的数组大小加一并在末尾写入新名称,配合 addons_infowatch 权限与配置参数,show_panel_buttons 会将其渲染在原有选项卡之后。
倾向服务于整数关口突破或均值回归的日内策略,但外汇贵金属波动剧烈,仅作概率参考。