轻松快捷开发 MetaTrader 程序的函数库(第 二十二部分):交易类 - 基准类,限制验证·进阶篇
(2/3)· 很多人直接填交易请求就发服务器,却漏了账户、品种和 FIFO 等前置限制检查
「错误音效与账户整数属性的枚举映射」
在 MT5 的底层枚举设计里,报错音效被拆成了五类独立开关:开仓/挂单失败、平仓/删单失败、SL 修改失败、TP 修改失败、挂单价修改失败。每一类都对应一个 MODE_SET_SOUND_ERROR_* 常量,意味着你可以用 PlaySound 体系分别定制提醒音,而不是所有错误共用一个 wav。 账户端则用 ENUM_ACCOUNT_PROP_INTEGER 暴露了 11 个整型属性(宏 ACCOUNT_PROP_INTEGER_TOTAL 定义为 11)。从 ACCOUNT_PROP_LOGIN 到 ACCOUNT_PROP_SERVER_TYPE,覆盖了账号号、杠杆、限价单上限、强平模式、交易权限、保证金算法等。其中 ACCOUNT_PROP_FIFO_CLOSE 标明了该账户是否强制 FIFO(先进先出)平仓——美监管账户通常为真。 实盘里若你的 EA 在美股经纪商上莫名平不掉老单,先读一下 ACCOUNT_PROP_FIFO_CLOSE 的值,大概率能省掉半晚的瞎调试。外汇和贵金属波动剧烈、杠杆风险高,读取这些属性仅用于风控适配,不预示任何收益。
enum ENUM_ACCOUNT_PROP_INTEGER { ACCOUNT_PROP_LOGIN, class=class="str">"cmt">// Account number ACCOUNT_PROP_TRADE_MODE, class=class="str">"cmt">// Trading account type ACCOUNT_PROP_LEVERAGE, class=class="str">"cmt">// Leverage ACCOUNT_PROP_LIMIT_ORDERS, class=class="str">"cmt">// Maximum allowed number of active pending orders ACCOUNT_PROP_MARGIN_SO_MODE, class=class="str">"cmt">// Mode of setting the minimum available margin level ACCOUNT_PROP_TRADE_ALLOWED, class=class="str">"cmt">// Permission to trade for the current account from the server side ACCOUNT_PROP_TRADE_EXPERT, class=class="str">"cmt">// Permission to trade for an EA from the server side ACCOUNT_PROP_MARGIN_MODE, class=class="str">"cmt">// Margin calculation mode ACCOUNT_PROP_CURRENCY_DIGITS, class=class="str">"cmt">// Number of digits for an account currency necessary for accurate display of trading results ACCOUNT_PROP_SERVER_TYPE, class=class="str">"cmt">// Trade server type(MetaTrader5, MetaTrader4) ACCOUNT_PROP_FIFO_CLOSE class=class="str">"cmt">// Flag of a position closure by FIFO rule only }; class="macro">#define ACCOUNT_PROP_INTEGER_TOTAL(class="num">11) class=class="str">"cmt">// Total number of integer properties
账户与品种排序属性的枚举落点
在批量扫描多账户或多品种时,先定义跳过项再算偏移,能避免把无排序价值的属性混进比较逻辑。原文用 ACCOUNT_PROP_INTEGER_SKIP 设为 0,表示整数类账户属性全部参与排序,随后用 FIRST_ACC_DBL_PROP 与 FIRST_ACC_STR_PROP 两个宏把 double 与 string 类属性的起始下标算出来。 排序枚举 ENUM_SORT_ACCOUNT_MODE 从 SORT_BY_ACCOUNT_LOGIN=0 起,依次覆盖账户号、交易模式、杠杆、挂单上限、止损平仓模式、交易权限、EA 权限、保证金模式、币种精度、服务器类型,以及被高亮的 SORT_BY_ACCOUNT_FIFO_CLOSE(仅按 FIFO 平仓规则标志排序)。 品种侧用 ENUM_SYMBOL_PROP_STRING 承接,起始下标直接取 SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL,列出 SYMBOL_PROP_NAME、SYMBOL_PROP_BASIS、SYMBOL_PROP_CURRENCY_BASE 等字符串属性。外汇与贵金属交易杠杆与 FIFO 规则因经纪商而异,多账户回测前应先按上述枚举核对属性偏移,否则可能把不同服务器类型的账户误排在一起。
class="macro">#define ACCOUNT_PROP_INTEGER_SKIP(class="num">0) class=class="str">"cmt">// Number of integer account properties not used in sorting class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Possible account sorting criteria | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#define FIRST_ACC_DBL_PROP(ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP) class="macro">#define FIRST_ACC_STR_PROP(ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP+ACCOUNT_PROP_DOUBLE_TOTAL-ACCOUNT_PROP_DOUBLE_SKIP) enum ENUM_SORT_ACCOUNT_MODE { class=class="str">"cmt">//--- Sort by integer properties SORT_BY_ACCOUNT_LOGIN = class="num">0, class=class="str">"cmt">// Sort by account number SORT_BY_ACCOUNT_TRADE_MODE, class=class="str">"cmt">// Sort by trading account type SORT_BY_ACCOUNT_LEVERAGE, class=class="str">"cmt">// Sort by leverage SORT_BY_ACCOUNT_LIMIT_ORDERS, class=class="str">"cmt">// Sort by maximum acceptable number of existing pending orders SORT_BY_ACCOUNT_MARGIN_SO_MODE, class=class="str">"cmt">// Sort by mode for setting the minimum acceptable margin level SORT_BY_ACCOUNT_TRADE_ALLOWED, class=class="str">"cmt">// Sort by permission to trade for the current account SORT_BY_ACCOUNT_TRADE_EXPERT, class=class="str">"cmt">// Sort by permission to trade for an EA SORT_BY_ACCOUNT_MARGIN_MODE, class=class="str">"cmt">// Sort by margin calculation mode SORT_BY_ACCOUNT_CURRENCY_DIGITS, class=class="str">"cmt">// Sort by number of digits for an account currency SORT_BY_ACCOUNT_SERVER_TYPE, class=class="str">"cmt">// Sort by trade server type(MetaTrader5, MetaTrader4) SORT_BY_ACCOUNT_FIFO_CLOSE, class=class="str">"cmt">// Sort by the flag of a position closure by FIFO rule only class=class="str">"cmt">//--- Sort by real properties class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Symbol class="type">class="kw">string properties | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_SYMBOL_PROP_STRING { SYMBOL_PROP_NAME = (SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL), class=class="str">"cmt">// Symbol name SYMBOL_PROP_BASIS, class=class="str">"cmt">// Name of the underlaying asset for a derivative symbol SYMBOL_PROP_CURRENCY_BASE, class=class="str">"cmt">// Instrument base currency
◍ 品种字符串属性与排序枚举的对应关系
在 MT5 的 API 里,品种(symbol)的字符串类属性用一组枚举值描述,从盈利货币、保证金货币到报价源、ISIN 编码、网页链接、品种树路径都有覆盖。其中 SYMBOL_PROP_CATEGORY 和 SYMBOL_PROP_EXCHANGE 是高亮的两个字段,分别指向品种分类与上市交易所名称,对做跨市场扫描时过滤标的有直接用。 这些字符串属性的总数由宏 SYMBOL_PROP_STRING_TOTAL 定义为 13,也就是说枚举里从 SYMBOL_PROP_CURRENCY_PROFIT 到 SYMBOL_PROP_EXCHANGE 正好 13 项,写循环遍历时直接用这个常量,别把数字写死。 排序方向也映射了同样的字符串属性:SORT_BY_SYMBOL_NAME 对应名称,SORT_BY_SYMBOL_CURRENCY_PROFIT 对应盈利货币,SORT_BY_SYMBOL_BANK 对应报价源。写自定义品种浏览器时,把这些枚举喂给排序函数,就能按基础资产、币种或交易所分组呈现,省去自己解析字符串。 外汇与贵金属品种属性受经纪商配置影响,不同服务器下 SYMBOL_PROP_EXCHANGE 可能为空,实盘前建议在 MT5 用 SymbolInfoString 逐个打印验证。
SYMBOL_PROP_CURRENCY_PROFIT, class=class="str">"cmt">// Profit currency SYMBOL_PROP_CURRENCY_MARGIN, class=class="str">"cmt">// Margin currency SYMBOL_PROP_BANK, class=class="str">"cmt">// Source of the current quote SYMBOL_PROP_DESCRIPTION, class=class="str">"cmt">// String description of a symbol SYMBOL_PROP_FORMULA, class=class="str">"cmt">// The formula used for custom symbol pricing SYMBOL_PROP_ISIN, class=class="str">"cmt">// The name of a trading symbol in the international system of securities identification numbers(ISIN) SYMBOL_PROP_PAGE, class=class="str">"cmt">// The web page containing symbol information SYMBOL_PROP_PATH, class=class="str">"cmt">// Location in the symbol tree SYMBOL_PROP_CATEGORY, class=class="str">"cmt">// Symbol category SYMBOL_PROP_EXCHANGE class=class="str">"cmt">// Name of an exchange a symbol is traded on }; class="macro">#define SYMBOL_PROP_STRING_TOTAL(class="num">13) class=class="str">"cmt">// Total number of class="type">class="kw">string properties class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//--- Sort by class="type">class="kw">string properties SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP, class=class="str">"cmt">// Sort by a symbol name SORT_BY_SYMBOL_BASIS, class=class="str">"cmt">// Sort by an underlying asset of a derivative SORT_BY_SYMBOL_CURRENCY_BASE, class=class="str">"cmt">// Sort by a base currency of a symbol SORT_BY_SYMBOL_CURRENCY_PROFIT, class=class="str">"cmt">// Sort by a profit currency SORT_BY_SYMBOL_CURRENCY_MARGIN, class=class="str">"cmt">// Sort by a margin currency SORT_BY_SYMBOL_BANK, class=class="str">"cmt">// Sort by a feeder of the current quote SORT_BY_SYMBOL_DESCRIPTION, class=class="str">"cmt">// Sort by a symbol class="type">class="kw">string description
「枚举项里的排序与报错边界」
在自定义交易面板库里,符号排序枚举收尾给了几个常被忽略的维度:SORT_BY_SYMBOL_CATEGORY 按品种类别排,SORT_BY_SYMBOL_EXCHANGE 按上市交易所名排。这两个高亮项决定了自定义品种树在 MT5 市场报价窗口里的分组逻辑,做跨品种扫描器时要先确认终端支持。 报错枚举 ENUM_MESSAGES_LIB 从 ERR_USER_ERROR_FIRST 起算,MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155 明确标出:低于 build 2155 的 MT5 不认某些属性。如果你在老版本终端跑新库,会直接走这个分支而不是通用不支持提示。 实际排错时,MSG_LIB_SYS_NOT_SYMBOL_ON_SERVER 和 MSG_LIB_SYS_NOT_SYMBOL_ON_LIST 要分开看:前者是 broker 端根本没有该符号,后者是你本地使用的符号清单未包含。外汇与贵金属杠杆高,品种下架或重命名可能引发脚本静默失败,建议在调用前用 SymbolInfoInteger 探一下存在性。
SORT_BY_SYMBOL_FORMULA, class=class="str">"cmt">// Sort by the formula used for custom symbol pricing SORT_BY_SYMBOL_ISIN, class=class="str">"cmt">// Sort by the name of a symbol in the ISIN system SORT_BY_SYMBOL_PAGE, class=class="str">"cmt">// Sort by an address of the web page containing symbol information SORT_BY_SYMBOL_PATH, class=class="str">"cmt">// Sort by a path in the symbol tree SORT_BY_SYMBOL_CATEGORY, class=class="str">"cmt">// Sort by symbol category SORT_BY_SYMBOL_EXCHANGE class=class="str">"cmt">// Sort by a name of an exchange a symbol is traded on }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| List of the library&class="macro">#x27;s text message indices | class=class="str">"cmt">//+------------------------------------------------------------------+ enum ENUM_MESSAGES_LIB { MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST, class=class="str">"cmt">// Beginning of the parameter list MSG_LIB_PARAMS_LIST_END, class=class="str">"cmt">// End of the parameter list MSG_LIB_PROP_NOT_SUPPORTED, class=class="str">"cmt">// Property not supported MSG_LIB_PROP_NOT_SUPPORTED_MQL4, class=class="str">"cmt">// Property not supported in MQL4 MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155, class=class="str">"cmt">// Property not supported in MetaTrader class="num">5 versions lower than class="num">2155 MSG_LIB_PROP_NOT_SUPPORTED_POSITION, class=class="str">"cmt">// Property not supported for position MSG_LIB_PROP_NOT_SUPPORTED_PENDING, class=class="str">"cmt">// Property not supported for pending order MSG_LIB_PROP_NOT_SUPPORTED_MARKET, class=class="str">"cmt">// Property not supported for market order MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST, class=class="str">"cmt">// Property not supported for historical market order MSG_LIB_PROP_NOT_SET, class=class="str">"cmt">// Value not set MSG_LIB_PROP_EMPTY, class=class="str">"cmt">// Not set MSG_LIB_SYS_ERROR, class=class="str">"cmt">// Error MSG_LIB_SYS_NOT_SYMBOL_ON_SERVER, class=class="str">"cmt">// Error. No such symbol on server MSG_LIB_SYS_NOT_SYMBOL_ON_LIST class=class="str">"cmt">// Error. No such symbol in the list of used symbols:
系统库报错枚举里的暗坑
这段枚举集中暴露了 MQL5 系统库在初始化与运行期的脆弱点:从市场观察列表添加失败、报价获取失败,到计时器创建失败,覆盖了 EA 启动前后最可能崩的地方。 注意 MSG_LIB_SYS_FAILED_CREATE_TIMER 被高亮,说明计时器创建失败在实战中最高频——多数情况是前一步账户对象或符号对象没建成功,导致 EventSetTimer() 拿到空上下文。 如果你在日志里看到 MSG_LIB_SYS_NO_TICKS_YET,不代表断网,只是对象结构已建但首 tick 未到;而 MSG_LIB_SYS_FAILED_ADD_CTRL_POSITION_TO_LIST 这类错误,往往意味着你的持仓监控列表容量或生命周期管理有问题。 把这些宏直接贴进调试输出,能在 MT5 策略测试器里快速定位是建仓前还是建仓后出的故障,省掉逐行断点。外汇与贵金属品种波动大,这类底层失败可能引发连锁平仓异常,实盘前务必在模拟盘跑通。
MSG_LIB_SYS_FAILED_PUT_SYMBOL, class=class="str">"cmt">// Failed to place to market watch. Error: MSG_LIB_SYS_NOT_GET_PRICE, class=class="str">"cmt">// Failed to get current prices. Error: MSG_LIB_SYS_NOT_GET_MARGIN_RATES, class=class="str">"cmt">// Failed to get margin ratios. Error: MSG_LIB_SYS_NOT_GET_DATAS, class=class="str">"cmt">// Failed to get data MSG_LIB_SYS_FAILED_CREATE_STORAGE_FOLDER, class=class="str">"cmt">// Failed to create folder for storing files. Error: MSG_LIB_SYS_FAILED_ADD_ACC_OBJ_TO_LIST, class=class="str">"cmt">// Error. Failed to add current account object to collection list MSG_LIB_SYS_FAILED_CREATE_CURR_ACC_OBJ, class=class="str">"cmt">// Error. Failed to create account object with current account data MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE, class=class="str">"cmt">// Could not open file for writing MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL, class=class="str">"cmt">// Input error: no symbol MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ, class=class="str">"cmt">// Failed to create symbol object MSG_LIB_SYS_FAILED_ADD_SYM_OBJ, class=class="str">"cmt">// Failed to add symbol MSG_LIB_SYS_NOT_GET_CURR_PRICES, class=class="str">"cmt">// Failed to get current prices by event symbol MSG_LIB_SYS_EVENT_ALREADY_IN_LIST, class=class="str">"cmt">// This event is already in the list MSG_LIB_SYS_FILE_RES_ALREADY_IN_LIST, class=class="str">"cmt">// This file already created and added to list: MSG_LIB_SYS_FAILED_CREATE_RES_LINK, class=class="str">"cmt">// Error. Failed to create object pointing to resource file MSG_LIB_SYS_ERROR_ALREADY_CREATED_COUNTER, class=class="str">"cmt">// Error. Counter with ID already created MSG_LIB_SYS_FAILED_CREATE_COUNTER, class=class="str">"cmt">// Failed to create timer counter MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST, class=class="str">"cmt">// Error creating temporary list MSG_LIB_SYS_ERROR_NOT_MARKET_LIST, class=class="str">"cmt">// Error. This is not a market collection list MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST, class=class="str">"cmt">// Error. This is not a history collection list MSG_LIB_SYS_FAILED_ADD_ORDER_TO_LIST, class=class="str">"cmt">// Could not add order to the list MSG_LIB_SYS_FAILED_ADD_DEAL_TO_LIST, class=class="str">"cmt">// Could not add deal to the list MSG_LIB_SYS_FAILED_ADD_CTRL_ORDER_TO_LIST, class=class="str">"cmt">// Failed to add control order MSG_LIB_SYS_FAILED_ADD_CTRL_POSITION_TO_LIST, class=class="str">"cmt">// Failed to add control position MSG_LIB_SYS_FAILED_ADD_MODIFIED_ORD_TO_LIST, class=class="str">"cmt">// Could not add modified order to the list of modified orders MSG_LIB_SYS_FAILED_CREATE_TIMER, class=class="str">"cmt">// Failed to create timer. Error: MSG_LIB_SYS_NO_TICKS_YET, class=class="str">"cmt">// No ticks yet MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT, class=class="str">"cmt">// Could not create object structure
◍ 订单与系统消息枚举的落地写法
在标准库的消息枚举定义里,系统级错误和订单类描述被拆成了两组常量。前面一组管文件读写与结构转换:写 uchar 数组失败、从文件加载失败、由 uchar 数组重建对象结构失败,都对应独立消息码,方便在日志里直接定位是哪一步断了。 index 取值被限制在 0–3 之间,超出就报 MSG_LIB_SYS_ERROR_INDEX;字符串转小写失败也有专属错误码。这些边界在写自定义序列化模块时很容易踩,建议直接复用同一套枚举而不是自己硬写字符串。 订单侧从 MSG_ORD_BUY 到 MSG_ORD_PENDING 覆盖了市价单、历史单、活动挂单与未知类型的区分。其中 MSG_ORD_MARKET 被标黄,说明在库内部它常被用作快速判断分支的锚点。复制下面这段枚举到 MT5 的 include 里,编译后搜 MSG_ORD_MARKET 就能看清调用链。 外汇与贵金属品种切换频繁,这类消息枚举若用于 EA 监控,需注意点差跳变时市价单状态翻转可能带来的误报,属于高风险场景下的辅助诊断,不是信号本身。
MSG_LIB_SYS_FAILED_WRITE_UARRAY_TO_FILE, class=class="str">"cmt">// Could not write class="type">uchar array to file MSG_LIB_SYS_FAILED_LOAD_UARRAY_FROM_FILE, class=class="str">"cmt">// Could not load class="type">uchar array from file MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT_FROM_UARRAY, class=class="str">"cmt">// Could not create object structure from class="type">uchar array MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY, class=class="str">"cmt">// Failed to save object structure to class="type">uchar array, error MSG_LIB_SYS_ERROR_INDEX, class=class="str">"cmt">// Error. "index" value should be within class="num">0 - class="num">3 MSG_LIB_SYS_ERROR_FAILED_CONV_TO_LOWERCASE, class=class="str">"cmt">// Failed to convert class="type">class="kw">string to lowercase, error class=class="str">"cmt">//--- COrder MSG_ORD_BUY, class=class="str">"cmt">// Buy MSG_ORD_SELL, class=class="str">"cmt">// Sell MSG_ORD_TO_BUY, class=class="str">"cmt">// Buy order MSG_ORD_TO_SELL, class=class="str">"cmt">// Sell order MSG_DEAL_TO_BUY, class=class="str">"cmt">// Buy deal MSG_DEAL_TO_SELL, class=class="str">"cmt">// Sell deal MSG_ORD_MARKET, class=class="str">"cmt">// Market order MSG_ORD_HISTORY, class=class="str">"cmt">// Historical order MSG_ORD_DEAL, class=class="str">"cmt">// Deal MSG_ORD_POSITION, class=class="str">"cmt">// Position MSG_ORD_PENDING_ACTIVE, class=class="str">"cmt">// Active pending order MSG_ORD_PENDING, class=class="str">"cmt">// Pending order MSG_ORD_UNKNOWN_TYPE, class=class="str">"cmt">// Unknown order type MSG_POS_UNKNOWN_TYPE, class=class="str">"cmt">// Unknown position type MSG_POS_UNKNOWN_DEAL, class=class="str">"cmt">// Unknown deal type class=class="str">"cmt">//--- class=class="str">"cmt">//--- MSG_SYM_PROP_NAME, class=class="str">"cmt">// Symbol name