MQL5 向导:如何教导 EA 以任意价格建立挂单(基础篇)
让 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 数过期。
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 把这两行贴进编辑器,先模拟跑一周再动真金。
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 取值逻辑不同,挂单触发位置可能和你肉眼算的有偏差。外汇与贵金属杠杆交易高风险,参数改动前建议在策略测试器用历史数据验证。
<span class="keyword">class</span> CExpertSignal : <span class="keyword">class="kw">public</span> CExpertBase { <span class="keyword">class="kw">protected</span>: <span class="comment">class=class="str">"cmt">//--- variables</span> <span class="keyword">class="type">class="kw">double</span> m_base_price; <span class="comment">class=class="str">"cmt">// base price for detection of level of entering(and/or exit?)</span> <span class="comment">class=class="str">"cmt">//--- variables for working with additional filters</span> CArrayObj m_filters; <span class="comment">class=class="str">"cmt">// array of additional filters(maximum number of fileter is class="num">64)</span> <span class="comment">class=class="str">"cmt">//--- Adjusted parameters</span> <span class="keyword">class="type">class="kw">double</span> m_weight; <span class="comment">class=class="str">"cmt">// "weight" of a signal in a combined filter</span> <span class="keyword">class="type">int</span> m_patterns_usage; <span class="comment">class=class="str">"cmt">// bit mask of class="kw">using of the market models of signals</span> <span class="keyword">class="type">int</span> m_general; <span class="comment">class=class="str">"cmt">// index of the "main" signal(-class="num">1 - no)</span> <span class="keyword">class="type">long</span> m_ignore; <span class="comment">class=class="str">"cmt">// bit mask of "ignoring" the additional filter</span> <span class="keyword">class="type">long</span> m_invert; <span class="comment">class=class="str">"cmt">// bit mask of "inverting" the additional filter</span> <span class="keyword">class="type">int</span> m_threshold_open; <span class="comment">class=class="str">"cmt">// threshold value for opening</span> <span class="keyword">class="type">int</span> m_threshold_close;<span class="comment">class=class="str">"cmt">// threshold level for closing</span> <span class="keyword">class="type">class="kw">double</span> m_price_level; <span class="comment">class=class="str">"cmt">// level of placing a pending orders relatively to the base price</span> <span class="keyword">class="type">class="kw">double</span> m_stop_level; <span class="comment">class=class="str">"cmt">// level of placing of the "stop loss" order relatively to the open price</span> <span class="keyword">class="type">class="kw">double</span> m_take_level; <span class="comment">class=class="str">"cmt">// level of placing of the "take profit" order relatively to the open price</span> <span class="keyword">class="type">int</span> m_expiration; <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 前先想清楚信号优先级。