MQL5 向导: 根据计算价位下单, 止损和止盈。标准库扩展·综合运用
「DeltaZZ 价格模块的类骨架与默认参数」
下面这段 CPriceDeltaZZ 类的声明和构造函数,把基于 ZigZag 偏离的价格模块骨架定死了。它管几件事:挂单层数 m_levels、盈亏比 m_tp_ratio、订单存活根数 m_exp_bars,以及从 ZZ 极值反推买卖止损位的 getBuySL / getSellSL。 构造函数里给的默认值值得直接抄进 MT5 试:m_app_price=1、m_rev_mode=0、m_pips=300、m_percent=0.5、m_levels=2。也就是说初始状态按 300 点基准、0.5% 比例、两层网格去算价格偏移,反转模式关闭。 calcExpiration 用 TimeCurrent() 加 m_exp_bars 乘 PeriodSeconds(m_period) 算订单过期时间,这根数直接决定挂单在盘面留多久。外汇和贵金属波动随机性高,m_exp_bars 设太大可能吃不到出场就废单。 逐行看声明段:m_levels 是 int 型层数;m_tp_ratio 注释写明是 tp:sl 比值;m_exp_bars 是订单以 K 线根计的生命周期;InitDeltaZZ 负责把指标挂进 CIndicators 指针;公开区一堆 set 方法让你运行时改参,ValidationSettings 做参数合法性校验,Prices 是输出最终价格的主函数。
class="type">int m_levels; class="type">class="kw">double m_tp_ratio; class=class="str">"cmt">//tp:sl ratio class="type">int m_exp_bars; class=class="str">"cmt">//lifetime of the orders in bars class=class="str">"cmt">//--- method of indicator initialization class="type">bool InitDeltaZZ(CIndicators *indicators); class=class="str">"cmt">//--- helper methods class="type">class="kw">datetime calcExpiration() { class="kw">return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); } class="type">class="kw">double getBuySL(); class=class="str">"cmt">//function for searching latest minimum of ZZ for buy SL class="type">class="kw">double getSellSL(); class=class="str">"cmt">//function for searching latest maximum of ZZ for sell SL class="kw">public: CPriceDeltaZZ(); ~CPriceDeltaZZ(); class=class="str">"cmt">//--- methods of changing module settings class="type">void setAppPrice(class="type">int ap) { m_app_price=ap; } class="type">void setRevMode(class="type">int rm) { m_rev_mode=rm; } class="type">void setPips(class="type">int pips) { m_pips=pips; } class="type">void setPercent(class="type">class="kw">double perc) { m_percent=perc; } class="type">void setLevels(class="type">int rnum) { m_levels=rnum; } class="type">void setTpRatio(class="type">class="kw">double tpr) { m_tp_ratio=tpr; } class="type">void setExpBars(class="type">int bars) { m_exp_bars=bars; } class=class="str">"cmt">//--- method of checking correctness of settings class="kw">virtual class="type">bool ValidationSettings(class="type">void); class=class="str">"cmt">//--- method of creating indicators class="kw">virtual class="type">bool InitIndicators(CIndicators *indicators); class=class="str">"cmt">//--- main method of price module updating the output data class="kw">virtual class="type">class="kw">double Prices(); }; CPriceDeltaZZ::CPriceDeltaZZ() : m_app_price(class="num">1), m_rev_mode(class="num">0), m_pips(class="num">300), m_percent(class="num">0.5), m_levels(class="num">2),
◍ 信号类里的参数闸门与指标挂载
自定义信号类 CPriceDeltaZZ 在跑策略前,先由 ValidationSettings() 卡一道参数边界。这里硬性规定:射线最小跨度 m_pips 必须 ≥10,否则直接 printf 报错并返回 false;m_app_price 与 m_rev_mode 只能取 0 或 1,m_percent、m_levels、m_tp_ratio 都必须大于 0,m_exp_bars 允许 0 但不可为负。 这些数字不是随便写的——m_pips<10 意味着价格射线连 1 个点差台阶都构不成,后续 ZigZag 拐点识别会失效。你在 MT5 里改 EA 输入参数时,若日志抛出 "Number of pips in a ray must be at least 10",就是这里拦的。 InitIndicators() 负责把指标挂进集合。它先调父类 CExpertSignal::InitIndicators() 保底,再走 InitDeltaZZ() 把自定义 m_deltazz 指针加进 indicators 容器;若 Add() 失败会打印 "error adding object" 并返回 false。 InitDeltaZZ() 里用 MqlParam parameters[6] 开 6 个槽位准备传参,首参 parameters[0].type=TYPE_STRING 表明自定义指标名以字符串形式递进去。外汇与贵金属波动剧烈,这类校验缺失可能导致异常下单,实盘前务必在策略测试器跑一遍初始化日志。
m_tp_ratio(class="num">1), m_exp_bars(class="num">10) { } class="type">bool CPriceDeltaZZ::ValidationSettings(class="type">void) { class=class="str">"cmt">//--- checking for settings of additional filters if(!CExpertSignal::ValidationSettings()) class="kw">return(class="kw">false); class=class="str">"cmt">//--- initial data check if(m_app_price<class="num">0 || m_app_price>class="num">1) { printf(__FUNCTION__+": Applied price must be class="num">0 or class="num">1"); class="kw">return(class="kw">false); } if(m_rev_mode<class="num">0 || m_rev_mode>class="num">1) { printf(__FUNCTION__+": Reversal mode must be class="num">0 or class="num">1"); class="kw">return(class="kw">false); } if(m_pips<class="num">10) { printf(__FUNCTION__+": Number of pips in a ray must be at least class="num">10"); class="kw">return(class="kw">false); } if(m_percent<=class="num">0) { printf(__FUNCTION__+": Percent must be greater than class="num">0"); class="kw">return(class="kw">false); } if(m_levels<class="num">1) { printf(__FUNCTION__+": Ray Number must be at least class="num">1"); class="kw">return(class="kw">false); } if(m_tp_ratio<=class="num">0) { printf(__FUNCTION__+": TP Ratio must be greater than zero"); class="kw">return(class="kw">false); } if(m_exp_bars<class="num">0) { printf(__FUNCTION__+": Expiration must be zero or positive value"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- parameter check passed class="kw">return(true); } class="type">bool CPriceDeltaZZ::InitIndicators(CIndicators *indicators) { class=class="str">"cmt">//--- initialization of indicator filters if(!CExpertSignal::InitIndicators(indicators)) class="kw">return(class="kw">false); class=class="str">"cmt">//--- creating and initializing of custom indicator if(!InitDeltaZZ(indicators)) class="kw">return(class="kw">false); class=class="str">"cmt">//--- success class="kw">return(true); } class="type">bool CPriceDeltaZZ::InitDeltaZZ(CIndicators *indicators) { class=class="str">"cmt">//--- adds to collection if(!indicators.Add(GetPointer(m_deltazz))) { printf(__FUNCTION__+": error adding object"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- specifies indicator parameters class="type">MqlParam parameters[class="num">6]; class=class="str">"cmt">//--- parameters[class="num">0].type=TYPE_STRING;
把指标缓冲映射成挂单参数
这段实现把自定义指标 deltazigzag.ex5 的 6 个输入参数塞进 parameters 数组,再交给 CPriceDeltaZZ 类去初始化。参数 0 是字符串类型的指标文件名,1~3 与 5 都是 TYPE_INT(价格类型、反转模式、点值、缓冲层数),4 是 TYPE_DOUBLE 的百分比阈值;Create 调用若失败直接返回 false 并打印函数名报错,NumBuffers(5) 则强制指标使用 5 个缓冲。 Prices() 是真正的取值入口:从缓冲 3 读 openbuy、缓冲 4 读 opensell,二者大于 0 才认为有信号。多头挂单价用 NormalizeDouble 按品种小数位对齐,止损取自 getBuySL(),止盈按 m_tp_ratio 乘(开仓价-止损价)推算;空头对称处理,缓冲 1 提供卖单止损。 getBuySL / getSellSL 用 while 从缓冲 0 / 1 向前扫描,遇到非 0 值即返回,等于跳过历史空白柱找最近的有效止损位。外汇与贵金属波动剧烈,这类自动挂单参数仅反映指标最近一根柱的逻辑,实盘前务必在 MT5 策略测试器用真实点差回测验证。
parameters[class="num">0].string_value="deltazigzag.ex5"; parameters[class="num">1].type=TYPE_INT; parameters[class="num">1].integer_value=m_app_price; parameters[class="num">2].type=TYPE_INT; parameters[class="num">2].integer_value=m_rev_mode; parameters[class="num">3].type=TYPE_INT; parameters[class="num">3].integer_value=m_pips; parameters[class="num">4].type=TYPE_DOUBLE; parameters[class="num">4].double_value=m_percent; parameters[class="num">5].type=TYPE_INT; parameters[class="num">5].integer_value=m_levels; class=class="str">"cmt">//--- object initialization if(!m_deltazz.Create(m_symbol.Name(),m_period,IND_CUSTOM,class="num">6,parameters)) { printf(__FUNCTION__+": error initializing object"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- number of the indicator buffers if(!m_deltazz.NumBuffers(class="num">5)) class="kw">return(class="kw">false); class=class="str">"cmt">//--- ок class="kw">return(true); } class="type">class="kw">double CPriceDeltaZZ::Prices(class="type">void) { class="type">class="kw">double openbuy =m_deltazz.GetData(class="num">3,class="num">0);class=class="str">"cmt">//receive the last value from buffer class="num">3 class="type">class="kw">double opensell=m_deltazz.GetData(class="num">4,class="num">0);class=class="str">"cmt">//receive the last value from buffer class="num">4 class=class="str">"cmt">//--- clear parameter values m_order_open_long=EMPTY_VALUE; m_order_stop_long=EMPTY_VALUE; m_order_take_long=EMPTY_VALUE; m_order_expiration_long=class="num">0; m_order_open_short=EMPTY_VALUE; m_order_stop_short=EMPTY_VALUE; m_order_take_short=EMPTY_VALUE; m_order_expiration_short=class="num">0; class="type">int digits=m_symbol.Digits(); class=class="str">"cmt">//--- check for the prices to buy if(openbuy>class="num">0)class=class="str">"cmt">//if buffer class="num">3 is not empty { m_order_open_long=NormalizeDouble(openbuy,digits); m_order_stop_long=NormalizeDouble(getBuySL(),digits); m_order_take_long=NormalizeDouble(m_order_open_long + m_tp_ratio*(m_order_open_long - m_order_stop_long),digits); m_order_expiration_long=calcExpiration(); } class=class="str">"cmt">//--- check for the prices to sell if(opensell>class="num">0)class=class="str">"cmt">//if buffer class="num">4 is not empty { m_order_open_short=NormalizeDouble(opensell,digits); m_order_stop_short=NormalizeDouble(getSellSL(),digits); m_order_take_short=NormalizeDouble(m_order_open_short - m_tp_ratio*(m_order_stop_short - m_order_open_short),digits); m_order_expiration_short=calcExpiration(); } class="kw">return(class="num">0); } class="type">class="kw">double CPriceDeltaZZ::getBuySL(class="type">void) { class="type">int i=class="num">0; class="type">class="kw">double sl=class="num">0.0; while(sl==class="num">0.0) { sl=m_deltazz.GetData(class="num">0,i); i++; } class="kw">return(sl); } class="type">class="kw">double CPriceDeltaZZ::getSellSL(class="type">void) { class="type">int i=class="num">0; class="type">class="kw">double sl=class="num">0.0; while(sl==class="num">0.0) { sl=m_deltazz.GetData(class="num">1,i); i++; } class="kw">return(sl); }
「内柱线模块的双边挂单逻辑」
内柱线指当前根 K 线的最高价和最低价都包在前一根 K 线的高低区间之内,属于纯价格行为形态,不依赖任何指标。它往往暗示原方向动能衰减,价格倾向出现反转或至少一波突破。 当识别到内柱线,模块会依据其极值直接算出向上突破买、向下突破卖两个入场价:突破前高加偏移挂多,跌破前低减偏移挂空。这两个开仓价同时就是反向订单的止损位,止盈则用止损距离乘以设置里的系数(默认 2)得出。 图例中上行趋势下虽未显示卖单成交,但模块仍会生成双向级别;部分止盈位因距离过远超出了可视窗口。该模块算法极简,不需要指标初始化,代码量很少。 Prices() 方法在没有可用信号时返回 EMPTY_VALUE,调用方据此跳过本轮。外汇与贵金属杠杆高,内柱线假突破概率不低,挂单前建议在 MT5 用 10 根 bars 过期参数实测命中率。
class="macro">#include <Expert\ExpertSignalAdvanced.mqh> class=class="str">"cmt">// wizard description start class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Description of the class | class=class="str">"cmt">//| Title=Inside Bar Price Module | class=class="str">"cmt">//| Type=SignalAdvanced | class=class="str">"cmt">//| Name=Inside Bar Price Module | class=class="str">"cmt">//| ShortName=IB_PM | class=class="str">"cmt">//| Class=CPriceInsideBar | class=class="str">"cmt">//| Page=not used | class=class="str">"cmt">//| Parameter=setTpRatio,class="type">class="kw">double,class="num">2,TP:SL ratio | class=class="str">"cmt">//| Parameter=setExpBars,class="type">int,class="num">10,Expiration after bars number | class=class="str">"cmt">//| Parameter=setOrderOffset,class="type">int,class="num">5,Offset for open and stop loss | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">// wizard description end class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Class CPriceInsideBar | class=class="str">"cmt">//| Purpose: Class of the generator of price levels for orders based | class=class="str">"cmt">//| on the "inside bar" pattern. | class=class="str">"cmt">//| Is derived from the CExpertSignalAdvanced class. | class=class="str">"cmt">//+------------------------------------------------------------------+ class CPriceInsideBar : class="kw">public CExpertSignalAdvanced { class="kw">protected: class="type">class="kw">double m_tp_ratio; class=class="str">"cmt">//tp:sl ratio class="type">int m_exp_bars; class=class="str">"cmt">//lifetime of the orders in bars class="type">class="kw">double m_order_offset; class=class="str">"cmt">//shift of the opening and Stop Loss levels class="type">class="kw">datetime calcExpiration() { class="kw">return(TimeCurrent()+m_exp_bars*PeriodSeconds(m_period)); } class="kw">public: CPriceInsideBar();
◍ 母子形态信号的参数闸门与取值
Inside Bar 信号类把几个可调项收进成员函数:止盈比、挂单失效根数、入场偏移点数。setTpRatio 直接写 m_tp_ratio;setExpBars 控 m_exp_bars;setOrderOffset 把 pips 乘上 Point() 转成价格偏移,避免手算小数位出错。 ValidationSettings 先调基类校验,再卡两道硬门槛:m_tp_ratio 必须 >0,否则终端打印「TP Ratio must be greater than zero」并返回 false;m_exp_bars 不能 <0,负过期根数同样驳回。这两处不通过,后续 Prices 根本不会被调用。 Prices 函数从 1 号偏移位取近 2 根 K 的高低:CopyHigh/CopyLow 各取 2 个值,失败返 EMPTY_VALUE。判定母子条的核心是 h[0]>=h[1] && l[0]<=l[1]——即第 1 根完全被第 2 根包容。成立时多头挂单价落在 h[0]+m_order_offset。外汇与贵金属波动跳空频繁,这类包容判定在重大数据前可能连续假触发,实盘前建议在 MT5 用 EURUSD 的 M15 跑一遍打印验证。
~CPriceInsideBar(); class="type">void setTpRatio(class="type">class="kw">double ratio){ m_tp_ratio=ratio; } class="type">void setExpBars(class="type">int bars) { m_exp_bars=bars;} class="type">void setOrderOffset(class="type">int pips){ m_order_offset=m_symbol.Point()*pips;} class="type">bool ValidationSettings(); class="type">class="kw">double Prices(); }; class=class="str">"cmt">//+------------------------------------------------------------------+ CPriceInsideBar::CPriceInsideBar() { } class=class="str">"cmt">//+------------------------------------------------------------------+ CPriceInsideBar::~CPriceInsideBar() { } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CPriceInsideBar::ValidationSettings(class="type">void) { class=class="str">"cmt">//--- verification of the filter parameters if(!CExpertSignal::ValidationSettings()) class="kw">return(class="kw">false); class=class="str">"cmt">//--- initial data check if(m_tp_ratio<=class="num">0) { printf(__FUNCTION__+": TP Ratio must be greater than zero"); class="kw">return(class="kw">false); } if(m_exp_bars<class="num">0) { printf(__FUNCTION__+": Expiration must be zero or positive value"); class="kw">return(class="kw">false); } class=class="str">"cmt">//--- check passed class="kw">return(true); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">class="kw">double CPriceInsideBar::Prices(class="type">void) { class="type">class="kw">double h[class="num">2],l[class="num">2]; if(CopyHigh(m_symbol.Name(),m_period,class="num">1,class="num">2,h)!=class="num">2 || CopyLow(m_symbol.Name(),m_period,class="num">1,class="num">2,l)!=class="num">2) class="kw">return(EMPTY_VALUE); class=class="str">"cmt">//--- check for inside bar if(h[class="num">0] >= h[class="num">1] && l[class="num">0] <= l[class="num">1]) { m_order_open_long=h[class="num">0]+m_order_offset;
多空挂单的止损止盈对称推导
这段逻辑把突破挂单的价位链一次性算完:多单止损取左侧参考价减去偏移量,多单止盈则按开仓价与止损的距离乘以盈亏比 m_tp_ratio 向外推。 空单的处理是镜像的——开仓价直接等于多单止损位,空单止损等于多单开仓价,止盈再按同样比例向内收。这样多空两边的风险敞口在数值上保持对称。 过期时间两个方向共用同一个 calcExpiration() 返回值,避免长短线挂单生命周期不一致。外汇与贵金属杠杆高,这类对称挂单仍可能因跳空触发滑点,实际成交价与计算价可能有偏差,开 MT5 用策略测试器跑一遍更稳妥。
m_order_stop_long=l[class="num">0]-m_order_offset; m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio; m_order_expiration_long=calcExpiration(); m_order_open_short=m_order_stop_long; m_order_stop_short=m_order_open_long; m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio; m_order_expiration_short=m_order_expiration_long; class="kw">return(class="num">0); } class="kw">return(EMPTY_VALUE); } class=class="str">"cmt">//+------------------------------------------------------------------+
「外柱线模块怎么挂双向突破单」
外柱线(Outside Bar)在价格行为里常被称为吞噬柱,特征是当前柱的最高价和最低价完全包住前一根柱的波动区间。它一旦出现,往往意味着接下来一段针对性波动的概率上升,适合在极值外缘布置突破单。 实际落单时,模块会在外柱线的高点上方挂买、低点下方挂卖,两组挂单的开仓价同时互为对方止损。止盈则用止损距离乘以设置里的系数得出,图例中红色水平线是开仓与止损、绿色是止盈。 趋势偏空时可能只留卖单,比如图例 5 里就只生成了向下突破的挂单,逻辑和前一种模块一致,只是 Prices() 方法换了判断条件。 下面这段是核心取价逻辑:先取最近两根 K 线高低价,若当前柱 high≤前柱 high 且 low≥前柱 low 即判定为外柱线,随后算出多空双向的开仓、止损、止盈与有效期。CopyHigh/CopyLow 取不到两根就返回 EMPTY_VALUE,避免误触发。
class="type">class="kw">double CPriceOutsideBar::Prices(class="type">void) { class="type">class="kw">double h[class="num">2],l[class="num">2]; if(CopyHigh(m_symbol.Name(),m_period,class="num">1,class="num">2,h)!=class="num">2 || CopyLow(m_symbol.Name(),m_period,class="num">1,class="num">2,l)!=class="num">2) class="kw">return(EMPTY_VALUE); class=class="str">"cmt">//--- check of outside bar if(h[class="num">0] <= h[class="num">1] && l[class="num">0] >= l[class="num">1]) { m_order_open_long=h[class="num">1]+m_order_offset; m_order_stop_long=l[class="num">1]-m_order_offset; m_order_take_long=m_order_open_long+(m_order_open_long-m_order_stop_long)*m_tp_ratio; m_order_expiration_long=calcExpiration(); m_order_open_short=m_order_stop_long; m_order_stop_short=m_order_open_long; m_order_take_short=m_order_open_short-(m_order_stop_short-m_order_open_short)*m_tp_ratio; m_order_expiration_short=m_order_expiration_long; class="kw">return(class="num">0); } class="kw">return(EMPTY_VALUE); }
◍ 把三个价格模块拆开单独跑一遍
这一节只干一件事:把前面写好的三个价格模块分别挂到 EA 里,验证代码本身能不能独立跑通、有没有逻辑偏差,而不是看谁赚得多。 测试环境是 EURUSD 模拟盘,MetaQuotes-Demo 服务器,周期 2013.01.01–2014.06.01,终端版本 5.00 编译号 965(2014.06.27 版)。动量振荡器模块固定在 H12 做过滤,价格模块跑在 H6;资金管理的固定手数和尾随止损都没开,纯粹测性能。 三个模块依次测:增量之字折线、内柱线、外柱线,各出一张余额图。看内柱线那张图时要清醒——这阶段的目标是查代码毛病,不是找能盈利的策略,曲线平或亏都正常。 每一阶段都把价格区间里的每笔操作扒开核对,没发现策略错误或偏移。文末附了全部程序,你拉进 MT5 自己按同样周期复跑就行,外汇和贵金属模拟测试本身就有高波动风险,别直接上实盘。
向导生成后改代码的几个硬坑
用 MQL5 向导拼 EA 时,模块添加顺序直接决定编译结果是否可控。信号模块(CExpertSignal 的继承者)必须先于价格模块(CExpertSignalAdvanced 的继承者)加入,顺序乱了行为不可预料;本例里先挂动量振荡器做唯一过滤器,再随机塞进三个价格模块(DeltaZZ、内柱线、外柱线)。 向导跑完得到的代码不能直接用。开头要把标准头文件换成高级版:#include <Expert\Expert.mqh> 改为 <Expert\ExpertAdvanced.mqh>,信号对象也要从 CExpertSignal 换成 CExpertSignalAdvanced,否则价格模块权重和索引逻辑不会生效。 模块在代码里按包含次序自动命名,filter0、filter1、filter2 依次排。本例只有一个信号模块,所以第一个价格模块编号是 filter2;要在 m_filters 数组里插入 signal.AddFilter(filter1) 前,先写一句 signal.CalcPriceModuleIndex() 让主信号识别过滤器指向。搜「filter」加数字能快速定位,别凭肉眼找。 删掉开盘缩进、止损止盈、过期等 input 参数串可以瘦身代码,但会引发编译报错,得再删一组连带声明才能过。样例 EA 名叫 TEST_EA_AO_DZZ_IB_OB,注释行可一并清掉。外汇与贵金属杠杆高,实盘前请在 MT5 策略测试器用历史数据验证模块权重。
class="macro">#include <Expert\Expert.mqh> class="macro">#include <Expert\ExpertAdvanced.mqh> CExpert ExtExpert; CExpertAdvanced ExtExpert; CExpertSignal *signal=new CExpertSignal; CExpertSignalAdvanced *signal=new CExpertSignalAdvanced; signal.AddFilter(filter1); signal.CalcPriceModuleIndex(); input class="type">class="kw">double Signal_PriceLevel =class="num">0.0; class=class="str">"cmt">// Price level to execute a deal input class="type">class="kw">double Signal_StopLevel =class="num">50.0; class=class="str">"cmt">// Stop Loss level(in points) input class="type">class="kw">double Signal_TakeLevel =class="num">50.0; class=class="str">"cmt">// Take Profit level(in points) input class="type">int Signal_Expiration =class="num">4; class=class="str">"cmt">// Expiration of pending orders(in bars) signal.PriceLevel(Signal_PriceLevel); signal.StopLevel(Signal_StopLevel); signal.TakeLevel(Signal_TakeLevel); signal.Expiration(Signal_Expiration);
「把这条线请下神坛」
向导生成的 EA 现在能跨价位挂单、带止损止盈,并靠一组价格模块挑最合适的参数组进场;设置里指定的组优先,方向清楚但点位模糊时,它会干等信号出现。目前标准兼容模块只给了三个——pricedeltazz、priceinsidebar、priceoutsidebar,体积分别在 22.93 KB、9.45 KB、9.47 KB,后续数量大概率会扩。 没写过节的人也能基于现成模型改出更进阶的 EA;继承机制是加功能最干净的路子。上面那段 Direction() 判断就是模块选择性生效的开关:返回 EMPTY_VALUE 直接 false,不强行发单。 外汇和贵金属杠杆高、滑点跳空频繁,这种选择性 EA 也只是把“乱枪打鸟”变成“挑位置开枪”,胜率倾向提升但绝不包赢。真要验证,把 mql5_library_extension.zip 里的 mqh 丢进 MT5 的 Include,跑一晚复盘看看拒单率再说。
class="type">class="kw">double direction=Direction(); class=class="str">"cmt">//-- 禁止信号 if(direction==EMPTY_VALUE) class="kw">return(class="kw">false);