延后交易请求对象类:用基类与衍生类搭好函数库扩展骨架(基础篇)
🧱

延后交易请求对象类:用基类与衍生类搭好函数库扩展骨架(基础篇)

(1/3)· 直接把延后请求逻辑写进交易类只是验证概念,包装成规范对象才能持续扩展

含代码示例偏理论 第 1/3 篇
把延后请求的处理代码直接堆在交易类里,初期能跑通,但后续加新属性就会牵一发而动全身。很多人验证完概念就接着写业务,结果对象无法复用。先把基准对象和衍生对象拆清楚,才是函数库该有的写法。

延后交易请求的基类该怎么搭

在 MT5 里做延后交易请求,第一步是把「请求」抽象成一个对象,而不是在 EA 里到处写 OrderSendAsync 的散代码。原文给出的思路是先建一个基准对象类,把所有请求共有的字段(品种、方向、手数、挂单触发价等)和状态机收进去。 在这个基类之上,再派生出具体请求类型,比如市价单、挂单、改单、撤单。这样主程序只管「扔一个请求对象进队列」,真正发往交易服务器的时机由调度器在空闲时批量或延后处理。 作者在 2020 年 3 月 16 日发布的示例里,随文附带了可运行的库代码,原文页面显示浏览量 3127、评论 2 条,说明这套结构至少经得起初级社区验证。外汇与贵金属杠杆交易风险高,延后机制并不能消除滑点与拒单概率,只是把请求生命周期可控化。 实际落地时,先开 MT5 用 MetaEditor 新建一个 CTradeRequest 基类,把异步发送和回执绑定到对象 ID 上,比直接调交易函数更容易排查「请求丢了但账户没动」的老问题。

「延后请求的对象化拆分思路」

延后请求本质就是带触发条件的普通交易单:服务器报错需要等待重发时,由交易类检查延迟发送条件。触发条件不限于时间,也可以是价位触及或品种属性阈值组合,stoplimit 挂单就是典型——价格碰止盈位后下一笔限价单。 之前为了快速验证概念,处理延后请求的代码直接堆在交易类里,现在要收进函数库对象体系,才能方便扩展新属性。做法是抽象出基准请求基类,承载所有交易请求共有的字段,再派生六个子类按操作类型厘清独有状态。 六个派生对象对应:开仓(对冲账户新仓、净持账户加仓冲抵)、改持仓止价、平仓(全平/部分/逆向单)、下挂单、改挂单属性、删挂单。这样分层后,新增请求类型只需挂到基类下面。 先在 Datas.mqh 里补一组消息索引和对应文本,下面这段就是本次新增的库消息片段,注意 MSG_LIB_TEXT_PEND_REQUEST_STATUS 系列是后续状态机要用的。

MQL5 / C++
  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 行双语言文本即说明结构无误。外汇与贵金属交易本身杠杆高、滑点大,这类状态机若处理不当,挂单可能在极端波动中重复触发,实际成交概率会偏离预期。

MQL5 / C++
{ "Окончание","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() 留成虚方法交给六个后代类各自重写,基准类里不做事。 这套抽象基类本身不落地具体请求,后续要基于它派生六个后代分别对应上面六种状态。处理交易报错等待重试时,以及手写延后交易逻辑时,都是这些后代对象在被实例化。

MQL5 / C++
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 里轮询挂单请求的真实进度。外汇与贵金属交易杠杆高,请求状态异常可能瞬间放大亏损,验证代码前先在策略测试器跑历史数据。

MQL5 / C++
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 都是请求时的静态值,实际成交价可能偏离,属正常高风险现象。

MQL5 / C++
  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)
把对象结构交给小布盯盘辅助核对
这些对象基类和衍生类的属性划分逻辑,小布盯盘的 AIGC 已内置结构检查,打开对应品种页即可比对你的实现是否偏离函数库规范。

常见问题

延后请求是由特定条件触发执行的正常订单,条件可以是价位触及、品种属性阈值等,例如 stoplimit 挂单在价格触止后下限定单。
直接写进交易类仅为快速验证概念,违背函数库对象常规概念,难以扩展新属性,应抽成基准对象与衍生对象。
可以,小布盯盘内置了函数库对象结构比对,能提示你的基类与衍生类属性划分是否规范,减少手动核对的遗漏。
按交易操作类型分六种衍生:开仓、改持仓止价、平仓、下挂单、改挂单属性、删挂单,基准对象只放共有属性。
Datas.mqh 写入新函数库消息索引与对应文本,Defines.mqh 加入对象状态枚举及整型实型字符串属性宏替换。