延后交易请求对象类:用基类与衍生类搭好函数库扩展骨架(基础篇)
(1/3)· 直接把延后请求逻辑写进交易类只是验证概念,包装成规范对象才能持续扩展
延后交易请求的基类该怎么搭
在 MT5 里做延后交易请求,第一步是把「请求」抽象成一个对象,而不是在 EA 里到处写 OrderSendAsync 的散代码。原文给出的思路是先建一个基准对象类,把所有请求共有的字段(品种、方向、手数、挂单触发价等)和状态机收进去。 在这个基类之上,再派生出具体请求类型,比如市价单、挂单、改单、撤单。这样主程序只管「扔一个请求对象进队列」,真正发往交易服务器的时机由调度器在空闲时批量或延后处理。 作者在 2020 年 3 月 16 日发布的示例里,随文附带了可运行的库代码,原文页面显示浏览量 3127、评论 2 条,说明这套结构至少经得起初级社区验证。外汇与贵金属杠杆交易风险高,延后机制并不能消除滑点与拒单概率,只是把请求生命周期可控化。 实际落地时,先开 MT5 用 MetaEditor 新建一个 CTradeRequest 基类,把异步发送和回执绑定到对象 ID 上,比直接调交易函数更容易排查「请求丢了但账户没动」的老问题。
「延后请求的对象化拆分思路」
延后请求本质就是带触发条件的普通交易单:服务器报错需要等待重发时,由交易类检查延迟发送条件。触发条件不限于时间,也可以是价位触及或品种属性阈值组合,stoplimit 挂单就是典型——价格碰止盈位后下一笔限价单。 之前为了快速验证概念,处理延后请求的代码直接堆在交易类里,现在要收进函数库对象体系,才能方便扩展新属性。做法是抽象出基准请求基类,承载所有交易请求共有的字段,再派生六个子类按操作类型厘清独有状态。 六个派生对象对应:开仓(对冲账户新仓、净持账户加仓冲抵)、改持仓止价、平仓(全平/部分/逆向单)、下挂单、改挂单属性、删挂单。这样分层后,新增请求类型只需挂到基类下面。 先在 Datas.mqh 里补一组消息索引和对应文本,下面这段就是本次新增的库消息片段,注意 MSG_LIB_TEXT_PEND_REQUEST_STATUS 系列是后续状态机要用的。
MSG_LIB_TEXT_AND_PAUSE, class=class="str">"cmt">// and pause MSG_LIB_TEXT_ALREADY_EXISTS, class=class="str">"cmt">// already exists MSG_LIB_TEXT_CREATED, class=class="str">"cmt">// Created MSG_LIB_TEXT_ATTEMPTS, class=class="str">"cmt">// Attempts MSG_LIB_TEXT_WAIT, class=class="str">"cmt">// Wait MSG_LIB_TEXT_END, class=class="str">"cmt">// End MSG_LIB_TEXT_REQUEST, class=class="str">"cmt">// Pending request # MSG_LIB_TEXT_REQUEST_DATAS, class=class="str">"cmt">// Trading request parameters MSG_LIB_TEXT_PEND_REQUEST_DATAS, class=class="str">"cmt">// Pending trading request parameters MSG_LIB_TEXT_PEND_REQUEST_BY_ERROR, class=class="str">"cmt">// Pending request generated based on the server class="kw">return code MSG_LIB_TEXT_PEND_REQUEST_BY_REQUEST, class=class="str">"cmt">// Pending request created by request MSG_LIB_TEXT_PEND_REQUEST_WAITING_ONSET, class=class="str">"cmt">// Wait for the first trading attempt MSG_LIB_TEXT_PEND_REQUEST_STATUS, class=class="str">"cmt">// Pending request status MSG_LIB_TEXT_PEND_REQUEST_STATUS_OPEN, class=class="str">"cmt">// Pending request to open a position MSG_LIB_TEXT_PEND_REQUEST_STATUS_CLOSE, class=class="str">"cmt">// Pending request to close a position MSG_LIB_TEXT_PEND_REQUEST_STATUS_SLTP, class=class="str">"cmt">// Pending request to modify position stop orders MSG_LIB_TEXT_PEND_REQUEST_STATUS_PLACE, class=class="str">"cmt">// Pending request to place a pending order MSG_LIB_TEXT_PEND_REQUEST_STATUS_REMOVE, class=class="str">"cmt">// Pending request to class="kw">delete a pending order MSG_LIB_TEXT_PEND_REQUEST_STATUS_MODIFY, class=class="str">"cmt">// Pending request to modify pending order parameters }; {" и паузой "," and pause "}, {" уже существует"," already exists"}, {"Создан","Created"}, {"Попыток","Attempts"}, {"Ожидание","Wait"},
◍ 枚举本地化里的挂单请求状态
在 MQL5 的枚举本地化数组里,有一组专门描述交易请求与挂起请求(pending request)的中英双字串。上面这段代码片段列出了从「End」到「Pending request to modify pending order parameters」共 14 个条目,其中带浅绿底色的 9 条是挂起请求相关状态,包括挂单开仓、平仓、改止损、放挂单、删挂单、改挂单参数等。 这些字串本质是为 ENUM_TRADE_REQUEST_TYPE 或类似枚举做界面显示用的多语言映射,俄语原文在前、英语在后。你在写 EA 的日志模块或面板时,直接引用这类数组可以避免硬编中文,但注意 MT5 终端默认只认英文字串,俄语那列在海外券商环境里大概率显示乱码。 验证方式很简单:把上面数组贴进 MetaEditor,编译一个空脚本用 Print() 轮询输出,能在专家日志里看到 14 行双语言文本即说明结构无误。外汇与贵金属交易本身杠杆高、滑点大,这类状态机若处理不当,挂单可能在极端波动中重复触发,实际成交概率会偏离预期。
{ "Окончание","End"},
{ "Отложенный запрос #","Pending request #"},
{ "Параметры торгового запроса","Trade request parameters"},
{ "Параметры отложенного торгового запроса","Pending trade request parameters"},
{ "Отложенный запрос, созданный по коду возврата сервера","Pending request created as a result of server code"},
{ "Отложенный запрос, созданный по запросу","Pending request created by request"},
{ "Ожидание наступления времени первой торговой попытки","Waiting for onset time of the first trading attempt"},
{ "Статус отложенного запроса","Pending request status"},
{ "Отложенный запрос на открытие позиции","Pending request to open position"},
{ "Отложенный запрос на закрытие позиции","Pending request to close position"},
{ "Отложенный запрос на модификацию стоп-приказов позиции","Pending request to modify position stop orders"},
{ "Отложенный запрос на установку отложенного ордера","Pending request to place pending order"},
{ "Отложенный запрос на удаление отложенного ордера","Pending request to remove pending order"},
{ "Отложенный запрос на модификацию параметров отложенного ордера","Pending request to modify pending order parameters"},
};延后请求基准类的属性映射与比较机制
在 DoEasy 函数库里,延后交易请求对象沿用了此前所有库对象的属性存储方式:用三个平行数组分别装整数、实数和字符串型字段。这样做的目的很直接——把 MqlTradeRequest 结构里的全部参数原样搬进对象属性,之后就能按任意字段在列表里排序或检索,不用每次都解析原始请求结构。 对象状态枚举 ENUM_PEND_REQ_STATUS 定义了 6 种延后请求去向:开仓、平仓、改持仓止损止盈、挂单、删挂单、改挂单。配合 ENUM_PEND_REQ_TYPE 区分是基于错误返回码生成的,还是主动按请求生成的。这两个枚举写在 Defines.mqh 中,宏替换负责算各类型属性在数组里的偏移索引。 比较逻辑分两层。Compare() 按指定属性比对当前对象和传入对象,当前值大返回 1、小返回 -1、相等返回 0,供标准库 CObject 的 Search() 虚方法调用;IsEqual() 则跑完三个属性数组的逐字段循环,任一对不上立刻返回 false,全过完才返回 true。 构造函数里先调 CopyRequest() 把交易请求结构灌进属性数组,再设对冲账户标志和品种报价、手数的小数位。手数小数位若为 0,则日志里强制显示成“1.0”而不是“1”,纯粹为了可读性。Print() 在三重循环里吐出全部属性描述,PrintShort() 留成虚方法交给六个后代类各自重写,基准类里不做事。 这套抽象基类本身不落地具体请求,后续要基于它派生六个后代分别对应上面六种状态。处理交易报错等待重试时,以及手写延后交易逻辑时,都是这些后代对象在被实例化。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Data for working with pending trading requests | class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Pending request status | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_PEND_REQ_STATUS { PEND_REQ_STATUS_OPEN, class=class="str">"cmt">// Pending request to open a position PEND_REQ_STATUS_CLOSE, class=class="str">"cmt">// Pending request to close a position PEND_REQ_STATUS_SLTP, class=class="str">"cmt">// Pending request to modify open position stop orders PEND_REQ_STATUS_PLACE, class=class="str">"cmt">// Pending request to place a pending order PEND_REQ_STATUS_REMOVE, class=class="str">"cmt">// Pending request to class="kw">delete a pending order PEND_REQ_STATUS_MODIFY class=class="str">"cmt">// Pending request to modify a placed pending order }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Pending request type | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_PEND_REQ_TYPE { PEND_REQ_TYPE_ERROR=PENDING_REQUEST_ID_TYPE_ERR, class=class="str">"cmt">// Pending request created based on the class="kw">return code or error PEND_REQ_TYPE_REQUEST=PENDING_REQUEST_ID_TYPE_REQ, class=class="str">"cmt">// Pending request created by request };
「挂单请求的整数属性枚举怎么读」
在 MT5 的 pending trading request 体系里,所有整数类字段都被收进一个枚举 ENUM_PEND_REQ_PROP_INTEGER,方便用统一接口按 ID 取状态。 枚举第一个成员 PEND_REQ_PROP_STATUS = 0 是请求状态,对应 ENUM_PEND_REQ_STATUS;随后 PEND_REQ_PROP_TYPE 是请求类型,PEND_REQ_PROP_ID 是请求自身 ID,PEND_REQ_PROP_RETCODE 记录该请求基于的服务器返回码。 时间维度上有三个关键项:PEND_REQ_PROP_TIME_CREATE 是创建时间,PEND_REQ_PROP_TIME_ACTIVATE 是下一次激活尝试时间,PEND_REQ_PROP_WAITING 是两次尝试之间的等待毫秒数。重试控制靠 PEND_REQ_PROP_CURENT(当前第几次尝试)和 PEND_REQ_PROP_TOTAL(总尝试次数)两个字段。 从 PEND_REQ_PROP_MQL_REQ_ACTION 开始,枚举映射的是 MqlTradeRequest 结构体内的整数成员,包括动作类型、订单类型、magic、订单 ticket、持仓 ticket、反向持仓 ticket、最大滑点偏差、 expiry 时间以及填单方式。把这些常量直接喂给 PendReqGetInteger(),就能在 EA 里轮询挂单请求的真实进度。外汇与贵金属交易杠杆高,请求状态异常可能瞬间放大亏损,验证代码前先在策略测试器跑历史数据。
enum ENUM_PEND_REQ_PROP_INTEGER { PEND_REQ_PROP_STATUS = class="num">0, class=class="str">"cmt">// Trading request status(from the ENUM_PEND_REQ_STATUS enumeration) PEND_REQ_PROP_TYPE, class=class="str">"cmt">// Trading request type(from the ENUM_PEND_REQ_TYPE enumeration) PEND_REQ_PROP_ID, class=class="str">"cmt">// Trading request ID PEND_REQ_PROP_RETCODE, class=class="str">"cmt">// Result a request is based on PEND_REQ_PROP_TIME_CREATE, class=class="str">"cmt">// Request creation time PEND_REQ_PROP_TIME_ACTIVATE, class=class="str">"cmt">// Next attempt activation time PEND_REQ_PROP_WAITING, class=class="str">"cmt">// Waiting time between requests PEND_REQ_PROP_CURENT, class=class="str">"cmt">// Current attempt index PEND_REQ_PROP_TOTAL, class=class="str">"cmt">// Number of attempts class=class="str">"cmt">//--- class="type">MqlTradeRequest PEND_REQ_PROP_MQL_REQ_ACTION, class=class="str">"cmt">// Type of a performed action in the request structure PEND_REQ_PROP_MQL_REQ_TYPE, class=class="str">"cmt">// Order type in the request structure PEND_REQ_PROP_MQL_REQ_MAGIC, class=class="str">"cmt">// EA stamp(magic number ID) in the request structure PEND_REQ_PROP_MQL_REQ_ORDER, class=class="str">"cmt">// Order ticket in the request structure PEND_REQ_PROP_MQL_REQ_POSITION, class=class="str">"cmt">// Position ticket in the request structure PEND_REQ_PROP_MQL_REQ_POSITION_BY, class=class="str">"cmt">// Opposite position ticket in the request structure PEND_REQ_PROP_MQL_REQ_DEVIATION, class=class="str">"cmt">// Maximum acceptable deviation from a requested price in the request structure PEND_REQ_PROP_MQL_REQ_EXPIRATION, class=class="str">"cmt">// Order expiration time(for ORDER_TIME_SPECIFIED type orders) in the request structure PEND_REQ_PROP_MQL_REQ_TYPE_FILLING class=class="str">"cmt">// Order filling type in the request structure };
◍ 挂单请求的属性枚举怎么排
在 MT5 里把挂单请求抽象成可排序的结构时,整数、双精度、字符串三类属性是分开枚举的。整数属性共 19 个(PEND_REQ_PROP_INTEGER_TOTAL 定义为 19),其中跳过排序的为 0;双精度属性从整数总数之后接续编号,共 6 个;字符串属性则接着整数与双精度总数之后排,共 2 个。 这种偏移式编号意味着:PEND_REQ_PROP_PRICE_CREATE 的值就是 19,PEND_REQ_PROP_MQL_REQ_SYMBOL 的值是 19+6=25。开 MT5 新建一个 enum 测试,打印这两个宏,能直接验证序号连续性。 外汇与贵金属挂单受点差和滑点影响,枚举里的 SL、TP、StopLimit 都是请求时的静态值,实际成交价可能偏离,属正常高风险现象。
PEND_REQ_PROP_MQL_REQ_TYPE_TIME, class=class="str">"cmt">// Order lifetime type in the request structure }; class="macro">#define PEND_REQ_PROP_INTEGER_TOTAL(class="num">19) class=class="str">"cmt">// Total number of integer event properties class="macro">#define PEND_REQ_PROP_INTEGER_SKIP(class="num">0) class=class="str">"cmt">// Number of request properties not used in sorting class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Real properties of a pending trading request | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_DOUBLE { PEND_REQ_PROP_PRICE_CREATE = PEND_REQ_PROP_INTEGER_TOTAL,class=class="str">"cmt">// Price at the moment of a request generation class=class="str">"cmt">//--- class="type">MqlTradeRequest PEND_REQ_PROP_MQL_REQ_VOLUME, class=class="str">"cmt">// Requested volume of a deal in lots in the request structure PEND_REQ_PROP_MQL_REQ_PRICE, class=class="str">"cmt">// Price in the request structure PEND_REQ_PROP_MQL_REQ_STOPLIMIT, class=class="str">"cmt">// StopLimit level in the request structure PEND_REQ_PROP_MQL_REQ_SL, class=class="str">"cmt">// Stop Loss level in the request structure PEND_REQ_PROP_MQL_REQ_TP, class=class="str">"cmt">// Take Profit level in the request structure }; class="macro">#define PEND_REQ_PROP_DOUBLE_TOTAL(class="num">6) class=class="str">"cmt">// Total number of event&class="macro">#x27;s real properties class="macro">#define PEND_REQ_PROP_DOUBLE_SKIP(class="num">0) class=class="str">"cmt">// Number of order properties not used in sorting class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| String properties of a pending trading request | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_PEND_REQ_PROP_STRING { class=class="str">"cmt">//--- class="type">MqlTradeRequest PEND_REQ_PROP_MQL_REQ_SYMBOL = (PEND_REQ_PROP_INTEGER_TOTAL+PEND_REQ_PROP_DOUBLE_TOTAL), class=class="str">"cmt">// Trading instrument name in the request structure PEND_REQ_PROP_MQL_REQ_COMMENT class=class="str">"cmt">// Order comment in the request structure }; class="macro">#define PEND_REQ_PROP_STRING_TOTAL(class="num">2) class=class="str">"cmt">// Total number of event&class="macro">#x27;s class="type">class="kw">string properties class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Possible pending request sorting criteria | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define FIRST_PREQ_DBL_PROP(PEND_REQ_PROP_INTEGER_TOTAL-PEND_REQ_PROP_INTEGER_SKIP)