轻松快捷开发 MetaTrader 程序的函数库(第 二十五部分):处理交易服务器返回的错误·进阶篇
🔁

轻松快捷开发 MetaTrader 程序的函数库(第 二十五部分):处理交易服务器返回的错误·进阶篇

(2/3)· 发送订单后服务器甩回的 6 类回执,怎样用循环重发和参数纠正自动消化

实战向 第 2/3 篇
很多人把 OrderSend 的返回值只当作成功或失败,遇到 FreezeLevel 禁改、停止单激活就手动重试。其实服务器回执里大半错误都能在库内自动分类、纠正并重发,不必每次在 EA 主逻辑里写一堆 if。

◍ 交易库底层宏与错误枚举的落地定义

在 MT5 自建交易库时,先固定一批全局宏ID能省掉后续不少乱码式报错。下面这组常量把行情、事件、账户、品种四个集合的标识锁在 0x777A–0x777D,文件目录统一收进 DoEasy\ 与 DoEasy\Resource\,品种默认处理上限给到 1000 个,这些数字直接决定后续数组开多大。 错误分支用两个枚举管住:ENUM_TRADE_REQUEST_ERR_FLAGS 里 0 是无错,1 和 2 是致命/内部错要直接退出 EA,4 进列表错交给你自己处理,8 和 16 分别卡住挂单价格和限价单价格偏差。ENUM_ERROR_CODE_PROCESSING_METHOD 则只列了 OK 和 DISABLE 两态,对应“继续”和“给 EA 断交易”两种走向。 把宏原样贴进 mqh 头文件,MT5 里编译后若 COLLECTION_SYMBOLS_ID 取不到品种,先查 SYMBOLS_COMMON_TOTAL 是否小于你观测池数量——外汇与贵金属波动剧烈,这类底层上限设错会放大实盘风险。

MQL5 / C++
class="macro">#define COLLECTION_MARKET_ID(0x777A)                 class=class="str">"cmt">// Market collection list ID
class="macro">#define COLLECTION_EVENTS_ID(0x777B)                 class=class="str">"cmt">// Event collection list ID
class="macro">#define COLLECTION_ACCOUNT_ID(0x777C)                 class=class="str">"cmt">// Account collection list ID
class="macro">#define COLLECTION_SYMBOLS_ID(0x777D)                 class=class="str">"cmt">// Symbol collection list ID
class=class="str">"cmt">//--- Data parameters for file operations
class="macro">#define DIRECTORY("DoEasy\")             class=class="str">"cmt">// Library directory for storing object folders
class="macro">#define RESOURCE_DIR("DoEasy\\Resource\\")  class=class="str">"cmt">// Library directory for storing resource folders
class=class="str">"cmt">//--- Symbol parameters
class="macro">#define CLR_DEFAULT(0xFF000000)             class=class="str">"cmt">// Default class="type">class="kw">color
class="macro">#define SYMBOLS_COMMON_TOTAL(class="num">1000)                   class=class="str">"cmt">// Total number of working symbols
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Flags indicating the trading request error handling methods       |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_TRADE_REQUEST_ERR_FLAGS
  {
   TRADE_REQUEST_ERR_FLAG_NO_ERROR                   =  class="num">0,     class=class="str">"cmt">// No error
   TRADE_REQUEST_ERR_FLAG_FATAL_ERROR                =  class="num">1,     class=class="str">"cmt">// Disable trading for an EA(critical error) - exit
   TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR               =  class="num">2,     class=class="str">"cmt">// Library internal error - exit
   TRADE_REQUEST_ERR_FLAG_ERROR_IN_LIST              =  class="num">4,     class=class="str">"cmt">// Error in the list - handle(ENUM_ERROR_CODE_PROCESSING_METHOD)
   TRADE_REQUEST_ERR_FLAG_PRICE_ERROR                =  class="num">8,     class=class="str">"cmt">// Placement price error
   TRADE_REQUEST_ERR_FLAG_LIMIT_ERROR                =  class="num">16,    class=class="str">"cmt">// Limit order price error
   };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| The methods of handling errors and server class="kw">return codes            |
class=class="str">"cmt">//+------------------------------------------------------------------+
enum ENUM_ERROR_CODE_PROCESSING_METHOD
  {
   ERROR_CODE_PROCESSING_METHOD_OK,                                class=class="str">"cmt">// No errors
   ERROR_CODE_PROCESSING_METHOD_DISABLE,                           class=class="str">"cmt">// Disable trading for the EA
   };

「错误分支与报文的枚举定义细节」

在封装交易类库时,错误处理通常先用一个枚举区分「下一步怎么做」。下面这组分支覆盖了退出、改参重发、刷新重发、挂单、等待重发五种走向,实盘里最常被触发的是 CORRECT 与 REFRESH 两类。 ERROR_CODE_PROCESSING_METHOD_EXIT 表示直接终止交易方法;ERROR_CODE_PROCESSING_METHOD_CORRECT 要求修正下单参数后重发;ERROR_CODE_PROCESSING_METHOD_REFRESH 则是更新行情或账户数据后再试;PENDING 用于转挂单,WAIT 用于延时重试。 另一组 MSG_LIB_TEXT_* 常量专门描述终端与服务器的拒单原因。其中 MSG_LIB_TEXT_LIMIT_LESS_STOP_LEVEL 指出:限价单距离止损单的点数若小于品种 StopLevel 允许值,会被拒;MSG_LIB_TEXT_SL_LESS_FREEZE_LEVEL 与 TP 版同理,针对的是 FreezeLevel 冻结层。 外汇与贵金属杠杆高、点差跳变频繁,StopLevel 和 FreezeLevel 在重大数据发布时可能瞬间放大,EA 若在此时下单极易吃到这类报错。开 MT5 在品种规格里核对 StopLevel / FreezeLevel 数值,再比对日志里的 MSG_LIB_TEXT_* 就能定位是哪一类合规被击穿。

MQL5 / C++
  ERROR_CODE_PROCESSING_METHOD_EXIT,                                              class=class="str">"cmt">// Exit the trading method
  ERROR_CODE_PROCESSING_METHOD_CORRECT,                                             class=class="str">"cmt">// Correct trading request parameters and repeat
  ERROR_CODE_PROCESSING_METHOD_REFRESH,                                             class=class="str">"cmt">// Update data and repeat
  ERROR_CODE_PROCESSING_METHOD_PENDING,                                             class=class="str">"cmt">// Create a pending request
  ERROR_CODE_PROCESSING_METHOD_WAIT,                                                class=class="str">"cmt">// Wait and repeat
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//--- CTrading
  MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED,     class=class="str">"cmt">// Trade operations are not allowed in the terminal(the AutoTrading button is disabled)
  MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED,           class=class="str">"cmt">// EA is not allowed to trade(F7 --> Common --> Allow Automated Trading)
  MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED,      class=class="str">"cmt">// Trading is disabled for the current account
  MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED,   class=class="str">"cmt">// Trading on the trading server side is disabled for EAs on the current account
  MSG_LIB_TEXT_REQUEST_REJECTED_DUE,           class=class="str">"cmt">// Request was rejected before sending to the server due to:
  MSG_LIB_TEXT_INVALID_REQUEST,                class=class="str">"cmt">// Invalid request:
  MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR,           class=class="str">"cmt">// Insufficient funds for performing a trade
  MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED,      class=class="str">"cmt">// Exceeded maximum allowed aggregate volume of orders and positions in one direction
  MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME,        class=class="str">"cmt">// Request volume is less than the minimum acceptable one
  MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME,        class=class="str">"cmt">// Request volume exceeds the maximum acceptable one
  MSG_LIB_TEXT_CLOSE_BY_ORDERS_DISABLED,       class=class="str">"cmt">// Close by is disabled
  MSG_LIB_TEXT_INVALID_VOLUME_STEP,            class=class="str">"cmt">// Request volume is not a multiple of the minimum lot change step gradation
  MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL,       class=class="str">"cmt">// Symbols of opposite positions are not equal
  MSG_LIB_TEXT_SL_LESS_STOP_LEVEL,             class=class="str">"cmt">// StopLoss violates requirements for symbol&class="macro">#x27;s StopLevel
  MSG_LIB_TEXT_TP_LESS_STOP_LEVEL,             class=class="str">"cmt">// TakeProfit violates requirements for symbol&class="macro">#x27;s StopLevel
  MSG_LIB_TEXT_PRICE_LESS_STOP_LEVEL,          class=class="str">"cmt">// Order distance in points is less than a value allowed by symbol&class="macro">#x27;s StopLevel parameter
  MSG_LIB_TEXT_LIMIT_LESS_STOP_LEVEL,          class=class="str">"cmt">// Limit order distance in points relative to a stop order is less than a value allowed by symbol&class="macro">#x27;s StopLevel parameter
  MSG_LIB_TEXT_SL_LESS_FREEZE_LEVEL,           class=class="str">"cmt">// The distance from the price to StopLoss is less than a value allowed by symbol&class="macro">#x27;s FreezeLevel parameter
  MSG_LIB_TEXT_TP_LESS_FREEZE_LEVEL,           class=class="str">"cmt">// The distance from the price to TakeProfit is less than a value allowed by symbol&class="macro">#x27;s FreezeLevel parameter

交易请求报错枚举与双语文案映射

在 MQL5 交易库里,挂单与改单失败的原因被集中定义成一组消息常量,方便 EA 在日志里直接吐出可读文本。上面这段代码列出的是部分关键枚举:FreezeLevel 距离不足、SL/TP 类型不是 int 或 double、交易被禁用等,都是实盘里最容易踩的坑。 注意 MSG_LIB_TEXT_LESS_FREEZE_LEVEL 和 MSG_LIB_TEXT_FAILING_CREATE_PENDING_REQ 这类被高亮的项——它们对应「价格距激活位小于 FreezeLevel」以及「创建挂单请求失败」,往往意味着你的下单逻辑在品种规则边界上撞墙。 下半段的双元素结构 {"俄文","英文"} 是库内部做的本地化映射,MT5 终端默认按英文输出。若你自建 EA 引用这套枚举,开策略测试器跑一遍 EURUSD 的即时单改单,就能在日志里看到具体哪条常量被触发。 外汇与贵金属杠杆高、滑点突变频繁,FreezeLevel 在重大数据发布时可能瞬间放大,任何距离校验失败都只是概率性提示,不等于行情方向判断。

MQL5 / C++
  MSG_LIB_TEXT_PR_LESS_FREEZE_LEVEL,                    class=class="str">"cmt">// The distance from the price to an order activation level is less than a value allowed by symbol&class="macro">#x27;s FreezeLevel parameter
  MSG_LIB_TEXT_UNSUPPORTED_SL_TYPE,                      class=class="str">"cmt">// Unsupported StopLoss parameter type(should be &class="macro">#x27;class="type">int&class="macro">#x27; or &class="macro">#x27;class="type">class="kw">double&class="macro">#x27;)
  MSG_LIB_TEXT_UNSUPPORTED_TP_TYPE,                      class=class="str">"cmt">// Unsupported TakeProfit parameter type(should be &class="macro">#x27;class="type">int&class="macro">#x27; or &class="macro">#x27;class="type">class="kw">double&class="macro">#x27;)
  MSG_LIB_TEXT_UNSUPPORTED_PR_TYPE,                      class=class="str">"cmt">// Unsupported price parameter type(should be &class="macro">#x27;class="type">int&class="macro">#x27; or &class="macro">#x27;class="type">class="kw">double&class="macro">#x27;)
  MSG_LIB_TEXT_UNSUPPORTED_PL_TYPE,                      class=class="str">"cmt">// Unsupported limit order price parameter type(should be &class="macro">#x27;class="type">int&class="macro">#x27; or &class="macro">#x27;class="type">class="kw">double&class="macro">#x27;)
  MSG_LIB_TEXT_UNSUPPORTED_PRICE_TYPE_IN_REQ,            class=class="str">"cmt">// Unsupported price parameter type in a request
  MSG_LIB_TEXT_TRADING_DISABLE,                          class=class="str">"cmt">// Trading disabled for the EA until the reason is eliminated
  MSG_LIB_TEXT_TRADING_OPERATION_ABORTED,                class=class="str">"cmt">// Trading operation is interrupted
  MSG_LIB_TEXT_CORRECTED_TRADE_REQUEST,                  class=class="str">"cmt">// Correcting trading request parameters
  MSG_LIB_TEXT_CREATE_PENDING_REQUEST,                   class=class="str">"cmt">// Creating a pending request
  MSG_LIB_TEXT_NOT_POSSIBILITY_CORRECT_LOT,              class=class="str">"cmt">// Unable to correct a lot
  MSG_LIB_TEXT_FAILING_CREATE_PENDING_REQ,               class=class="str">"cmt">// Failed to create a pending request
  MSG_LIB_TEXT_TRY_N,                                    class=class="str">"cmt">// Trading attempt #

};
 {"Дистанция установки ордера в пунктах меньше разрешённой параметром StopLevel символа","Distance to place order in points less than allowed by symbol&class="macro">#x27;s StopLevel"},
 {"Дистанция установки лимит-ордера относительно стоп-ордера меньше разрешённой параметром StopLevel символа","Distance to place limit order relative to stop order less than allowed by symbol&class="macro">#x27;s StopLevel"},
 {"Дистанция от цены до StopLoss меньше разрешённой параметром FreezeLevel символа","Distance from price to StopLoss less than allowed by symbol&class="macro">#x27;s FreezeLevel"},
 {"Дистанция от цены до TakeProfit меньше разрешённой параметром FreezeLevel символа","Distance from price to TakeProfit less than allowed by symbol&class="macro">#x27;s FreezeLevel"},
 {"Дистанция от цены до цены срабатывания ордера меньше разрешённой параметром FreezeLevel символа","Distance from price to order triggering price less than allowed by symbol&class="macro">#x27;s FreezeLevel"},
 {"Неподдерживаемый тип параметра StopLoss(необходимо class="type">int или class="type">class="kw">double)","Unsupported StopLoss parameter type(class="type">int or class="type">class="kw">double required)"},
 {"Неподдерживаемый тип параметра TakeProfit(необходимо class="type">int или class="type">class="kw">double)","Unsupported TakeProfit parameter type(class="type">int or class="type">class="kw">double required)"},
 {"Неподдерживаемый тип параметра цены (необходимо class="type">int или class="type">class="kw">double)","Unsupported price parameter type(class="type">int or class="type">class="kw">double required)"},
 {"Неподдерживаемый тип параметра цены limit-ордера (необходимо class="type">int или class="type">class="kw">double)","Unsupported type of price parameter for limit order(class="type">int or class="type">class="kw">double required)"},
 {"Неподдерживаемый тип параметра цены в запросе","Unsupported price parameter type in request"},
 {"Торговля отключена для эксперта до устранения причины запрета","Trading for expert disabled till this ban eliminated"},
 {"Торговая операция прервана","Trading operation aborted"},
 {"Корректировка параметров торгового запроса ...","Correction of trade request parameters ..."},
 {"Создание отложенного запроса","Create pending request"},
 {"Нет возможности скорректировать лот","Unable to correct lot"},
 {"Не удалось создать отложенный запрос","Failed to create pending request"},

◍ 下单函数的参数骨架

在 MT5 的自定义交易类里,把挂单和市价单统一收口到一个 SetOrder 方法,是减少重复代码的直接做法。下面这段声明给出了该方法暴露的全部入参,从订单类型到填充策略都在列。 bool SetOrder(const ENUM_ORDER_TYPE type, const double volume, const double price, const double sl=0, const double tp=0, const double price_stoplimit=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE, const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE); sl 和 tp 默认 0,意味着不传就代表不带止损止盈,实盘里容易因漏设而裸奔,外汇和贵金属波动大,高风险下建议显式传值。type_filling 默认 WRONG_VALUE 是个明显信号:不同券商对 IOC 和 FOK 的支持不同,不主动指定可能在部分账户直接拒单。 把 magic 设为 ULONG_MAX 做默认值也有讲究,它和具体 EA 的魔数区隔开,便于在调试阶段一眼识别出“测试单”。开 MT5 新建个 CTradeObj 类,把这段声明贴进去编译,先验证参数默认值会不会触发你当前账户的报错。

MQL5 / C++
class="type">bool SetOrder(class="kw">const ENUM_ORDER_TYPE type,
                class="kw">const class="type">class="kw">double volume,
                class="kw">const class="type">class="kw">double price,
                class="kw">const class="type">class="kw">double sl=class="num">0,
                class="kw">const class="type">class="kw">double tp=class="num">0,
                class="kw">const class="type">class="kw">double price_stoplimit=class="num">0,
                class="kw">const class="type">class="kw">ulong magic=ULONG_MAX,
                class="kw">const class="type">class="kw">string comment=NULL,
                class="kw">const class="type">class="kw">datetime expiration=class="num">0,
                class="kw">const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
                class="kw">const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE);

「挂单请求结构体里那些容易填错的字段」

在封装交易类时,挂单函数入口往往会带一长串带默认值的参数:magic 默认 ULONG_MAX 表示沿用实例魔法码,comment 默认 NULL 则取类内注释,expiration 给 0 代表不限期。type_time 和 type_filling 传 WRONG_VALUE 时,引擎会回退到对象成员里的预设值,这一层兜底能避免重复传参。 代码里先拦掉市价单类型:ORDER_TYPE_BUY、ORDER_TYPE_SELL、ORDER_TYPE_CLOSE_BY(MQL4 下还含 BUY_STOP_LIMIT / SELL_STOP_LIMIT)若混进挂单接口,直接写 MSG_LIB_SYS_INVALID_ORDER_TYPE 并返回 false,不会走到服务器。 随后 ZeroMemory 清空 request 与 result,再逐字段赋值。注意 stoplimit 只针对 STOP_LIMIT 类挂单有效,普通 LIMIT 单填了也会被服务端忽略;type_filling 在外汇黄金这种高波动品种上若选错,可能触发部分成交,实盘前建议在 MT5 策略测试器里用不同填充策略跑一遍验证。 最后按 m_async_mode 分流:同步走 OrderSend,异步走 OrderSendAsync。异步模式下回码不在当场返回,得靠 OnTradeTransaction 抓结果,写 EA 时别漏了这部分回调。

MQL5 / C++
class="kw">const class="type">class="kw">ulong magic=ULONG_MAX,
class="kw">const class="type">class="kw">string comment=NULL,
class="kw">const class="type">class="kw">datetime expiration=class="num">0,
class="kw">const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE,
class="kw">const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE)
{
 ::ResetLastError();
 class=class="str">"cmt">//--- If an invalid order type has been passed, write the error code and description, send the message to the journal and class="kw">return &class="macro">#x27;class="kw">false&class="macro">#x27;
 if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL || type==ORDER_TYPE_CLOSE_BY
    class="macro">#ifdef __MQL4__ || type==ORDER_TYPE_BUY_STOP_LIMIT || type==ORDER_TYPE_SELL_STOP_LIMIT class="macro">#endif )
    {
     this.m_result.retcode=MSG_LIB_SYS_INVALID_ORDER_TYPE;
     this.m_result.comment=CMessage::Text(this.m_result.retcode);
     if(this.m_log_level>LOG_LEVEL_NO_MSG)
        ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_INVALID_ORDER_TYPE),OrderTypeDescription(type));
     class="kw">return class="kw">false;
    }
 class=class="str">"cmt">//--- Clear the structures
 ::ZeroMemory(this.m_request);
 ::ZeroMemory(this.m_result);
 class=class="str">"cmt">//--- Fill in the request structure
 this.m_request.action       = TRADE_ACTION_PENDING;
 this.m_request.symbol       = this.m_symbol;
 this.m_request.magic        = (magic==ULONG_MAX ? this.m_magic : magic);
 this.m_request.volume       = volume;
 this.m_request.type         = type;
 this.m_request.stoplimit    = price_stoplimit;
 this.m_request.price        = price;
 this.m_request.sl           = sl;
 this.m_request.tp           = tp;
 this.m_request.expiration   = expiration;
 this.m_request.type_time    = (type_time>WRONG_VALUE ? type_time : this.m_type_time);
 this.m_request.type_filling = (type_filling>WRONG_VALUE ? type_filling : this.m_type_filling);
 this.m_request.comment      = (comment==NULL ? this.m_comment : comment);
 class=class="str">"cmt">//--- Return the result of sending a request to the server
class="macro">#ifdef __MQL5__
 class="kw">return(!this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result));
class="macro">#else
 ::ResetLastError();

下单回执与交易类骨架的衔接

发单动作结束后,立刻用 SymbolInfoTick 刷新本地 tick,避免拿到的 ask/bid 是几毫秒前的旧值。OrderSend 返回 ticket 不等于 WRONG_VALUE 时,先读 GetLastError 填 retcode,再尝试 OrderSelect 回捞真实开仓价与手数;若选单失败,就退回 m_request 里的预设值,保证结果结构永远有数可读。 成功分支里 m_result.price 和 volume 都走了「OrderSelect 成功才取真实值,否则用请求值」的三元判断,这套兜底能让回测与实盘在滑点场景下行为一致。外汇与贵金属点差跳变频繁,这种兜底可降低结果结构空窗导致的误判概率。 CTrading 类把账户、品种集、持仓集、历史集全部用指针挂进来,自己只持有一份 m_list_request 挂单队列和 m_list_errors 错误表。m_is_trade_disable 与 m_use_sound 两个布尔量分别管「禁交易开关」和「成交音效」,实盘里切策略时直接翻 m_is_trade_disable 比注释代码更安全。

MQL5 / C++
class="type">int ticket=::OrderSend(m_request.symbol,m_request.type,m_request.volume,m_request.price,(class="type">int)m_request.deviation,m_request.sl,m_request.tp,m_request.comment,(class="type">int)m_request.magic,m_request.expiration,clrNONE);
::SymbolInfoTick(this.m_symbol,this.m_tick);
if(ticket!=WRONG_VALUE)
  {
    this.m_result.retcode=::GetLastError();
    this.m_result.ask=this.m_tick.ask;
    this.m_result.bid=this.m_tick.bid;
    this.m_result.order=ticket;
    this.m_result.price=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderOpenPrice() : this.m_request.price);
    this.m_result.volume=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderLots() : this.m_request.volume);
    this.m_result.comment=CMessage::Text(this.m_result.retcode);
    class="kw">return true;
  }
else
  {
    this.m_result.retcode=::GetLastError();
    this.m_result.ask=this.m_tick.ask;
    this.m_result.bid=this.m_tick.bid;
    this.m_result.comment=CMessage::Text(this.m_result.retcode);
    class="kw">return class="kw">false;
  }
class="macro">#endif
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Trading class                                                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CTrading
  {
class="kw">private:
   CAccount            *m_account;            class=class="str">"cmt">// Pointer to the current account object
   CSymbolsCollection  *m_symbols;            class=class="str">"cmt">// Pointer to the symbol collection list
   CMarketCollection   *m_market;             class=class="str">"cmt">// Pointer to the list of the collection of market orders and positions
   CHistoryCollection  *m_history;            class=class="str">"cmt">// Pointer to the list of the collection of historical orders and deals
   CArrayObj           m_list_request;        class=class="str">"cmt">// List of pending requests
   CArrayInt           m_list_errors;         class=class="str">"cmt">// Error list
   class="type">bool                m_is_trade_disable;    class=class="str">"cmt">// Flag disabling trading
   class="type">bool                m_use_sound;           class=class="str">"cmt">// The flag of class="kw">using sounds of the object trading events
把重发循环交给小布盯盘辅助验证
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到重发尝试次数与最后回执码的分布,你只需确认库里的纠正逻辑是否覆盖当前品种规则。

常见问题

应直接退出交易方法并返回明确标志,不在循环里消耗尝试次数;调用程序可据此暂停逻辑而非反复报错。
在重发循环里识别该回执,延时等待价格离开冻结区或停止单激活后再发,尝试次数用尽则返回 false 并保留末次错误码。
可以,小布盯盘的 AIGC 模块能按品种展示重发次数与回执分布,省去你手动加打印看日志的重复劳动。
账户属性属于环境上下文,交易类只消费该标志决定纠正路径,分离后库的可复用性和测试边界更清晰。
本篇给交易类挂上计时器参数,下一篇用它调度延后请求,避免阻塞主循环,同时把等待并重复从忙等改成事件驱动。