MQL5 向导:如何教导 EA 以任意价格建立挂单(基础篇)
📘

MQL5 向导:如何教导 EA 以任意价格建立挂单(基础篇)

第 1/3 篇

让 EA 按指定价位挂单

在 MT5 里写 EA,经常遇到一个朴素需求:不在市价成交,而是让程序在任意给定价位挂限价单或止损单。MQL5 向导生成的框架默认只做市价开仓,要改成交逻辑得手动接 Trade 类的挂单函数。 核心入口是 CTrade::BuyLimit / SellLimit / BuyStop / SellStop,这四个方法允许你把价格参数独立传进去,而不是用 Ask/Bid。比如想在比市价低 50 点的地方挂 buy limit,只需算好目标价再调用一次即可。 外汇与贵金属杠杆高、滑点跳空频繁,挂单未成交前不会被占用保证金,但价格瞬间穿越可能直接市价撮合,实盘前务必在策略测试器用历史数据跑一遍验证触发逻辑。

「固定距离挂单的硬伤」

MQL5 向导直接产出的 EA,挂单只能按离现价的固定点数去摆。市场一变,比如波动率从 12 点跳到 30 点,原来设好的距离立刻不合时宜,EA 只能靠人工重跑并改参数才能继续用。 对多数实战系统这路子走不通。挂单位置本该由策略动态算出来,和现价的间距随时在变,不是写死的数。 这篇要做的,就是改掉向导生成的 EA 里那段写死距离的逻辑,让它按可变距离挂单。你打开 MT5 用向导建个 EA,进 OnTick 看 PlacePendingOrder 的入参,就能看到那个固定距离常量。

◍ 用 Signal_PriceLevel 把市价单改成挂单

MT5 向导生成的 EA 头文件里,Signal_PriceLevel 这个输入参数直接决定了订单以什么价格落地。默认值是 0.0,意味着 EA 按当前市场价直接发单;想让它挂单,就得给这个参数填非零值,正负都行。 填负值代表挂单价格比现价更不利。比如 Signal_PriceLevel=-50,EA 会在离现价 50 点、成交条件更苛刻的位置挂买入止损或卖出止损;填正值则相反,Signal_PriceLevel=50 时挂单位置比现价优 50 点,属于提前埋伏型。 这套逻辑下生成的 EA 只会建立卖出止损和买入止损两类挂单,不会挂限价单。外汇和贵金属杠杆高、滑点大,挂单距离设太近容易被瞬时波动扫掉,实盘前建议在 MT5 策略测试器里把参数调成 ±50 跑一遍验证。 下面这段是向导产出的输入参数声明,逐行看重点:Expert_MagicNumber=3915 是订单识别码;Signal_PriceLevel=0.0 就是前面说的挂单距离开关;Signal_StopLevel=85.0 和 Signal_TakeLevel=195.0 以点为单位的止损止盈;Signal_Expiration=0 表示挂单不按 bars 数过期。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Inputs                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//--- inputs for expert
class="kw">input class="type">class="kw">string      Expert_Title="ExpertMySignalEnvelopes.mq5";      class=class="str">"cmt">// Document name
class="type">class="kw">ulong             Expert_MagicNumber       =class="num">3915;                  class=class="str">"cmt">// 
class="type">bool              Expert_EveryTick         =class="kw">false;                 class=class="str">"cmt">// 
class=class="str">"cmt">//--- inputs for main signal
class="kw">input class="type">int         Signal_ThresholdOpen     =class="num">10;                    class=class="str">"cmt">// Signal threshold value to open [class="num">0...class="num">100]
class="kw">input class="type">int         Signal_ThresholdClose    =class="num">10;                    class=class="str">"cmt">// Signal threshold value to close [class="num">0...class="num">100]
class="kw">input class="type">class="kw">double      Signal_PriceLevel        =class="num">0.0;                   class=class="str">"cmt">// Price level to execute a deal
class="kw">input class="type">class="kw">double      Signal_StopLevel         =class="num">85.0;                  class=class="str">"cmt">// Stop Loss level(in points)
class="kw">input class="type">class="kw">double      Signal_TakeLevel         =class="num">195.0;                 class=class="str">"cmt">// Take Profit level(in points)
class="kw">input class="type">int         Signal_Expiration        =class="num">0;                     class=class="str">"cmt">// Expiration of pending orders(in bars)
class="kw">input class="type">int         Signal_Envelopes_PeriodMA =class="num">13;                   class=class="str">"cmt">// Envelopes(class="num">13,class="num">0,MODE_SMA,...) Period of averaging
class="kw">input class="type">int         Signal_Envelopes_Shift   =class="num">0;                     class=class="str">"cmt">// Envelopes(class="num">13,class="num">0,MODE_SMA,...) Time shift
class="kw">input ENUM_MA_METHOD    Signal_Envelopes_Method   =MODE_SMA;       class=class="str">"cmt">// Envelopes(class="num">13,class="num">0,MODE_SMA,...) Method of averaging
class="kw">input ENUM_APPLIED_PRICE Signal_Envelopes_Applied =PRICE_CLOSE;    class=class="str">"cmt">// Envelopes(class="num">13,class="num">0,MODE_SMA,...) Prices series
class="kw">input class="type">class="kw">double      Signal_Envelopes_Deviation=class="num">0.2;                  class=class="str">"cmt">// Envelopes(class="num">13,class="num">0,MODE_SMA,...) Deviation

信号权重与仓位输入的硬编码点

这段声明集中在 EA 头部,把包络线信号权重和资金管理的两个核心参数直接摊开。Envelopes 权重设成 1.0,意味着该信号在组合里占满额度,若你接了别的过滤器,得把这里压到 0~1 之间重新分配。 Money_FixLot_Percent 给的是 10.0,代表按账户净值 10% 的风险敞口逻辑去算手数;Money_FixLot_Lots 则锁死 0.1 手固定仓。两者并存时,实际生效规则要看后面下单函数怎么二选一,别以为改了百分比就自动生效。 外汇和贵金属杠杆高,10% 净值敞口在欧美波动夜可能直接扫掉止损,上 MT5 把这两行贴进编辑器,先模拟跑一周再动真金。

MQL5 / C++
class="kw">input class="type">class="kw">double Signal_Envelopes_Weight =class="num">1.0; class=class="str">"cmt">// Envelopes(class="num">13,class="num">0,MODE_SMA,...) Weight [class="num">0...class="num">1.0]
class=class="str">"cmt">//--- inputs for money
class="kw">input class="type">class="kw">double Money_FixLot_Percent =class="num">10.0; class=class="str">"cmt">// Percent
class="kw">input class="type">class="kw">double Money_FixLot_Lots =class="num">0.1; class=class="str">"cmt">// Fixed volume

「挂单距离参数落到了哪个变量里」

用 MQL5 向导生成的 EA 里,ExtExpert 是 CExpert 类的全局对象。OnInit() 中先 new 一个 CExpertSignal 的 signal 指针,再走 ExtExpert.InitSignal() 把 signal 初始化,随后通过 signal.PriceLevel() 把外部输入的 Signal_PriceLevel 传进去。 也就是说,你在 EA 属性面板填的「与当前价格距离」,最终并不是散落在全局,而是被塞进了 CExpertSignal 类受保护成员 m_price_level。这个类里还顺带存了 m_stop_level、m_take_level、m_expiration 等,分别对应止损挂单距离、止盈挂单距离和挂单过期棒数。 下面这段是 CExpertSignal 类里相关变量的声明节选,注意 m_price_level 的注释写的是「level of placing a pending orders relatively to the base price」——它相对的是 m_base_price 而非实时 Bid/Ask,回测时若 base price 取值逻辑不同,挂单触发位置可能和你肉眼算的有偏差。外汇与贵金属杠杆交易高风险,参数改动前建议在策略测试器用历史数据验证。

MQL5 / C++
<span class="keyword">class</span> CExpertSignal : <span class="keyword">class="kw">public</span> CExpertBase
&nbsp;&nbsp;{
<span class="keyword">class="kw">protected</span>:
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- variables</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_base_price;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// base price for detection of level of entering(and/or exit?)</span>
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- variables for working with additional filters</span>
&nbsp;&nbsp; CArrayObj&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_filters;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// array of additional filters(maximum number of fileter is class="num">64)</span>
&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">//--- Adjusted parameters</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_weight;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// "weight" of a signal in a combined filter</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_patterns_usage; <span class="comment">class=class="str">"cmt">// bit mask of&nbsp;&nbsp;class="kw">using of the market models of signals</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_general;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// index of the "main" signal(-class="num">1 - no)</span>
&nbsp;&nbsp; <span class="keyword">class="type">long</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_ignore;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// bit mask of "ignoring" the additional filter</span>
&nbsp;&nbsp; <span class="keyword">class="type">long</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_invert;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// bit mask of "inverting" the additional filter</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_threshold_open; <span class="comment">class=class="str">"cmt">// threshold value for opening</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_threshold_close;<span class="comment">class=class="str">"cmt">// threshold level for closing</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_price_level;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// level of placing a pending orders relatively to the base price</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_stop_level;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// level of placing of the "stop loss" order relatively to the open price</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m_take_level;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// level of placing of the "take profit" order relatively to the open price</span>
&nbsp;&nbsp; <span class="keyword">class="type">int</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_expiration;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// time of expiration of a pending order in bars</span>

◍ 向导产出的 EA 骨架长什么样

用 MQL5 向导点出来的 EA,并不是一整块黑盒,而是按功能切开的几层结构。最外层是 Expert Advisor 本体,里面挂着一个 CExpert 基类,它负责把交易策略真正跑起来。 信号这一侧走的是 CExpertSignal 体系:它本身是信号生成器的基类,下面可以挂 filter 0 到 filter n 多个过滤器,每一个都是 CExpertSignal 的派生类。也就是说,你看到的“多个指标共振”在代码里就是一排 filter 对象依次过一遍。 我们这套基于轨道线指标的信号生成器,也是挂在这个 filter 链里的;不过生成器内部的信号逻辑已经被改过,不是向导默认那套。具体改了哪些、为什么改,留到第 7 节拆。外汇与贵金属杠杆高,EA 任何一层逻辑变动都可能放大滑点与回撤,上 MT5 前先想清楚信号优先级。

常见问题

用 Signal_PriceLevel 信号把市价逻辑改成挂单,把挂单距离参数写进对应变量即可,不要依赖固定点差距离。
固定距离不跟波动走,跳空或点差扩大时会错挂;应把距离作为参数输入,由信号模块动态取价。
可以,把EA信号模块贴给小布,它能标出挂单价变量和权重硬编码点,提示你哪些该提成外部参数。
在信号权重与仓位输入部分直接写死,想调仓得改对应输入变量,别在主体里硬改数值。
核心在 Signal_PriceLevel 的信号生成函数,把下单类型从市价换成挂单并填入计算好的挂单价。