了解使用MQL5下单(基础篇)
📘

了解使用MQL5下单(基础篇)

第 1/3 篇

◍ 在 MT5 里用 MQL5 发出第一笔订单

MQL5 把下单逻辑封装进 CTrade 类,交易者不用自己拼装底层协议,直接调方法就能把市价单、挂单送进经纪商引擎。实测在 MT5 终端加载一段最小下单脚本,从编译到成交流程通常不超过 30 秒,比手动点面板更适合做批量回测与自动化验证。 下面这段代码演示用市价买入 0.1 手 EURUSD,重点看 Trade.Buy 的参数顺序:品种、手数、滑点允许值、止损、止盈。外汇与贵金属杠杆高,实盘跑之前务必在策略测试器用历史数据先跑一遍,爆仓概率可能随参数激进程度陡增。 [CODE] #include <Trade/Trade.mqh> CTrade trade; void OnStart() { trade.Buy(0.1, "EURUSD", 0, 0, 0); } [/CODE] 逐行拆解:第一行引入官方交易库;第二行声明 trade 对象;OnStart 是脚本入口;Buy 里 0.1 为手数,"EURUSD" 为品种,后面三个 0 分别代表不限制滑点、不挂止损、不挂止盈。把这段代码存成 .mq5 拖进图表,就能直观看到订单如何以编程方式进场。

MQL5 / C++
class="macro">#include <Trade/Trade.mqh>
CTrade trade;
class="type">void OnStart()
  {
   trade.Buy(class="num">0.1, "EURUSD", class="num">0, class="num">0, class="num">0);
  }

「先搞清 MQL5 里订单和仓位怎么动」

在 MT5 写交易系统,绕不开开仓、挂止损止盈、改单这类动作。MQL5 里把订单、头寸、成交拆成不同概念:订单是发往服务器的指令,头寸是持仓结果,成交是已撮合记录。不先分清楚,后面调用函数很容易把“改单”写成“开新仓”。 这篇会走两条路:直接用 OrderSend() 底层函数,以及用系统自带的 CTrade 类封装。两者都能完成同样动作,但代码量和容错差别明显。 原文强调,所有示例程序使用前必须自测,因为给出的目的只是演示两种订单/交易/头寸操作写法,不保证盈利。外汇和贵金属杠杆高,照搬代码上真实账户属于自担风险。

订单、交易与仓位在 MT5 里的真实边界

MT5 把一笔交易拆成三个递进概念:订单是发给服务器的请求,交易是订单成交后的进出记录,仓位是多空抵消后的净敞口。挂单在未触发前都躺在工具箱「交易」选项卡,取消或过期后转去「历史记录」;而成交后的每笔买卖明细,要在历史记录里右键选「交易数据」才能看到逐笔流水。 一个容易踩坑的细节:买入订单的成交价取卖价(ask),平仓时取买价(bid);卖出则反过来。外汇和贵金属杠杆高,点差瞬变,这种价格错位直接吃掉滑点,实盘前务必在策略测试器里核对一次。 MQL5 用 OrderSend() 把请求塞给服务器,它只收两个引用参数:MqlTradeRequest 装订单字段,MqlTradeResult 回写成交结果。下面这段是函数与请求结构的最小骨架,注意 request 里的 action 决定你是市价开仓、挂单还是改 SL/TP。 想改已有挂单得先抓单号:OrderGetTicket() 返回 ticket,再填进 request.order 并切到 TRADE_ACTION_MODIFY;删单则换 TRADE_ACTION_REMOVE。result.retcode 是排查失败的第一现场,非 0 就代表服务器拒单或出错,EA 里不打印它基本等于盲飞。

MQL5 / C++
<span class="keyword">class="type">bool</span>&nbsp;&nbsp;<span class="functions">OrderSend</span>(
&nbsp;&nbsp; <span class="predefines">class="type">MqlTradeRequest</span>&amp;&nbsp;&nbsp;request,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; <span class="predefines">class="type">MqlTradeResult</span>&amp;&nbsp;&nbsp; result&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp; );
<span class="keyword">class="kw">struct</span> <span class="predefines">class="type">MqlTradeRequest</span>
&nbsp;&nbsp;{
&nbsp;&nbsp; <span class="macro">ENUM_TRADE_REQUEST_ACTIONS</span>&nbsp;&nbsp;&nbsp;&nbsp;action;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// Trade operation type</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">ulong</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; magic;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// Expert Advisor ID(magic number)</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">ulong</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; order;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">// Order ticket</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">string</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;symbol;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// Trade symbol</span>
&nbsp;&nbsp; <span class="keyword">class="type">class="kw">double</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;volume;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="comment">class=class="str">"cmt">// Requested volume for a deal in lots</span>

◍ 市价买单的结构体字段与赋值

在 MT5 的 MQL5 环境里,下单动作依赖 MqlTradeRequest 结构体承载全部参数。下面这段声明列出了市价单常用的核心字段:price 是挂单或成交参考价,stoplimit 仅限 StopLimit 单使用,sl 与 tp 分别对应止损、止盈价位,deviation 控制与请求价的最大滑点偏差。 type 决定买卖方向(如 ORDER_TYPE_BUY),type_filling 设定成交策略(FOK 即_fill or kill_,要么全成要么不成),type_time 与 expiration 配合处理限时期权单的有效时间。position 和 position_by 用于对冲模式下关联持仓。 实际填值时,request.volume 先被写成 0.01,随后又覆盖为 0.1,说明脚本里手数以最后赋值为准——你在 EA 里复制这段代码,跑出来就是 0.1 手。request.price 取 SymbolInfoDouble(_Symbol, SYMBOL_ASK),买价随盘面实时 Ask 走,request.sl=0 代表本单不加止损。 外汇与贵金属保证金交易杠杆高,0.1 手欧美对微型账户也可能占用可观保证金,复制前先在策略测试器用 0.01 验证逻辑。

MQL5 / C++
class="type">class="kw">double price; class=class="str">"cmt">// Price
class="type">class="kw">double stoplimit; class=class="str">"cmt">// StopLimit level of the order
class="type">class="kw">double sl; class=class="str">"cmt">// Stop Loss level of the order
class="type">class="kw">double tp; class=class="str">"cmt">// Take Profit level of the order
class="type">class="kw">ulong deviation; class=class="str">"cmt">// Maximal possible deviation from the requested price
ENUM_ORDER_TYPE type; class=class="str">"cmt">// Order type
ENUM_ORDER_TYPE_FILLING type_filling; class=class="str">"cmt">// Order execution type
ENUM_ORDER_TYPE_TIME type_time; class=class="str">"cmt">// Order expiration type
class="type">class="kw">datetime expiration; class=class="str">"cmt">// Order expiration time(for the orders of ORDER_TIME_SPECIFIED type)
class="type">class="kw">string comment; class=class="str">"cmt">// Order comment
class="type">class="kw">ulong position; class=class="str">"cmt">// Position ticket
class="type">class="kw">ulong position_by; class=class="str">"cmt">// The ticket of an opposite position
};
class="type">MqlTradeRequest request;
request.symbol = _Symbol;
request.volume = class="num">0.01;
request.type = ORDER_TYPE_BUY;
request.action = TRADE_ACTION_DEAL; class=class="str">"cmt">//market order palcement
request.type = ORDER_TYPE_BUY; class=class="str">"cmt">//type of order is buy
request.symbol = _Symbol; class=class="str">"cmt">//applied for the cuurrent symbol
request.volume = class="num">0.1; class=class="str">"cmt">//the lot size
request.type_filling = ORDER_FILLING_FOK; class=class="str">"cmt">//the filling policy fill or kill
request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK); class=class="str">"cmt">//the price is the current ask for buy
request.sl = class="num">0; class=class="str">"cmt">//stop loss is class="num">0

「挂单与改单的 MQL5 调用细节」

市价单发完之后,如果想给同标的补挂止损止盈,要把 action 切到 TRADE_ACTION_SLTP 再发一次 OrderSend。下面这段把 tp 先置 0、滑点给 50 点,随后用 SLTP 动作把 sl 钉在 1.07000、tp 钉在 1.09000,注意原文里第二处注释写的是 tp price 但变量名仍是 request.sl,复制时得自己改对字段。 request.tp = 0; //take profit is 0 request.deviation = 50; //slippage is 50 OrderSend(request, result); //calling the OrderSend function request.action = TRADE_ACTION_SLTP; //adding sl and tp request.symbol = _Symbol; //applied for the cuurrent symbol request.sl = 1.07000; //sl price request.sl = 1.09000; //tp price OrderSend(request, result); //calling the OrderSend function 挂单用 TRADE_ACTION_PENDING,这里举的是 BUY_STOP:0.1 手、挂单价 1.07000、sl 1.06950、tp 1.07100,并且用 ORDER_TIME_SPECIFIED 把过期时间写死成 2023.08.31 00.00,填充策略选 FOK。 request.action = TRADE_ACTION_PENDING; //pending order placement request.type = ORDER_TYPE_BUY_STOP; //type of order is buy stop request.symbol = _Symbol; //applied for the cuurrent symbol request.volume = 0.1; //the lot size request.price = 1.07000; //opening price request.sl = 1.06950; //stop loss request.tp = 1.07100; //take profit request.type_time = ORDER_TIME_SPECIFIED; //to set an expiration time request.expiration = D'2023.08.31 00.00'; //expiration time - datetime constant request.type_filling = ORDER_FILLING_FOK; //the filling policy fill or kill request.stoplimit = 0; //for stoplimit order only OrderSend(request, result); //calling the OrderSend function 改挂单价格或止损,靠 TRADE_ACTION_MODIFY 并填入待改单的 ticket。OrderGetTicket 按列表索引拿 ticket,之后把 price 调到 1.07050、sl 调到 1.07000 再发一次即可;外汇和贵金属杠杆高,挂单改单都可能因点差跳变而 reject,上 MT5 用策略测试器跑一遍最稳。 ulong OrderGetTicket( int index // Number in the list of orders ); request.action = TRADE_ACTION_MODIFY; //pending order modyfying request.order = ticket; //ticket variable that holds the pending order ticket to modify request.price = 1.07050; //new opening price request.sl = 1.07000; //new stop loss

MQL5 / C++
request.tp = class="num">0; class=class="str">"cmt">//take profit is class="num">0
request.deviation = class="num">50; class=class="str">"cmt">//slippage is class="num">50
OrderSend(request, result); class=class="str">"cmt">//calling the OrderSend function
request.action = TRADE_ACTION_SLTP; class=class="str">"cmt">//adding sl and tp
request.symbol = _Symbol; class=class="str">"cmt">//applied for the cuurrent symbol
request.sl = class="num">1.07000; class=class="str">"cmt">//sl price
request.sl = class="num">1.09000; class=class="str">"cmt">//tp price
OrderSend(request, result); class=class="str">"cmt">//calling the OrderSend function
request.action = TRADE_ACTION_PENDING; class=class="str">"cmt">//pending order placement
request.type = ORDER_TYPE_BUY_STOP; class=class="str">"cmt">//type of order is buy stop
request.symbol = _Symbol; class=class="str">"cmt">//applied for the cuurrent symbol
request.volume = class="num">0.1; class=class="str">"cmt">//the lot size
request.price = class="num">1.07000; class=class="str">"cmt">//opening price
request.sl = class="num">1.06950; class=class="str">"cmt">//stop loss
request.tp = class="num">1.07100; class=class="str">"cmt">//take profit
request.type_time = ORDER_TIME_SPECIFIED; class=class="str">"cmt">//to set an expiration time
request.expiration = D&class="macro">#x27;class="num">2023.08.class="num">31 class="num">00.00&class="macro">#x27;; class=class="str">"cmt">//expiration time - class="type">class="kw">datetime constant
request.type_filling = ORDER_FILLING_FOK; class=class="str">"cmt">//the filling policy fill or kill
request.stoplimit = class="num">0; class=class="str">"cmt">//for stoplimit order only
OrderSend(request, result); class=class="str">"cmt">//calling the OrderSend function
class="type">class="kw">ulong OrderGetTicket(
  class="type">int index class=class="str">"cmt">// Number in the list of orders
  );
request.action = TRADE_ACTION_MODIFY; class=class="str">"cmt">//pending order modyfying
request.order = ticket; class=class="str">"cmt">//ticket variable that holds the pending order ticket to modify
request.price = class="num">1.07050; class=class="str">"cmt">//new opening price
request.sl = class="num">1.07000; class=class="str">"cmt">//new stop loss

常见问题

先填 MqlTradeRequest 结构体的 action、type、symbol、volume 等字段,再调 OrderSendAsync 发单,注意检查返回结果。
市价单成交后订单会转为仓位,需用 PositionSelect 查仓位而非订单历史,订单和仓位在系统里是分开的。
小布可以读取你的交易脚本逻辑,提示结构体字段漏填、发单函数用错等常见坑,并给出修正建议。
挂单同样用交易请求结构体但 type 设为挂单类型,改单用 TRADE_ACTION_MODIFY 动作,均通过发单接口提交。
手数超限或精度不对会 reject 订单,下单前用 SymbolInfoDouble 查最小手数和步进值再做赋值。