DoEasy 函数库中的图形(第九十七部分):独立处理窗体对象移动·进阶篇
🖱️

DoEasy 函数库中的图形(第九十七部分):独立处理窗体对象移动·进阶篇

(2/3)· 想用鼠标拖动图表上的任意窗体,却总被其他工具的事件干扰?本篇收口移动处理逻辑。

进阶 第 2/3 篇
很多人直接在图表上拖窗体,却没隔离鼠标事件,结果选不中目标、其它工具乱响应。窗体移动若不做独立处理,交互逻辑会互相打架,调试起来极费时间。

10027–10038 这批交易报错码在说什么

在 MT5 的 Trade 相关返回码里,10027 到 10038 这一段集中暴露了客户端与交易服务器之间的「软性拒绝」。它们不是行情问题,而是下单动作本身被终端或券商规则拦下。 比如 10027 代表客户端禁用了自动交易,EA 再怎么发单也会被挡;10031 是无服务器连接,这时候任何下单函数都会直接返回失败。10033 和 10034 则是账户层面的限额:挂单总数触顶、或单一品种的开仓与挂单总体积触顶。 外汇与贵金属杠杆高,这类返回码频繁出现往往意味着风控参数或终端设置要先排查,而不是盲目重试。打开 MT5 的「工具→选项→EA交易」,确认允许算法交易勾选状态,能直接消掉 10027。 下面这段是这批码的原始中俄英对照定义,直接取自标准错误表结构,可粘进枚举做本地化:

MQL5 / C++
  {"Автотрейдинг запрещен клиентским терминалом","Autotrading disabled by client terminal"},                                                                              class=class="str">"cmt">// class="num">10027
  {"Запрос заблокирован для обработки","Request locked for processing"},                                                                                                    class=class="str">"cmt">// class="num">10028
  {"Ордер или позиция заморожены","Order or position frozen"},                                                                                                              class=class="str">"cmt">// class="num">10029
  {"Указан неподдерживаемый тип исполнения ордера по остатку","Invalid order filling type"},                                                                               class=class="str">"cmt">// class="num">10030
  {"Нет соединения с торговым сервером","No connection with trade server"},                                                                                                class=class="str">"cmt">// class="num">10031
  {"Операция разрешена только для реальных счетов","Operation allowed only for live accounts"},                                                                            class=class="str">"cmt">// class="num">10032
  {"Достигнут лимит на количество отложенных ордеров","Number of pending orders reached limit"},                                                                           class=class="str">"cmt">// class="num">10033
  {"Достигнут лимит на объем ордеров и позиций для данного символа","Volume of orders and positions for symbol reached limit"},                                            class=class="str">"cmt">// class="num">10034
  {"Неверный или запрещённый тип ордера","Incorrect or prohibited order type"},                                                                                            class=class="str">"cmt">// class="num">10035
  {"Позиция с указанным идентификатором уже закрыта","Position with specified identifier already closed"},                                                                 class=class="str">"cmt">// class="num">10036
  {"Неизвестный код возврата торгового сервера","Unknown trading server class="kw">return code"},                                                                                     class=class="str">"cmt">// class="num">10037
  {"Закрываемый объем превышает текущий объем позиции","Close volume exceeds the current position volume"}                                                                  class=class="str">"cmt">// class="num">10038

「交易请求被拒的底层错误码」

在 MT5 的 EA 或脚本里,交易函数返回的错误码能直接告诉你请求为什么没成交。下面这组 10039–10046 的常量,是仓位与账户规则层面的典型拒绝原因,做风控逻辑时绕不开。

  • 表示指定仓位已经挂了关闭订单,再发平仓请求会被拒;10040 是持仓数触到账户上限。10041 则是挂单激活请求被驳、挂单直接取消,常见于流动性瞬间抽干时。
  • 到 10044 都是品种级限制:分别只允许多、只允许空、只允许平。10045 是账户层 FIFO 平仓强制规则,10046 禁止同一品种开对向仓位。外汇与贵金属杠杆高,这类规则由经纪商动态设定,实盘前务必用 Print 把返回值打出来核对。

把这些码写进错误映射数组,EA 才能在拒绝时给出可读提示,而不是闷头重试。下面这段就是原文里的映射片段,逐行看:前两项是俄语与英语双语文本配错误码注释;10046 那组标明账户禁对向仓。

MQL5 / C++
  {"Для указанной позиции уже есть ордер на закрытие","Close order already exists for specified position"},                                                                         class=class="str">"cmt">// class="num">10039
  {"Достигнут лимит на количество открытых позиций","Number of positions reached limit"},                                                                                               class=class="str">"cmt">// class="num">10040
  {
    "Запрос на активацию отложенного ордера отклонен, а сам ордер отменен",                                                                                                                                class=class="str">"cmt">// class="num">10041
    "The pending order activation request is rejected, the order is canceled"
  },
  {
    "Запрос отклонен, так как на символе установлено правило \"Разрешены только длинные позиции\"",                                                                                                        class=class="str">"cmt">// class="num">10042
    "The request is rejected, because the \"Only class="type">long positions are allowed\" rule is set for the symbol"
  },
  {
    "Запрос отклонен, так как на символе установлено правило \"Разрешены только короткие позиции\"",                                                                                                       class=class="str">"cmt">// class="num">10043
    "The request is rejected, because the \"Only class="type">class="kw">short positions are allowed\" rule is set for the symbol"
  },
  {
    "Запрос отклонен, так как на символе установлено правило \"Разрешено только закрывать существующие позиции\"",                                                                                       class=class="str">"cmt">// class="num">10044
    "The request is rejected, because the \"Only position closing is allowed\" rule is set for the symbol"
  },
  {
    "Запрос отклонен, так как для торгового счета установлено правило \"Разрешено закрывать существующие позиции только по правилу FIFO\"",                                                               class=class="str">"cmt">// class="num">10045
    "The request is rejected, because \"Position closing is allowed only by FIFO rule\" flag is set for the trading account"
  },
  {
    "Запрос отклонен, так как для торгового счета установлено правило \"Запрещено открывать встречные позиции по одному символу\"",                                                                      class=class="str">"cmt">// class="num">10046
    "The request is rejected, because the \"Opposite positions on a single symbol are disabled\" rule is set for the trading account"
  },

◍ OpenCL 报错码 5100–5109 的本地化映射

在 MT5 终端里调用 OpenCL 做并行计算(比如多品种形态扫描)时,系统错误会以 5xxx 系列码返回。下面这段错误描述表把俄文与英文双语文本成对写死在数组里,方便 EA 在日志里直接吐出可读信息,而不是只留一个冷冰冰的数字。 从 5100 到 5109 覆盖了最常见的十类故障:本机不支持 OpenCL、运行内部错、句柄无效、上下文创建失败、执行队列创建失败、程序编译失败、内核名过长、内核创建失败、内核参数设置失败、程序运行时错误。 如果你在老核显或没装显卡驱动的 VPS 上跑 GPU 版指标,大概率先撞上 5100;而写了自定义 .cl 内核却编译不过,终端会抛 5105。开 MT5 按 F4 进 MetaEditor,把这段表贴进错误映射函数,断点跑一遍就能看到具体是哪一行卡住。

MQL5 / C++
  {"Функции OpenCL на данном компьютере не поддерживаются","OpenCL functions not supported on this computer"},                                                                       class=class="str">"cmt">// class="num">5100
  {"Внутренняя ошибка при выполнении OpenCL","Internal error occurred when running OpenCL"},                                                                                                                                                     class=class="str">"cmt">// class="num">5101
  {"Неправильный хэндл OpenCL","Invalid OpenCL handle"},                                                                                                                                                                                                                                                                             class=class="str">"cmt">// class="num">5102
  {"Ошибка при создании контекста OpenCL","Error creating the OpenCL context"},                                                                                                                                                                                                                                     class=class="str">"cmt">// class="num">5103
  {"Ошибка создания очереди выполнения в OpenCL","Failed to create run queue in OpenCL"},                                                                                                                                                                                                                       class=class="str">"cmt">// class="num">5104
  {"Ошибка при компиляции программы OpenCL","Error occurred when compiling OpenCL program"},                                                                                                                                                                                                                     class=class="str">"cmt">// class="num">5105
  {"Слишком длинное имя точки входа (кернел OpenCL)","Too class="type">long kernel name(OpenCL kernel)"},                                                                                                                                                                                                                     class=class="str">"cmt">// class="num">5106
  {"Ошибка создания кернел - точки входа OpenCL","Error creating OpenCL kernel"},                                                                                                                                                                                                                               class=class="str">"cmt">// class="num">5107
  {
    "Ошибка при установке параметров для кернел OpenCL(точки входа в программу OpenCL)",                                                                                                                                                                                                                     class=class="str">"cmt">// class="num">5108
    "Error occurred when setting parameters for the OpenCL kernel"
  },
  {"Ошибка выполнения программы OpenCL","OpenCL program runtime error"},                                                                                                                                                                                                                                         class=class="str">"cmt">// class="num">5109

OpenCL与数据库运行时报错码对照

在 MT5 的 EA 或指标里调用 OpenCL 做并行计算时,内核返回的错误码集中在 5110–5114 这一段。比如 5110 代表传入的缓冲区尺寸不合法,5111 是偏移量越界,5112 直接是缓冲区创建失败,这类错误往往出现在你用 BufferCreate 传了非 2 的幂尺寸、或总显存占用超过设备上限时。 紧接着 5120–5122 是数据库操作的执行期报错。DatabaseOpen 返回的句柄如果失效会抛 5121,而同进程内打开的 SQLite 连接数超过终端限制则触发 5122。实盘跑高频策略做本地 tick 落库时,这个上限很容易在多线程回测里踩到。 下面两段数组就是终端内部用的双语消息表,第一列俄语、第二列英文,直接嵌在你的错误打印模块里就能把数字码翻译成可读文本,省去查文档的功夫。

MQL5 / C++
  {"Неверный размер буфера OpenCL","Invalid size of OpenCL buffer"},                                                                          class=class="str">"cmt">// class="num">5110
  {"Неверное смещение в буфере OpenCL","Invalid offset in OpenCL buffer"},                                                                       class=class="str">"cmt">// class="num">5111
  {"Ошибка создания буфера OpenCL","Failed to create OpenCL buffer"},                                                                             class=class="str">"cmt">// class="num">5112
  {"Превышено максимальное число OpenCL объектов","Too many OpenCL objects"},                                                                     class=class="str">"cmt">// class="num">5113
  {"Ошибка выбора OpenCL устройства","OpenCL device selection error"},                                                                            class=class="str">"cmt">// class="num">5114
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Array of execution time error messages(class="num">5120 - class="num">5130)          |
class=class="str">"cmt">//| (Working with databases)                                          |
class=class="str">"cmt">//| (class="num">1) in user&class="macro">#x27;s country language                                    |
class=class="str">"cmt">//| (class="num">2) in the international language                                  |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">string messages_runtime_database[][TOTAL_LANG]=
  {
  {"Внутренняя ошибка базы данных","Internal database error"},                                                                                  class=class="str">"cmt">// class="num">5120
  {"Невалидный хендл базы данных","Invalid database handle"},                                                                                    class=class="str">"cmt">// class="num">5121
  {"Превышено максимально допустимое количество объектов Database","Exceeded the maximum acceptable number of Database objects"},       class=class="str">"cmt">// class="num">5122

「数据库与WebRequest报错码映射」

在 MQL5 里做本地数据库或外部 HTTP 接口调用时,报错不会直接给中文,而是落在一张双语消息数组里。上面这段就是数据库相关的一组:从 5123 到 5130,覆盖了连接失败、查询执行失败、结果未就绪、SQL 参数自动替换失败等非交易逻辑错误。 这些码和消息通常定义成 string messages_runtime_db[][2] 之类的二维数组,第一列是俄语等本地语种,第二列是英文。实战中如果你自己封装了 DatabaseOpen / WebRequest,建议直接复用这套枚举,别手搓字符串比对。 注意 5128「Data for reading request results are not ready yet」和 5130「Database query not read only」——前者常出现在异步读取没轮询完就取数,后者说明你跑的 SQL 带了写操作却被当成只读句柄。外汇与贵金属 EA 接数据库本就小众且高风险,参数错一处就可能静默丢信号。

MQL5 / C++
  {"Ошибка подключения к базе данных","Database connection error"},                                                                               class=class="str">"cmt">// class="num">5123
  {"Ошибка выполнения запроса","Request execution error"},                                                                                               class=class="str">"cmt">// class="num">5124
  {"Ошибка создания запроса","Request generation error"},                                                                                                 class=class="str">"cmt">// class="num">5125
  {"Данных для чтения больше нет","No more data to read"},                                                                                                class=class="str">"cmt">// class="num">5126
  {"Ошибка перехода к следующей записи запроса","Failed to move to the next request entry"},                                                              class=class="str">"cmt">// class="num">5127
  {"Данные для чтения результатов запроса еще не готовы","Data for reading request results are not ready yet"},                                            class=class="str">"cmt">// class="num">5128
  {"Ошибка автоподстановки параметров в SQL-запрос","Failed to auto substitute parameters to an SQL request"},                                            class=class="str">"cmt">// class="num">5129
  {"Запрос базы данных не только для чтения","Database query not read only"},                                                                             class=class="str">"cmt">// class="num">5130
};

◍ 网络函数报错码的本地化对照

在 MT5 里做 HTTP 请求或 socket 通信时,错误会以双语文段形式返回:前一个是终端界面语言(如俄语),后一个是国际英语。上面这段数组覆盖了 5200–5203 与 5270–5272 两组网络相关错误码。

  • 对应 URL 校验未过(Invalid URL),5201 是连不上指定地址,5202 为数据接收超时,5203 是 HTTP 请求执行失败;socket 侧 5270 表示传入了非法句柄,5271 提示打开的 socket 超过上限 128 个,5272 则是远端主机连接失败。

实盘接行情 API 或中继服务时,建议直接把这组 messages_runtime_netsocket 数组拷进 EA,用 GetLastError() 映射后打印英语项,排错效率比翻文档高。外汇与贵金属杠杆高,网络抖动可能触发 5272 造成信号延迟,仓位管理上需留余量。

MQL5 / C++
  {"URL не прошел проверку","Invalid URL"},                                                                                                        class=class="str">"cmt">// class="num">5200
  {"Не удалось подключиться к указанному URL","Failed to connect to specified URL"},                                                                              class=class="str">"cmt">// class="num">5201
  {"Превышен таймаут получения данных","Timeout exceeded"},                                                                                                        class=class="str">"cmt">// class="num">5202
  {"Ошибка в результате выполнения HTTP запроса","HTTP request failed"},                                                                                          class=class="str">"cmt">// class="num">5203
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Array of execution time error messages(class="num">5270 - class="num">5275)           | 
class=class="str">"cmt">//| (Working with network(sockets))                                | 
class=class="str">"cmt">//| (class="num">1) in user&class="macro">#x27;s country language                                  | 
class=class="str">"cmt">//| (class="num">2) in the international language                                | 
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">string messages_runtime_netsocket[][TOTAL_LANG]=
  {
  {"В функцию передан неверный хэндл сокета","Invalid socket handle passed to function"},                                                                         class=class="str">"cmt">// class="num">5270
  {"Открыто слишком много сокетов (максимум class="num">128)","Too many open sockets(max class="num">128)"},                                                                             class=class="str">"cmt">// class="num">5271
  {"Ошибка соединения с удаленным хостом","Failed to connect to remote host"},                                                                                   class=class="str">"cmt">// class="num">5272
把事件隔离交给小布
这些窗体拖拽与错误码映射的底层诊断,小布盯盘的 AIGC 已内置,打开对应品种页即可看到实时对象状态,你只管判断该不该动。

常见问题

全局事件会被所有图形对象共享,导致拖动一个窗体时其它工具误触发;独立处理能精准锁定被拖窗体并正确启用禁用其它交互。
需要将处理代码范围上限加 1 覆盖该值,并从新增错误数组按数值提取文本赋值到消息变量,否则返回码会落空显示。
在 Defines.mqh 的实数型属性枚举加入新项,总数从 11 调到 12,并在订单与成交排序准则枚举补上对应可能的排序值。
可以,小布的品种页会把图形对象的事件挂载与错误码状态列出,省去你手动在代码里翻 Message.mqh 的功夫。
上篇搭了事件入口,本篇收口拖动逻辑并为后续交互凭证做准备,完整衔接见《DoEasy 图形窗体对象·基础篇》。