轻松快捷开发 MetaTrader 程序的函数库(第 二十二部分):交易类 - 基准类,限制验证
内容
在前一篇文章中,我们开启了一个拓展的函数库章节,专门讨论交易函数,并创建了品种基准交易对象。 交易对象从发送给服务器的交易请求中提取参数里的所有属性,根据被调用类的方法类型(开仓/下单/修改/平仓/撤除)填写交易请求结构,并将交易订单发送到服务器。 有效的交易请求属性值将传递到基准交易对象,以便发送交易订单。 不过,为了最大程度地运用交易对象,我们首先需要在终端里检查存在的限制:进行交易操作的权限、程序、账户和交易品种。 这些初步检查通过后,我们便可以验证交易请求属性。
在本文中,我们将着手开发成熟的交易类。 我们要实现的第一件事是验证交易操作限制。
概念
我们已有了基准交易对象,它是品种对象的一部分。 它根据传递给类方法之一的参数填写交易请求结构,并将交易订单发送给服务器。 在实现成熟的交易类之前,我们会加入一些基本的交易对象功能 — 即依据发送交易指令的结果播放语音。 这将令我们能够针对音频交易事件设置音频。 我们可以为每个品种的每一交易事件设置自定义音频。 当然,我们也可以为所有品种的每个共用事件指定一组音频。 基准交易对象能够为交易事件设置音频提供充分的机会,无论所有品种和事件的声音是否相同/不同。
接着,我们将创建一个交易类,所有交易操作都将在该类中进行。 在本文中,我们将为该类实现最低功能 — 验证交易操作权限,并依据所需品种调用其基准交易对象的必要方法。
扩展基准交易对象功能
若要将音频分配给交易事件,我们需要一些宏替换和枚举。 打开 Defines.mqh 文件,并加入宏替换覆盖标准音频文件的名称:
//+------------------------------------------------------------------+ //| Macro substitutions | //+------------------------------------------------------------------+ //--- Describe the function with the error line number #define DFUN_ERR_LINE (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(string)__LINE__+": ") #define DFUN (__FUNCTION__+": ") // "Function description" #define COUNTRY_LANG ("Russian") // Country language #define END_TIME (D'31.12.3000 23:59:59') // End date for account history data requests #define TIMER_FREQUENCY (16) // Minimal frequency of the library timer in milliseconds //--- Standard sounds #define SND_ALERT "alert.wav" #define SND_ALERT2 "alert2.wav" #define SND_CONNECT "connect.wav" #define SND_DISCONNECT "disconnect.wav" #define SND_EMAIL "email.wav" #define SND_EXPERT "expert.wav" #define SND_NEWS "news.wav" #define SND_OK "ok.wav" #define SND_REQUEST "request.wav" #define SND_STOPS "stops.wav" #define SND_TICK "tick.wav" #define SND_TIMEOUT "timeout.wav" #define SND_WAIT "wait.wav" //--- Parameters of the orders and deals collection timer
如果我们想利用它们作为交易事件语音的音频文件,如此即可更方便地指定标准音频文件的名称。
在用于交易类操作的数据块清单之后,添加交易操作类型的枚举和音频设置模式的枚举:
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Data for working with trading classes | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Logging level | //+------------------------------------------------------------------+ enum ENUM_LOG_LEVEL { LOG_LEVEL_NO_MSG, // Trading logging disabled LOG_LEVEL_ERROR_MSG, // Only trading errors LOG_LEVEL_ALL_MSG // Full logging }; //+------------------------------------------------------------------+ //| Types of performed operations | //+------------------------------------------------------------------+ enum ENUM_ACTION_TYPE { ACTION_TYPE_BUY = ORDER_TYPE_BUY, // Open Buy ACTION_TYPE_SELL = ORDER_TYPE_SELL, // Open Sell ACTION_TYPE_BUY_LIMIT = ORDER_TYPE_BUY_LIMIT, // Place BuyLimit ACTION_TYPE_SELL_LIMIT = ORDER_TYPE_SELL_LIMIT, // Place SellLimit ACTION_TYPE_BUY_STOP = ORDER_TYPE_BUY_STOP, // Place BuyStop ACTION_TYPE_SELL_STOP = ORDER_TYPE_SELL_STOP, // Place SellStop ACTION_TYPE_BUY_STOP_LIMIT = ORDER_TYPE_BUY_STOP_LIMIT, // Place BuyStopLimit ACTION_TYPE_SELL_STOP_LIMIT = ORDER_TYPE_SELL_STOP_LIMIT, // Place SellStopLimit ACTION_TYPE_CLOSE_BY = ORDER_TYPE_CLOSE_BY, // Close a position by an opposite one ACTION_TYPE_MODIFY = ACTION_TYPE_CLOSE_BY+1, // Modification }; //+------------------------------------------------------------------+ //| Sound setting mode | //+------------------------------------------------------------------+ enum ENUM_MODE_SET_SOUND { MODE_SET_SOUND_OPEN, // Opening/placing sound setting mode MODE_SET_SOUND_CLOSE, // Closing/removal sound setting mode MODE_SET_SOUND_MODIFY_SL, // StopLoss modification sound setting mode MODE_SET_SOUND_MODIFY_TP, // TakeProfit modification sound setting mode MODE_SET_SOUND_MODIFY_PRICE, // Placing price modification sound setting mode MODE_SET_SOUND_ERROR_OPEN, // Opening/placing error sound setting mode MODE_SET_SOUND_ERROR_CLOSE, // Closing/removal error sound setting mode MODE_SET_SOUND_ERROR_MODIFY_SL, // StopLoss modification error sound setting mode MODE_SET_SOUND_ERROR_MODIFY_TP, // TakeProfit modification error sound setting mode MODE_SET_SOUND_ERROR_MODIFY_PRICE, // Placing price modification error sound setting mode }; //+------------------------------------------------------------------+
在 MQL5 的终端版本 2155 中引入了新的品种和帐户属性:
- MQL5: 下值已添加到 ENUM_SYMBOL_INFO_STRING 枚举中:
- SYMBOL_CATEGORY — 品种类别。 它用于金融工具的附加标记。 例如,这可以是该品种所属的市场分部:农业、石油和天然气、等等。
- SYMBOL_EXCHANGE — 品种交易所处的交易所名称。
- MQL5: 增加了遵照先进先出(FIFO)规则平仓的支持。
- ACCOUNT_FIFO_CLOSE 值已添加到 ENUM_ACCOUNT_INFO_INTEGER。 它表示只能遵照先进先出(FIFO)规则平仓。 如果属性值为 true,则每个金融工具必须按照开仓的相同顺序依次平仓:最久的持仓应先关闭,然后再关闭下一个,依此类推。 如果尝试按不同顺序平仓,将返回错误。 对于不支持对冲持仓管理的帐户,属性值始终为 “false”(ACCOUNT_MARGIN_MODE!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)。
- 新的返回代码: MT_RET_REQUEST_CLOSE_ONLY — 该请求被拒绝,因为该品种设置了规则“持仓仅允许遵照 FIFO 规则平仓”
平仓有三种主要方法:
- 从客户终端平仓:交易者手工平仓,利用交易机器人,基于信号服务订阅,等等。 如果尝试平仓不符合 FIFO 规则,交易者将收到相应的错误。
- 由止损或止盈激活时平仓:这些订单在服务器端处理,因此交易员(终端)无需请求平仓,而是由服务器启动。 如果持仓触发止损或止盈,且该笔持仓不符合 FIFO 规则(同一品种有一笔更久的持仓),则该笔持仓将不会被平仓。
- 触发爆仓时平仓:此类操作也在服务器端处理。 在正常模式下,遵照 FIFO 平仓被禁用,而在爆仓情况下从亏损最多的持仓开始平仓。 如果启用此选项,则将额外检查亏损持仓的开仓时间。 服务器判断每个品种的亏损持仓,搜索每个品种的最久持仓,然后将所发现持仓中亏损最多的一笔平仓。
考虑到所有这些,新的属性已添加到品种和帐户对象。
新的属性已添加到帐户整数型属性块中,从而整数型属性的数量已增加到 11:
//+------------------------------------------------------------------+ //| Account integer properties | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_PROP_INTEGER { ACCOUNT_PROP_LOGIN, // Account number ACCOUNT_PROP_TRADE_MODE, // Trading account type ACCOUNT_PROP_LEVERAGE, // Leverage ACCOUNT_PROP_LIMIT_ORDERS, // Maximum allowed number of active pending orders ACCOUNT_PROP_MARGIN_SO_MODE, // Mode of setting the minimum available margin level ACCOUNT_PROP_TRADE_ALLOWED, // Permission to trade for the current account from the server side ACCOUNT_PROP_TRADE_EXPERT, // Permission to trade for an EA from the server side ACCOUNT_PROP_MARGIN_MODE, // Margin calculation mode ACCOUNT_PROP_CURRENCY_DIGITS, // Number of digits for an account currency necessary for accurate display of trading results ACCOUNT_PROP_SERVER_TYPE, // Trade server type (MetaTrader5, MetaTrader4) ACCOUNT_PROP_FIFO_CLOSE // Flag of a position closure by FIFO rule only }; #define ACCOUNT_PROP_INTEGER_TOTAL (11) // Total number of integer properties #define ACCOUNT_PROP_INTEGER_SKIP (0) // Number of integer account properties not used in sorting //+------------------------------------------------------------------+
整数型属性的新排序标准已添加到可能的帐户排序标准块之中:
//+------------------------------------------------------------------+ //| Possible account sorting criteria | //+------------------------------------------------------------------+ #define FIRST_ACC_DBL_PROP (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP) #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 { //--- Sort by integer properties SORT_BY_ACCOUNT_LOGIN = 0, // Sort by account number SORT_BY_ACCOUNT_TRADE_MODE, // Sort by trading account type SORT_BY_ACCOUNT_LEVERAGE, // Sort by leverage SORT_BY_ACCOUNT_LIMIT_ORDERS, // Sort by maximum acceptable number of existing pending orders SORT_BY_ACCOUNT_MARGIN_SO_MODE, // Sort by mode for setting the minimum acceptable margin level SORT_BY_ACCOUNT_TRADE_ALLOWED, // Sort by permission to trade for the current account SORT_BY_ACCOUNT_TRADE_EXPERT, // Sort by permission to trade for an EA SORT_BY_ACCOUNT_MARGIN_MODE, // Sort by margin calculation mode SORT_BY_ACCOUNT_CURRENCY_DIGITS, // Sort by number of digits for an account currency SORT_BY_ACCOUNT_SERVER_TYPE, // Sort by trade server type (MetaTrader5, MetaTrader4) SORT_BY_ACCOUNT_FIFO_CLOSE, // Sort by the flag of a position closure by FIFO rule only //--- Sort by real properties
品种对象属性按照类似的方式添加。
字符串型属性块含有两个新属性,而字符串型属性的数量已增加到 13:
//+------------------------------------------------------------------+ //| Symbol string properties | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_PROP_STRING { SYMBOL_PROP_NAME = (SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL), // Symbol name SYMBOL_PROP_BASIS, // Name of the underlaying asset for a derivative symbol SYMBOL_PROP_CURRENCY_BASE, // Instrument base currency SYMBOL_PROP_CURRENCY_PROFIT, // Profit currency SYMBOL_PROP_CURRENCY_MARGIN, // Margin currency SYMBOL_PROP_BANK, // Source of the current quote SYMBOL_PROP_DESCRIPTION, // String description of a symbol SYMBOL_PROP_FORMULA, // The formula used for custom symbol pricing SYMBOL_PROP_ISIN, // The name of a trading symbol in the international system of securities identification numbers (ISIN) SYMBOL_PROP_PAGE, // The web page containing symbol information SYMBOL_PROP_PATH, // Location in the symbol tree SYMBOL_PROP_CATEGORY, // Symbol category SYMBOL_PROP_EXCHANGE // Name of an exchange a symbol is traded on }; #define SYMBOL_PROP_STRING_TOTAL (13) // Total number of string properties //+------------------------------------------------------------------+
依照品种的字符串型属性排序的两个新条件已添加到可能的品种排序条件列表中:
//--- Sort by string properties SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP, // Sort by a symbol name SORT_BY_SYMBOL_BASIS, // Sort by an underlying asset of a derivative SORT_BY_SYMBOL_CURRENCY_BASE, // Sort by a base currency of a symbol SORT_BY_SYMBOL_CURRENCY_PROFIT, // Sort by a profit currency SORT_BY_SYMBOL_CURRENCY_MARGIN, // Sort by a margin currency SORT_BY_SYMBOL_BANK, // Sort by a feeder of the current quote SORT_BY_SYMBOL_DESCRIPTION, // Sort by a symbol string description SORT_BY_SYMBOL_FORMULA, // Sort by the formula used for custom symbol pricing SORT_BY_SYMBOL_ISIN, // Sort by the name of a symbol in the ISIN system SORT_BY_SYMBOL_PAGE, // Sort by an address of the web page containing symbol information SORT_BY_SYMBOL_PATH, // Sort by a path in the symbol tree SORT_BY_SYMBOL_CATEGORY, // Sort by symbol category SORT_BY_SYMBOL_EXCHANGE // Sort by a name of an exchange a symbol is traded on }; //+------------------------------------------------------------------+
此外,还添加了一些函数库文本消息的索引新常量,以便协同对象、类和方法操作的新属性。
我们来研究 Datas.mqh 文件中的新常量:
//+------------------------------------------------------------------+ //| List of the library's text message indices | //+------------------------------------------------------------------+ enum ENUM_MESSAGES_LIB { MSG_LIB_PARAMS_LIST_BEG=ERR_USER_ERROR_FIRST, // Beginning of the parameter list MSG_LIB_PARAMS_LIST_END, // End of the parameter list MSG_LIB_PROP_NOT_SUPPORTED, // Property not supported MSG_LIB_PROP_NOT_SUPPORTED_MQL4, // Property not supported in MQL4 MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155, // Property not supported in MetaTrader 5 versions lower than 2155 MSG_LIB_PROP_NOT_SUPPORTED_POSITION, // Property not supported for position MSG_LIB_PROP_NOT_SUPPORTED_PENDING, // Property not supported for pending order MSG_LIB_PROP_NOT_SUPPORTED_MARKET, // Property not supported for market order MSG_LIB_PROP_NOT_SUPPORTED_MARKET_HIST, // Property not supported for historical market order MSG_LIB_PROP_NOT_SET, // Value not set MSG_LIB_PROP_EMPTY, // Not set MSG_LIB_SYS_ERROR, // Error MSG_LIB_SYS_NOT_SYMBOL_ON_SERVER, // Error. No such symbol on server MSG_LIB_SYS_NOT_SYMBOL_ON_LIST, // Error. No such symbol in the list of used symbols: MSG_LIB_SYS_FAILED_PUT_SYMBOL, // Failed to place to market watch. Error: MSG_LIB_SYS_NOT_GET_PRICE, // Failed to get current prices. Error: MSG_LIB_SYS_NOT_GET_MARGIN_RATES, // Failed to get margin ratios. Error: MSG_LIB_SYS_NOT_GET_DATAS, // Failed to get data MSG_LIB_SYS_FAILED_CREATE_STORAGE_FOLDER, // Failed to create folder for storing files. Error: MSG_LIB_SYS_FAILED_ADD_ACC_OBJ_TO_LIST, // Error. Failed to add current account object to collection list MSG_LIB_SYS_FAILED_CREATE_CURR_ACC_OBJ, // Error. Failed to create account object with current account data MSG_LIB_SYS_FAILED_OPEN_FILE_FOR_WRITE, // Could not open file for writing MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL, // Input error: no symbol MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ, // Failed to create symbol object MSG_LIB_SYS_FAILED_ADD_SYM_OBJ, // Failed to add symbol MSG_LIB_SYS_NOT_GET_CURR_PRICES, // Failed to get current prices by event symbol MSG_LIB_SYS_EVENT_ALREADY_IN_LIST, // This event is already in the list MSG_LIB_SYS_FILE_RES_ALREADY_IN_LIST, // This file already created and added to list: MSG_LIB_SYS_FAILED_CREATE_RES_LINK, // Error. Failed to create object pointing to resource file MSG_LIB_SYS_ERROR_ALREADY_CREATED_COUNTER, // Error. Counter with ID already created MSG_LIB_SYS_FAILED_CREATE_COUNTER, // Failed to create timer counter MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST, // Error creating temporary list MSG_LIB_SYS_ERROR_NOT_MARKET_LIST, // Error. This is not a market collection list MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST, // Error. This is not a history collection list MSG_LIB_SYS_FAILED_ADD_ORDER_TO_LIST, // Could not add order to the list MSG_LIB_SYS_FAILED_ADD_DEAL_TO_LIST, // Could not add deal to the list MSG_LIB_SYS_FAILED_ADD_CTRL_ORDER_TO_LIST, // Failed to add control order MSG_LIB_SYS_FAILED_ADD_CTRL_POSITION_TO_LIST, // Failed to add control position MSG_LIB_SYS_FAILED_ADD_MODIFIED_ORD_TO_LIST, // Could not add modified order to the list of modified orders MSG_LIB_SYS_FAILED_CREATE_TIMER, // Failed to create timer. Error: MSG_LIB_SYS_NO_TICKS_YET, // No ticks yet MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT, // Could not create object structure MSG_LIB_SYS_FAILED_WRITE_UARRAY_TO_FILE, // Could not write uchar array to file MSG_LIB_SYS_FAILED_LOAD_UARRAY_FROM_FILE, // Could not load uchar array from file MSG_LIB_SYS_FAILED_CREATE_OBJ_STRUCT_FROM_UARRAY, // Could not create object structure from uchar array MSG_LIB_SYS_FAILED_SAVE_OBJ_STRUCT_TO_UARRAY, // Failed to save object structure to uchar array, error MSG_LIB_SYS_ERROR_INDEX, // Error. "index" value should be within 0 - 3 MSG_LIB_SYS_ERROR_FAILED_CONV_TO_LOWERCASE, // Failed to convert string to lowercase, error //--- COrder MSG_ORD_BUY, // Buy MSG_ORD_SELL, // Sell MSG_ORD_TO_BUY, // Buy order MSG_ORD_TO_SELL, // Sell order MSG_DEAL_TO_BUY, // Buy deal MSG_DEAL_TO_SELL, // Sell deal MSG_ORD_MARKET, // Market order MSG_ORD_HISTORY, // Historical order MSG_ORD_DEAL, // Deal MSG_ORD_POSITION, // Position MSG_ORD_PENDING_ACTIVE, // Active pending order MSG_ORD_PENDING, // Pending order MSG_ORD_UNKNOWN_TYPE, // Unknown order type MSG_POS_UNKNOWN_TYPE, // Unknown position type MSG_POS_UNKNOWN_DEAL, // Unknown deal type //--- //--- MSG_SYM_PROP_NAME, // Symbol name MSG_SYM_PROP_BASIS, // Underlying asset of derivative MSG_SYM_PROP_CURRENCY_BASE, // Basic currency of symbol MSG_SYM_PROP_CURRENCY_PROFIT, // Profit currency MSG_SYM_PROP_CURRENCY_MARGIN, // Margin currency MSG_SYM_PROP_BANK, // Feeder of the current quote MSG_SYM_PROP_DESCRIPTION, // Symbol description MSG_SYM_PROP_FORMULA, // Formula used for custom symbol pricing MSG_SYM_PROP_ISIN, // Symbol name in ISIN system MSG_SYM_PROP_PAGE, // Address of web page containing symbol information MSG_SYM_PROP_PATH, // Location in symbol tree MSG_SYM_PROP_CAYEGORY, // Symbol category MSG_SYM_PROP_EXCHANGE, // Name of an exchange a symbol is traded on //--- //--- MSG_SYM_TRADE_MODE_DISABLED, // Trade disabled for symbol MSG_SYM_TRADE_MODE_LONGONLY, // Only long positions allowed MSG_SYM_TRADE_MODE_SHORTONLY, // Only short positions allowed MSG_SYM_TRADE_MODE_CLOSEONLY, // Enable close only MSG_SYM_TRADE_MODE_FULL, // No trading limitations MSG_SYM_MARKET_ORDER_DISABLED, // Market orders disabled MSG_SYM_LIMIT_ORDER_DISABLED, // Limit orders disabled MSG_SYM_STOP_ORDER_DISABLED, // Stop orders disabled MSG_SYM_STOP_LIMIT_ORDER_DISABLED, // StopLimit orders disabled MSG_SYM_SL_ORDER_DISABLED, // StopLoss orders disabled MSG_SYM_TP_ORDER_DISABLED, // TakeProfit orders disabled MSG_SYM_CLOSE_BY_ORDER_DISABLED, // CloseBy orders disabled //--- //--- CAccount MSG_ACC_PROP_LOGIN, // Account number MSG_ACC_PROP_TRADE_MODE, // Trading account type MSG_ACC_PROP_LEVERAGE, // Leverage MSG_ACC_PROP_LIMIT_ORDERS, // Maximum allowed number of active pending orders MSG_ACC_PROP_MARGIN_SO_MODE, // Mode of setting the minimum available margin level MSG_ACC_PROP_TRADE_ALLOWED, // Trading permission of the current account MSG_ACC_PROP_TRADE_EXPERT, // Trading permission of an EA MSG_ACC_PROP_MARGIN_MODE, // Margin calculation mode MSG_ACC_PROP_CURRENCY_DIGITS, // Number of decimal places for the account currency MSG_ACC_PROP_SERVER_TYPE, // Trade server type MSG_ACC_PROP_FIFO_CLOSE, // Flag of a position closure by FIFO rule only //--- //--- CTrading MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED, // Trade operations are not allowed in the terminal (the AutoTrading button is disabled) MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED, // EA is not allowed to trade (F7 --> Common --> Allow Automated Trading) MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED, // Trading is disabled for the current account MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED, // Trading on the trading server side is disabled for EAs on the current account MSG_LIB_TEXT_TERMINAL_NOT_CONNECTED, // No connection to the trade server MSG_LIB_TEXT_REQUEST_REJECTED_DUE, // Request was rejected before sending to the server due to: MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR, // Insufficient funds for opening a position: MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED, // Exceeded maximum allowed aggregate volume of orders and positions in one direction MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME, // Request volume is less than the minimum acceptable one MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME, // Request volume exceeds the maximum acceptable one MSG_LIB_TEXT_CLOSE_BY_ORDERS_DISABLED, // Close by is disabled MSG_LIB_TEXT_INVALID_VOLUME_STEP, // Request volume is not a multiple of the minimum lot change step gradation MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL, // Symbols of opposite positions are not equal };
另外,我们在文本消息数组中添加与声明的常量相对应的文本:
//+------------------------------------------------------------------+ //| Array of predefined library messages | //| (1) in user's country language | //| (2) in the international language (English) | //| (3) any additional language. | //| The default languages are English and Russian. | //| To add the necessary number of other languages, simply | //| set the total number of used languages in TOTAL_LANG | //| and add the necessary translation after the English text | //+------------------------------------------------------------------+ string messages_library[][TOTAL_LANG]= { {"Начало списка параметров","Beginning of event parameter list"}, {"Конец списка параметров","End of parameter list"}, {"Свойство не поддерживается","Property not supported"}, {"Свойство не поддерживается в MQL4","Property not supported in MQL4"}, {"Свойство не поддерживается в MetaTrader5 версии ниже 2155","Property not supported in MetaTrader 5, build lower than 2155"}, {"Свойство не поддерживается у позиции","Property not supported for position"}, {"Свойство не поддерживается у отложенного ордера","Property not supported for pending order"}, {"Свойство не поддерживается у маркет-ордера","Property not supported for market order"}, {"Свойство не поддерживается у исторического маркет-ордера","Property not supported for historical market order"}, {"Значение не задано","Value not set"}, {"Отсутствует","Not set"}, {"Ошибка ","Error "}, {"Ошибка. Такого символа нет на сервере","Error. No such symbol on server"}, {"Ошибка. Такого символа нет в списке используемых символов: ","Error. This symbol is not in the list of symbols used: "}, {"Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in market watch. Error: "}, {"Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "}, {"Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "}, {"Не удалось получить данные ","Failed to get data of "}, {"Не удалось создать папку хранения файлов. Ошибка: ","Could not create file storage folder. Error: "}, {"Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию","Error. Failed to add current account object to collection list"}, {"Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта","Error. Failed to create account object with current account data"}, {"Не удалось открыть для записи файл ","Could not open file for writing: "}, {"Ошибка входных данных: нет символа ","Input error: no "}, {"Не удалось создать объект-символ ","Failed to create symbol object "}, {"Не удалось добавить символ ","Failed to add "}, {"Не удалось получить текущие цены по символу события ","Failed to get current prices by event symbol "}, {"Такое событие уже есть в списке","This event already in the list"}, {"Такой файл уже создан и добавлен в список: ","This file has already been created and added to list: "}, {"Ошибка. Не удалось создать объект-указатель на файл ресурса","Error. Failed to create resource file link object"}, {"Ошибка. Уже создан счётчик с идентификатором ","Error. Already created counter with id "}, {"Не удалось создать счётчик таймера ","Failed to create timer counter "}, {"Ошибка создания временного списка","Error creating temporary list"}, {"Ошибка. Список не является списком рыночной коллекции","Error. The list is not a list of market collection"}, {"Ошибка. Список не является списком исторической коллекции","Error. The list is not a list of history collection"}, {"Не удалось добавить ордер в список","Could not add order to list"}, {"Не удалось добавить сделку в список","Could not add deal to list"}, {"Не удалось добавить контрольный ордер ","Failed to add control order "}, {"Не удалось добавить контрольую позицию ","Failed to add control position "}, {"Не удалось добавить модифицированный ордер в список изменённых ордеров","Could not add modified order to list of modified orders"}, {"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: "}, //--- COrder {"Buy","Buy"}, {"Sell","Sell"}, {"Ордер на покупку","Buy order"}, {"Ордер на продажу","Sell order"}, {"Сделка на покупку","Buy deal"}, {"Сделка на продажу","Sell deal"}, {"Маркет-ордер","Market order"}, {"Исторический ордер","History order"}, {"Сделка","Deal"}, {"Позиция","Active position"}, {"Установленный отложенный ордер","Active pending order"}, {"Отложенный ордер","Pending order"}, {"Неизвестный тип ордера","Unknown order type"}, {"Неизвестный тип позиции","Unknown position type"}, {"Неизвестный тип сделки","Unknown deal type"}, //--- {"Путь в дереве символов","Path in symbol tree"}, {"Название категории или сектора, к которой принадлежит торговый символ","Name of sector or category trading symbol belongs to"}, {"Название биржи или площадки, на которой торгуется символ","Name of exchange financial symbol traded in"}, //--- {"Форекс символ","Forex symbol"}, {"Разрешены только операции закрытия позиций","Close only"}, {"Нет ограничений на торговые операции","No trade restrictions"}, {"Торговля рыночными ордерами запрещена","Trading through market orders prohibited"}, {"Установка Limit-ордеров запрещена","Limit orders prohibited"}, {"Установка Stop-ордеров запрещена","Stop orders prohibited"}, {"Установка StopLimit-ордеров запрещена","StopLimit orders prohibited"}, {"Установка StopLoss-ордеров запрещена","StopLoss orders prohibited"}, {"Установка TakeProfit-ордеров запрещена","TakeProfit orders prohibited"}, {"Установка CloseBy-ордеров запрещена","CloseBy orders prohibited"}, //--- {"Торговля по запросу","Execution by request"}, {"Торговля по потоковым ценам","Instant execution"}, {"Исполнение ордеров по рынку","Market execution"}, {"Биржевое исполнение","Exchange execution"}, //--- //--- CAccount {"Номер счёта","Account number"}, {"Тип торгового счета","Account trade mode"}, {"Размер предоставленного плеча","Account leverage"}, {"Максимально допустимое количество действующих отложенных ордеров","Maximum allowed number of active pending orders"}, {"Режим задания минимально допустимого уровня залоговых средств","Mode for setting minimal allowed margin"}, {"Разрешенность торговли для текущего счета","Allowed trade for the current account"}, {"Разрешенность торговли для эксперта","Allowed trade for Expert Advisor"}, {"Режим расчета маржи","Margin calculation mode"}, {"Количество знаков после запятой для валюты счета","Number of decimal places in account currency"}, {"Тип торгового сервера","Type of trading server"}, {"Признак закрытия позиций только по правилу FIFO","Sign of closing positions only according to FIFO rule"}, //--- {"Баланс счета","Account balance"}, //--- CEngine {"С момента последнего запуска ЕА торговых событий не было","No trade events since the last launch of EA"}, {"Не удалось получить описание последнего торгового события","Failed to get description of the last trading event"}, {"Не удалось получить список открытых позиций","Failed to get open positions list"}, {"Не удалось получить список установленных ордеров","Failed to get pending orders list"}, {"Нет открытых позиций","No open positions"}, {"Нет установленных ордеров","No placed orders"}, {"В терминале нет разрешения на проведение торговых операций (отключена кнопка \"Авто-торговля\")","No permission to conduct trading operations in terminal (\"AutoTrading\" button disabled)"}, {"Для советника нет разрешения на проведение торговых операций (F7 --> Общие --> \"Разрешить автоматическую торговлю\")","EA does not have permission to conduct trading operations (F7 --> Common --> \"Allow Automatic Trading\")"}, {"Для текущего счёта запрещена торговля","Trading prohibited for the current account"}, {"Для советников на текущем счёте запрещена торговля на стороне торгового сервера","From the side of trade server, trading for EA on the current account prohibited"}, {"Нет связи с торговым сервером","No connection to trade server"}, {"Запрос отклонён до отправки на сервер по причине:","Request rejected before being sent to server due to:"}, {"Не хватает средств на открытие позиции: ","Not enough money to open position: "}, {"Превышен максимальный совокупный объём ордеров и позиций в одном направлении","Exceeded maximum total volume of orders and positions in one direction"}, {"Объём в запросе меньше минимально-допустимого","Volume in request less than minimum allowable"}, {"Объём в запросе больше максимально-допустимого","Volume in request greater than maximum allowable"}, {"Закрытие встречным запрещено","CloseBy orders prohibited"}, {"Объём в запросе не кратен минимальной градации шага изменения лота","Volume in request not a multiple of minimum gradation of step for changing lot"}, {"Символы встречных позиций не равны","Symbols of two opposite positions not equal"}, }; //+---------------------------------------------------------------------+ //| Array of messages for trade server return codes (10004 - 10045) | //| (1) in user's country language | //| (2) in the international language | //+---------------------------------------------------------------------+ string messages_ts_ret_code[][TOTAL_LANG]= { {"Реквота","Requote"}, // 10004 {"Неизвестный код возврата торгового сервера","Unknown trading server return code"}, // 10005 {"Запрос отклонен","Request rejected"}, // 10006 {"Запрос отменен трейдером","Request canceled by trader"}, // 10007 {"Ордер размещен","Order placed"}, // 10008 {"Заявка выполнена","Request completed"}, // 10009 {"Заявка выполнена частично","Only part of request completed"}, // 10010 {"Ошибка обработки запроса","Request processing error"}, // 10011 {"Запрос отменен по истечению времени","Request canceled by timeout"}, // 10012 {"Неправильный запрос","Invalid request"}, // 10013 {"Неправильный объем в запросе","Invalid volume in request"}, // 10014 {"Неправильная цена в запросе","Invalid price in request"}, // 10015 {"Неправильные стопы в запросе","Invalid stops in request"}, // 10016 {"Торговля запрещена","Trading disabled"}, // 10017 {"Рынок закрыт","Market closed"}, // 10018 {"Нет достаточных денежных средств для выполнения запроса","Not enough money to complete request"}, // 10019 {"Цены изменились","Prices changed"}, // 10020 {"Отсутствуют котировки для обработки запроса","No quotes to process request"}, // 10021 {"Неверная дата истечения ордера в запросе","Invalid order expiration date in request"}, // 10022 {"Состояние ордера изменилось","Order state changed"}, // 10023 {"Слишком частые запросы","Too frequent requests"}, // 10024 {"В запросе нет изменений","No changes in request"}, // 10025 {"Автотрейдинг запрещен сервером","Autotrading disabled by server"}, // 10026 {"Автотрейдинг запрещен клиентским терминалом","Autotrading disabled by client terminal"}, // 10027 {"Запрос заблокирован для обработки","Request locked for processing"}, // 10028 {"Ордер или позиция заморожены","Order or position frozen"}, // 10029 {"Указан неподдерживаемый тип исполнения ордера по остатку","Invalid order filling type"}, // 10030 {"Нет соединения с торговым сервером","No connection with trade server"}, // 10031 {"Операция разрешена только для реальных счетов","Operation allowed only for live accounts"}, // 10032 {"Достигнут лимит на количество отложенных ордеров","Number of pending orders reached limit"}, // 10033 {"Достигнут лимит на объем ордеров и позиций для данного символа","Volume of orders and positions for symbol reached limit"}, // 10034 {"Неверный или запрещённый тип ордера","Incorrect or prohibited order type"}, // 10035 {"Позиция с указанным идентификатором уже закрыта","Position with specified identifier already closed"}, // 10036 {"Неизвестный код возврата торгового сервера","Unknown trading server return code"}, // 10037 {"Закрываемый объем превышает текущий объем позиции","Close volume exceeds the current position volume"}, // 10038 {"Для указанной позиции уже есть ордер на закрытие","Close order already exists for specified position"}, // 10039 {"Достигнут лимит на количество открытых позиций","Number of positions reached limit"}, // 10040 { "Запрос на активацию отложенного ордера отклонен, а сам ордер отменен", // 10041 "Pending order activation request rejected, order canceled" }, { "Запрос отклонен, так как на символе установлено правило \"Разрешены только длинные позиции\"", // 10042 "Request rejected, because \"Only long positions are allowed\" rule set for symbol" }, { "Запрос отклонен, так как на символе установлено правило \"Разрешены только короткие позиции\"", // 10043 "Request rejected, because \"Only short positions are allowed\" rule set for symbol" }, { "Запрос отклонен, так как на символе установлено правило \"Разрешено только закрывать существующие позиции\"", // 10044 "Request rejected because \"Only position closing is allowed\" rule set for symbol" }, { "Запрос отклонен, так как для торгового счета установлено правило \"Разрешено закрывать существующие позиции только по правилу FIFO\"", // 10045 "Request rejected, because \"Position closing is allowed only by FIFO rule\" flag set for trading account" }, }; //+------------------------------------------------------------------+
众所周知,所有已执行的动作皆旨在将新消息添加到函数库中,并通过消息常量中编码的索引来访问消息。
现在,我们来改进 \MQL5\Include\DoEasy\Services\Message.mqh 中的消息类。
在类的公开部分中,声明停止播放任何音频文件的方法:
public: //--- (1) Display a text message in the journal, send a push notification and e-mail, //--- (2) Display a message by ID, send a push notification and e-mail, //--- (3) play an audio file //--- (4) Stop playing any sound static bool Out(const string text,const bool push=false,const bool mail=false,const string subject=NULL); static bool OutByID(const int msg_id,const bool code=true); static bool PlaySound(const string file_name); static bool StopPlaySound(void); //--- Return (1) a message, (2) a code in the "(code)" format
将其实现写在类主体之外:
//+------------------------------------------------------------------+ //| Stop playing any sound | //+------------------------------------------------------------------+ bool CMessage::StopPlaySound(void) { bool res=::PlaySound(NULL); CMessage::m_global_error=(res ? ERR_SUCCESS : ::GetLastError()); return res; } //+------------------------------------------------------------------+
这一切都很简单:当传递 NULL 常量作为文件名时,PlaySound() 标准函数停止当前播放的音频文件。
为了能够播放终端发行包中内含的标准音频文件,我们需要指定一个文件名(以便从文件的标准位置播放声音:终端_文件夹\Sounds),或者指定一个非标准音频文件,其路径前缀需包含一个双斜杠和存储子文件夹。
所以,我们应该改进 PlaySound() 方法:
//+------------------------------------------------------------------+ //| Play an audio file | //+------------------------------------------------------------------+ bool CMessage::PlaySound(const string file_name) { if(file_name==NULL) return true; string pref=(file_name==SND_ALERT || file_name==SND_ALERT2 || file_name==SND_CONNECT || file_name==SND_DISCONNECT || file_name==SND_EMAIL || file_name==SND_EXPERT || file_name==SND_NEWS || file_name==SND_OK || file_name==SND_REQUEST || file_name==SND_STOPS || file_name==SND_TICK || file_name==SND_TIMEOUT || file_name==SND_WAIT ? "" : "\\Files\\"); bool res=::PlaySound(pref+file_name); CMessage::m_global_error=(res ? ERR_SUCCESS : ::GetLastError()); return res; } //+------------------------------------------------------------------+
我们在此拥有什么?
如果文件名包含标准音频文件的名称,在文件名前缀里写入空字符串。
否则,将双斜线和包含函数库声音的子文件夹的名称添加进前缀。
然后,由前缀和传递给方法的名称组成文件名。
现在将名称传递给 PlaySound() 函数时,将自动选择声音文件的位置(标准声音文件夹,或函数库音频文件文件夹),并播放相应的文件。
现在我们有了新的交易服务器返回代码。 在按照 ID 从文本数组接收消息的方法 void CMessage::GetTextByID() 当中, 修改交易服务器返回代码的极限:增加 1 (用 10045 替换 10044):
//--- Runtime errors (Economic calendar 5400 - 5402) msg_id>5399 && msg_id<5403 ? messages_runtime_calendar[msg_id-5400][m_lang_num] : //--- Trade server return codes (10004 - 10045) msg_id>10003 && msg_id<10046 ? messages_ts_ret_code[msg_id-10004][m_lang_num] : #else // MQL4 msg_id>0 && msg_id<10 ? messages_ts_ret_code_mql4[msg_id][m_lang_num] : msg_id>63 && msg_id<66 ? messages_ts_ret_code_mql4[msg_id-54][m_lang_num] : msg_id>127 && msg_id<151 ? messages_ts_ret_code_mql4[msg_id-116][m_lang_num] : msg_id<4000 ? messages_ts_ret_code_mql4[26][m_lang_num] : //--- MQL4 runtime errors (4000 - 4030) msg_id<4031 ? messages_runtime_4000_4030[msg_id-4000][m_lang_num] : //--- MQL4 runtime errors (4050 - 4075) msg_id>4049 && msg_id<4076 ? messages_runtime_4050_4075[msg_id-4050][m_lang_num] : //--- MQL4 runtime errors (4099 - 4112) msg_id>4098 && msg_id<4113 ? messages_runtime_4099_4112[msg_id-4099][m_lang_num] : //--- MQL4 runtime errors (4200 - 4220) msg_id>4199 && msg_id<4221 ? messages_runtime_4200_4220[msg_id-4200][m_lang_num] : //--- MQL4 runtime errors (4250 - 4266) msg_id>4249 && msg_id<4267 ? messages_runtime_4250_4266[msg_id-4250][m_lang_num] : //--- MQL4 runtime errors (5001 - 5029) msg_id>5000 && msg_id<5030 ? messages_runtime_5001_5029[msg_id-5001][m_lang_num] : //--- MQL4 runtime errors (5200 - 5203) msg_id>5199 && msg_id<5204 ? messages_runtime_5200_5203[msg_id-5200][m_lang_num] : #endif //--- Library messages (ERR_USER_ERROR_FIRST) msg_id>ERR_USER_ERROR_FIRST-1 ? messages_library[msg_id-ERR_USER_ERROR_FIRST][m_lang_num] : messages_library[MSG_LIB_SYS_ERROR_CODE_OUT_OF_RANGE-ERR_USER_ERROR_FIRST][m_lang_num] );
函数库消息类的修改至此结束。
有时,当订单被激活了,我们需要利用订单类型来搜索仓位的方向。 假设我们放置了一笔 ORDER_TYPE_BUY_LIMIT 类型的挂单。 一经激活,就会放置 ORDER_TYPE_BUY 入场订单,从而导致 DEAL_TYPE_BUY 类型的 DEAL_ENTRY_IN 成交。 这笔成交会导致仓位类型为 POSITION_TYPE_BUY。
为了按照挂单类型搜索仓位方向,我们需要接收入场订单类型(在当前示例中为 ORDER_TYPE_BUY)。
之前,我们使用三元运算符来定义它,同时将其与挂单类型进行比较。 但是,这样做更容易:我们只需将查验的订单类型除以 2 并取其余数。 类型 0 (ORDER_TYPE_BUY) 总是返回偶数,而类型 1 (ORDER_TYPE_SELL) 会返回奇数。 我们已经在某些函数和方法中实现了这一点。
在 (\MQL5\Include\DoEasy\Objects\Orders\Order.mqh) 抽象订单类:
//+------------------------------------------------------------------+ //| Return the type by direction | //+------------------------------------------------------------------+ long COrder::OrderTypeByDirection(void) const { ENUM_ORDER_STATUS status=(ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS); if(status==ORDER_STATUS_MARKET_POSITION) { return (ENUM_ORDER_TYPE)this.OrderType(); } else if(status==ORDER_STATUS_MARKET_PENDING || status==ORDER_STATUS_HISTORY_PENDING) { return ENUM_ORDER_TYPE(this.OrderType()%2); } else if(status==ORDER_STATUS_MARKET_ORDER || status==ORDER_STATUS_HISTORY_ORDER) { return this.OrderType(); } else if(status==ORDER_STATUS_DEAL) { return ( (ENUM_DEAL_TYPE)this.TypeOrder()==DEAL_TYPE_BUY ? ORDER_TYPE_BUY : (ENUM_DEAL_TYPE)this.TypeOrder()==DEAL_TYPE_SELL ? ORDER_TYPE_SELL : WRONG_VALUE ); } return WRONG_VALUE; } //+------------------------------------------------------------------+
并在服务函数函数库 (\MQL5\Include\DoEasy\Services\DELib.mqh):
//+------------------------------------------------------------------+ //| Return position type by order type | //+------------------------------------------------------------------+ ENUM_POSITION_TYPE PositionTypeByOrderType(ENUM_ORDER_TYPE type_order) { if(type_order==ORDER_TYPE_CLOSE_BY) return WRONG_VALUE; return ENUM_POSITION_TYPE(type_order%2); } //+------------------------------------------------------------------+
在服务函数的同一文件中将返回订单名称的函数一并修改。 显示订单描述所需的旗标也已添加。. 根据该旗标,返回的入场订单类型,亦或接收该入场订单说明,接收内容可为空。 订单类型描述已添加到返回的挂单类型:
//+------------------------------------------------------------------+ //| Return the order name | //+------------------------------------------------------------------+ string OrderTypeDescription(const ENUM_ORDER_TYPE type,bool as_order=true,bool need_prefix=true) { string pref= ( !need_prefix ? "" : #ifdef __MQL5__ CMessage::Text(MSG_ORD_MARKET) #else/*__MQL4__*/(as_order ? CMessage::Text(MSG_ORD_MARKET) : CMessage::Text(MSG_ORD_POSITION)) #endif ); return ( type==ORDER_TYPE_BUY_LIMIT ? CMessage::Text(MSG_ORD_PENDING)+" Buy Limit" : type==ORDER_TYPE_BUY_STOP ? CMessage::Text(MSG_ORD_PENDING)+" Buy Stop" : type==ORDER_TYPE_SELL_LIMIT ? CMessage::Text(MSG_ORD_PENDING)+" Sell Limit" : type==ORDER_TYPE_SELL_STOP ? CMessage::Text(MSG_ORD_PENDING)+" Sell Stop" : #ifdef __MQL5__ type==ORDER_TYPE_BUY_STOP_LIMIT ? CMessage::Text(MSG_ORD_PENDING)+" Buy Stop Limit" : type==ORDER_TYPE_SELL_STOP_LIMIT ? CMessage::Text(MSG_ORD_PENDING)+" Sell Stop Limit" : type==ORDER_TYPE_CLOSE_BY ? CMessage::Text(MSG_ORD_CLOSE_BY) : #else type==ORDER_TYPE_BALANCE ? CMessage::Text(MSG_LIB_PROP_BALANCE) : type==ORDER_TYPE_CREDIT ? CMessage::Text(MSG_LIB_PROP_CREDIT) : #endif type==ORDER_TYPE_BUY ? pref+" Buy" : type==ORDER_TYPE_SELL ? pref+" Sell" : CMessage::Text(MSG_ORD_UNKNOWN_TYPE) ); } //+------------------------------------------------------------------+
由于引入了新的品种和帐户对象属性,因此我们需要将这些属性添加到对象中。
打开 \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh,并进行必要的修改。
在类的保护部分中,添加方法定义用于接收两个新属性:
protected: //--- Protected parametric constructor CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index); //--- Get and return integer properties of a selected symbol from its parameters bool SymbolExists(const string name) const; long SymbolExists(void) const; long SymbolCustom(void) const; long SymbolChartMode(void) const; long SymbolMarginHedgedUseLEG(void) const; long SymbolOrderFillingMode(void) const; long SymbolOrderMode(void) const; long SymbolExpirationMode(void) const; long SymbolOrderGTCMode(void) const; long SymbolOptionMode(void) const; long SymbolOptionRight(void) const; long SymbolBackgroundColor(void) const; long SymbolCalcMode(void) const; long SymbolSwapMode(void) const; long SymbolDigitsLot(void); int SymbolDigitsBySwap(void); //--- Get and return real properties of a selected symbol from its parameters double SymbolBidHigh(void) const; double SymbolBidLow(void) const; double SymbolVolumeReal(void) const; double SymbolVolumeHighReal(void) const; double SymbolVolumeLowReal(void) const; double SymbolOptionStrike(void) const; double SymbolTradeAccruedInterest(void) const; double SymbolTradeFaceValue(void) const; double SymbolTradeLiquidityRate(void) const; double SymbolMarginHedged(void) const; bool SymbolMarginLong(void); bool SymbolMarginShort(void); bool SymbolMarginBuyStop(void); bool SymbolMarginBuyLimit(void); bool SymbolMarginBuyStopLimit(void); bool SymbolMarginSellStop(void); bool SymbolMarginSellLimit(void); bool SymbolMarginSellStopLimit(void); //--- Get and return string properties of a selected symbol from its parameters string SymbolBasis(void) const; string SymbolBank(void) const; string SymbolISIN(void) const; string SymbolFormula(void) const; string SymbolPage(void) const; string SymbolCategory(void) const; string SymbolExchange(void) const; //--- Search for a symbol and return the flag indicating its presence on the server bool Exist(void) const; public:
在类的公开部分里用于简化接收对象属性的代码块中,添加两个新方法的定义:
public: //+------------------------------------------------------------------+ //| Methods of a simplified access to the order object properties | //+------------------------------------------------------------------+ //--- Integer properties long Status(void) const { return this.GetProperty(SYMBOL_PROP_STATUS); } int IndexInMarketWatch(void) const { return (int)this.GetProperty(SYMBOL_PROP_INDEX_MW); } bool IsCustom(void) const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM); } color ColorBackground(void) const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR); } ENUM_SYMBOL_CHART_MODE ChartMode(void) const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE); } bool IsExist(void) const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST); } bool IsExist(const string name) const { return this.SymbolExists(name); } bool IsSelect(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT); } bool IsVisible(void) const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE); } long SessionDeals(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS); } long SessionBuyOrders(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS); } long SessionSellOrders(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS); } long Volume(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME); } long VolumeHigh(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH); } long VolumeLow(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW); } datetime Time(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME); } int Digits(void) const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS); } int DigitsLot(void) const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS); } int Spread(void) const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD); } bool IsSpreadFloat(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT); } int TicksBookdepth(void) const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH); } ENUM_SYMBOL_CALC_MODE TradeCalcMode(void) const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE); } ENUM_SYMBOL_TRADE_MODE TradeMode(void) const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE); } datetime StartTime(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME); } datetime ExpirationTime(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME); } int TradeStopLevel(void) const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL); } int TradeFreezeLevel(void) const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL); } ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void) const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE); } ENUM_SYMBOL_SWAP_MODE SwapMode(void) const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE); } ENUM_DAY_OF_WEEK SwapRollover3Days(void) const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS); } bool IsMarginHedgedUseLeg(void) const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG); } int ExpirationModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE); } int FillingModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE); } int OrderModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE); } ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void) const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE); } ENUM_SYMBOL_OPTION_MODE OptionMode(void) const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE); } ENUM_SYMBOL_OPTION_RIGHT OptionRight(void) const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT); } //--- Real properties double Bid(void) const { return this.GetProperty(SYMBOL_PROP_BID); } double BidHigh(void) const { return this.GetProperty(SYMBOL_PROP_BIDHIGH); } double BidLow(void) const { return this.GetProperty(SYMBOL_PROP_BIDLOW); } double Ask(void) const { return this.GetProperty(SYMBOL_PROP_ASK); } double AskHigh(void) const { return this.GetProperty(SYMBOL_PROP_ASKHIGH); } double AskLow(void) const { return this.GetProperty(SYMBOL_PROP_ASKLOW); } double Last(void) const { return this.GetProperty(SYMBOL_PROP_LAST); } double LastHigh(void) const { return this.GetProperty(SYMBOL_PROP_LASTHIGH); } double LastLow(void) const { return this.GetProperty(SYMBOL_PROP_LASTLOW); } double VolumeReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL); } double VolumeHighReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL); } double VolumeLowReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL); } double OptionStrike(void) const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE); } double Point(void) const { return this.GetProperty(SYMBOL_PROP_POINT); } double TradeTickValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE); } double TradeTickValueProfit(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT); } double TradeTickValueLoss(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS); } double TradeTickSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE); } double TradeContractSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE); } double TradeAccuredInterest(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST); } double TradeFaceValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE); } double TradeLiquidityRate(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE); } double LotsMin(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN); } double LotsMax(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX); } double LotsStep(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP); } double VolumeLimit(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT); } double SwapLong(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG); } double SwapShort(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT); } double MarginInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL); } double MarginMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE); } double MarginLongInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL); } double MarginBuyStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL); } double MarginBuyLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL); } double MarginBuyStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL); } double MarginLongMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE); } double MarginBuyStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE); } double MarginBuyLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE); } double MarginBuyStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE); } double MarginShortInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL); } double MarginSellStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL); } double MarginSellLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL); } double MarginSellStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL); } double MarginShortMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE); } double MarginSellStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE); } double MarginSellLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE); } double MarginSellStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE); } double SessionVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME); } double SessionTurnover(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER); } double SessionInterest(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST); } double SessionBuyOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME); } double SessionSellOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME); } double SessionOpen(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN); } double SessionClose(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE); } double SessionAW(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_AW); } double SessionPriceSettlement(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT); } double SessionPriceLimitMin(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN); } double SessionPriceLimitMax(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX); } double MarginHedged(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED); } double NormalizedPrice(const double price) const; double NormalizedLot(const double volume) const; double BidLast(void) const; double BidLastHigh(void) const; double BidLastLow(void) const; //--- String properties string Name(void) const { return this.GetProperty(SYMBOL_PROP_NAME); } string Basis(void) const { return this.GetProperty(SYMBOL_PROP_BASIS); } string CurrencyBase(void) const { return this.GetProperty(SYMBOL_PROP_CURRENCY_BASE); } string CurrencyProfit(void) const { return this.GetProperty(SYMBOL_PROP_CURRENCY_PROFIT); } string CurrencyMargin(void) const { return this.GetProperty(SYMBOL_PROP_CURRENCY_MARGIN); } string Bank(void) const { return this.GetProperty(SYMBOL_PROP_BANK); } string Description(void) const { return this.GetProperty(SYMBOL_PROP_DESCRIPTION); } string Formula(void) const { return this.GetProperty(SYMBOL_PROP_FORMULA); } string ISIN(void) const { return this.GetProperty(SYMBOL_PROP_ISIN); } string Page(void) const { return this.GetProperty(SYMBOL_PROP_PAGE); } string Path(void) const { return this.GetProperty(SYMBOL_PROP_PATH); } string Category(void) const { return this.GetProperty(SYMBOL_PROP_CATEGORY); } string Exchange(void) const { return this.GetProperty(SYMBOL_PROP_EXCHANGE); } //+------------------------------------------------------------------+
在封闭参数的类构造函数中接收以下这些新属性:
//--- Save string properties this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)] = this.m_name; this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_BASE); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_PROFIT); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_MARGIN); this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)] = ::SymbolInfoString(this.m_name,SYMBOL_DESCRIPTION); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)] = ::SymbolInfoString(this.m_name,SYMBOL_PATH); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)] = this.SymbolBasis(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)] = this.SymbolBank(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)] = this.SymbolISIN(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)] = this.SymbolFormula(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)] = this.SymbolPage(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CATEGORY)] = this.SymbolCategory(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_EXCHANGE)] = this.SymbolExchange(); //--- Save additional integer properties
在类主体外部实现用于接收两个新属性的方法:
//+------------------------------------------------------------------+ //| Return a symbol category | //+------------------------------------------------------------------+ string CSymbol::SymbolCategory(void) const { return ( #ifdef __MQL5__ ( ::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155) : ::SymbolInfoString(this.m_name,SYMBOL_CATEGORY) ) #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif ); } //+------------------------------------------------------------------+ //| Return an exchange name | //| a symbol is traded on | //+------------------------------------------------------------------+ string CSymbol::SymbolExchange(void) const { return ( #ifdef __MQL5__ ( ::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MT5_LESS_2155) : ::SymbolInfoString(this.m_name,SYMBOL_EXCHANGE) ) #else ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED_MQL4) #endif ); } //+------------------------------------------------------------------+
此处,检查 MQL5 的终端版本。 如果它小于 2155,则通知 2155 以下的版本不支持当前属性,否则返回新的 SYMBOL_EXCHANGE属性。
对于 MQL4 的情况,则通知 MQL4 不支持该属性。
在返回品种字符串型属性描述的方法里实现返回两个新属性的描述:
//+------------------------------------------------------------------+ //| Return the description of a symbol string property | //+------------------------------------------------------------------+ string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_STRING property) { return ( property==SYMBOL_PROP_NAME ? CMessage::Text(MSG_SYM_PROP_NAME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetProperty(property) ) : property==SYMBOL_PROP_BASIS ? CMessage::Text(MSG_SYM_PROP_BASIS)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_CURRENCY_BASE ? CMessage::Text(MSG_SYM_PROP_CURRENCY_BASE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_CURRENCY_PROFIT ? CMessage::Text(MSG_SYM_PROP_CURRENCY_PROFIT)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_CURRENCY_MARGIN ? CMessage::Text(MSG_SYM_PROP_CURRENCY_MARGIN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_BANK ? CMessage::Text(MSG_SYM_PROP_BANK)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_DESCRIPTION ? CMessage::Text(MSG_SYM_PROP_DESCRIPTION)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_FORMULA ? CMessage::Text(MSG_SYM_PROP_FORMULA)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_ISIN ? CMessage::Text(MSG_SYM_PROP_ISIN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_PAGE ? CMessage::Text(MSG_SYM_PROP_PAGE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_PATH ? CMessage::Text(MSG_SYM_PROP_PATH)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_CATEGORY ? CMessage::Text(MSG_SYM_PROP_CAYEGORY)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : property==SYMBOL_PROP_EXCHANGE ? CMessage::Text(MSG_SYM_PROP_EXCHANGE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)=="" || this.GetProperty(property)==NULL ? ": ("+CMessage::Text(MSG_LIB_PROP_EMPTY)+")" : ": \""+this.GetProperty(property)+"\"") ) : "" ); } //+------------------------------------------------------------------+
现在,我们将新属性添加到以下帐户对象中 \MQL5\Include\DoEasy\Objects\Accounts\Account.mqh。
在账户属性结构里编写新的字段:
//+------------------------------------------------------------------+ //| Account class | //+------------------------------------------------------------------+ class CAccount : public CBaseObj { private: struct SData { //--- Account integer properties long login; // ACCOUNT_LOGIN (Account number) int trade_mode; // ACCOUNT_TRADE_MODE (Trading account type) long leverage; // ACCOUNT_LEVERAGE (Leverage) int limit_orders; // ACCOUNT_LIMIT_ORDERS (Maximum allowed number of active pending orders) int margin_so_mode; // ACCOUNT_MARGIN_SO_MODE (Mode of setting the minimum available margin level) bool trade_allowed; // ACCOUNT_TRADE_ALLOWED (Permission to trade for the current account from the server side) bool trade_expert; // ACCOUNT_TRADE_EXPERT (Permission to trade for an EA from the server side) int margin_mode; // ACCOUNT_MARGIN_MODE (Margin calculation mode) int currency_digits; // ACCOUNT_CURRENCY_DIGITS (Number of decimal places for the account currency) int server_type; // Trade server type (MetaTrader 5, MetaTrader 4) bool fifo_close; // The flag indicating that positions can be closed only by the FIFO rule //--- Account real properties double balance; // ACCOUNT_BALANCE (Account balance in a deposit currency) double credit; // ACCOUNT_CREDIT (Credit in a deposit currency) double profit; // ACCOUNT_PROFIT (Current profit on an account in the account currency) double equity; // ACCOUNT_EQUITY (Equity on an account in the deposit currency) double margin; // ACCOUNT_MARGIN (Reserved margin on an account in a deposit currency) double margin_free; // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in a deposit currency) double margin_level; // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %) double margin_so_call; // ACCOUNT_MARGIN_SO_CALL (MarginCall) double margin_so_so; // ACCOUNT_MARGIN_SO_SO (StopOut) double margin_initial; // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders) double margin_maintenance; // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions) double assets; // ACCOUNT_ASSETS (Current assets on an account) double liabilities; // ACCOUNT_LIABILITIES (Current liabilities on an account) double comission_blocked; // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account) //--- Account string properties uchar name[128]; // ACCOUNT_NAME (Client name) uchar server[64]; // ACCOUNT_SERVER (Trade server name) uchar currency[32]; // ACCOUNT_CURRENCY (Deposit currency) uchar company[128]; // ACCOUNT_COMPANY (Name of a company serving an account) }; SData m_struct_obj; // Account object structure
在类的公开部分里用于简化访问对象属性的代码块中,添加返回新属性的方法:
//+------------------------------------------------------------------+ //| Methods of a simplified access to the account object properties | //+------------------------------------------------------------------+ //--- Return the account's integer properties ENUM_ACCOUNT_TRADE_MODE TradeMode(void) const { return (ENUM_ACCOUNT_TRADE_MODE)this.GetProperty(ACCOUNT_PROP_TRADE_MODE); } ENUM_ACCOUNT_STOPOUT_MODE MarginSOMode(void) const { return (ENUM_ACCOUNT_STOPOUT_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_SO_MODE); } ENUM_ACCOUNT_MARGIN_MODE MarginMode(void) const { return (ENUM_ACCOUNT_MARGIN_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_MODE); } long Login(void) const { return this.GetProperty(ACCOUNT_PROP_LOGIN); } long Leverage(void) const { return this.GetProperty(ACCOUNT_PROP_LEVERAGE); } long LimitOrders(void) const { return this.GetProperty(ACCOUNT_PROP_LIMIT_ORDERS); } long TradeAllowed(void) const { return this.GetProperty(ACCOUNT_PROP_TRADE_ALLOWED); } long TradeExpert(void) const { return this.GetProperty(ACCOUNT_PROP_TRADE_EXPERT); } long CurrencyDigits(void) const { return this.GetProperty(ACCOUNT_PROP_CURRENCY_DIGITS); } long ServerType(void) const { return this.GetProperty(ACCOUNT_PROP_SERVER_TYPE); } long FIFOClose(void) const { return this.GetProperty(ACCOUNT_PROP_FIFO_CLOSE); } //--- Return the account's real properties
在类的构造函数中保存新帐户对象属性:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CAccount::CAccount(void) { //--- Initialize control data this.SetControlDataArraySizeLong(ACCOUNT_PROP_INTEGER_TOTAL); this.SetControlDataArraySizeDouble(ACCOUNT_PROP_DOUBLE_TOTAL); this.ResetChangesParams(); this.ResetControlsParams(); //--- Save integer properties this.m_long_prop[ACCOUNT_PROP_LOGIN] = ::AccountInfoInteger(ACCOUNT_LOGIN); this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = ::AccountInfoInteger(ACCOUNT_TRADE_MODE); this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = ::AccountInfoInteger(ACCOUNT_LEVERAGE); this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED); this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT); this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif ; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4); this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE] = (#ifdef __MQL5__::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? false : ::AccountInfoInteger(ACCOUNT_FIFO_CLOSE) #else false #endif ); //--- Save real properties
如果终端版本低于 2155,则输入 false。 否则,写入 ACCOUNT_FIFO_CLOSE 账户属性值。
此外,在更新帐户属性的 Refresh() 方法中保存属性:
//+------------------------------------------------------------------+ //| Update all account data | //+------------------------------------------------------------------+ void CAccount::Refresh(void) { //--- Initialize event data this.m_is_event=false; this.m_hash_sum=0; //--- Update integer properties this.m_long_prop[ACCOUNT_PROP_LOGIN] = ::AccountInfoInteger(ACCOUNT_LOGIN); this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = ::AccountInfoInteger(ACCOUNT_TRADE_MODE); this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = ::AccountInfoInteger(ACCOUNT_LEVERAGE); this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED); this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT); this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif ; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4); this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE] = (#ifdef __MQL5__::TerminalInfoInteger(TERMINAL_BUILD)<2155 ? false : ::AccountInfoInteger(ACCOUNT_FIFO_CLOSE) #else false #endif ); //--- Update real properties
在依据结构创建帐户对象的方法中填充新属性:
//+------------------------------------------------------------------+ //| Create the account object from the structure | //+------------------------------------------------------------------+ void CAccount::StructToObject(void) { //--- Save integer properties this.m_long_prop[ACCOUNT_PROP_LOGIN] = this.m_struct_obj.login; this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = this.m_struct_obj.trade_mode; this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = this.m_struct_obj.leverage; this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = this.m_struct_obj.limit_orders; this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = this.m_struct_obj.margin_so_mode; this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = this.m_struct_obj.trade_allowed; this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = this.m_struct_obj.trade_expert; this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = this.m_struct_obj.margin_mode; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = this.m_struct_obj.currency_digits; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = this.m_struct_obj.server_type; this.m_long_prop[ACCOUNT_PROP_FIFO_CLOSE] = this.m_struct_obj.fifo_close; //--- Save real properties
在返回帐户整数型属性描述的方法中显示新属性描述:
//+------------------------------------------------------------------+ //| Return the description of the account integer property | //+------------------------------------------------------------------+ string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property) { return ( property==ACCOUNT_PROP_LOGIN ? CMessage::Text(MSG_ACC_PROP_LOGIN)+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_TRADE_MODE ? CMessage::Text(MSG_ACC_PROP_TRADE_MODE)+": "+this.TradeModeDescription() : property==ACCOUNT_PROP_LEVERAGE ? CMessage::Text(MSG_ACC_PROP_LEVERAGE)+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_LIMIT_ORDERS ? CMessage::Text(MSG_ACC_PROP_LIMIT_ORDERS)+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_MARGIN_SO_MODE ? CMessage::Text(MSG_ACC_PROP_MARGIN_SO_MODE)+": "+this.MarginSOModeDescription() : property==ACCOUNT_PROP_TRADE_ALLOWED ? CMessage::Text(MSG_ACC_PROP_TRADE_ALLOWED)+": "+ (this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) : property==ACCOUNT_PROP_TRADE_EXPERT ? CMessage::Text(MSG_ACC_PROP_TRADE_EXPERT)+": "+ (this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) : property==ACCOUNT_PROP_MARGIN_MODE ? CMessage::Text(MSG_ACC_PROP_MARGIN_MODE)+": "+this.MarginModeDescription() : property==ACCOUNT_PROP_CURRENCY_DIGITS ? CMessage::Text(MSG_ACC_PROP_CURRENCY_DIGITS)+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_SERVER_TYPE ? CMessage::Text(MSG_ACC_PROP_SERVER_TYPE)+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_FIFO_CLOSE ? CMessage::Text(MSG_ACC_PROP_FIFO_CLOSE)+": "+(string)this.GetProperty(property) : "" ); } //+------------------------------------------------------------------+
请记住,向帐户对象添加新属性会令先前保存在所有终端的公用文件夹中的帐户对象失效。 为避免读取错误,请确保删除 \DoEasy\Accounts\ 子文件夹中所有终端的公用文件夹中的所有以前创建的帐户文件。 随后,当用新帐户替换时,函数库将以新格式自行保存帐户对象。
若要打开所有终端的公共文件夹,请使用编辑器命令文件->打开公共数据文件夹。 在资源管理器窗口中,转到“文件”文件夹,然后输入 \DoEasy\Accounts\
在该类的公开部分,添加方法返回开仓或下挂单所需保证金的说明:
public: //--- Constructor CAccount(void); //--- Set account's (1) integer, (2) real and (3) string properties void SetProperty(ENUM_ACCOUNT_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_ACCOUNT_PROP_DOUBLE property,double value) { this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_ACCOUNT_PROP_STRING property,string value) { this.m_string_prop[this.IndexProp(property)]=value; } //--- Return (1) integer, (2) real and (3) string order properties from the account string property long GetProperty(ENUM_ACCOUNT_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_ACCOUNT_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_ACCOUNT_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } //--- Return the flag of calculating MarginCall and StopOut levels in % bool IsPercentsForSOLevels(void) const { return this.MarginSOMode()==ACCOUNT_STOPOUT_MODE_PERCENT; } //--- Return the flag of supporting the property by the account object virtual bool SupportProperty(ENUM_ACCOUNT_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_ACCOUNT_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_ACCOUNT_PROP_STRING property) { return true; } //--- Compare CAccount objects by all possible properties (for sorting the lists by a specified account object property) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CAccount objects by account properties (to search for equal account objects) bool IsEqual(CAccount* compared_account) const; //--- Update all account data virtual void Refresh(void); //--- (1) Save the account object to the file, (2), download the account object from the file virtual bool Save(const int file_handle); virtual bool Load(const int file_handle); //--- Return the margin required for opening a position or placing a pending order double MarginForAction(const ENUM_ORDER_TYPE action,const string symbol,const double volume,const double price) const; //+------------------------------------------------------------------+
将其实现写在类主体之外:
//+------------------------------------------------------------------+ //| Return the margin required for opening a position | //| or placing a pending order | //+------------------------------------------------------------------+ double CAccount::MarginForAction(const ENUM_ORDER_TYPE action,const string symbol,const double volume,const double price) const { double margin=EMPTY_VALUE; #ifdef __MQL5__ return(!::OrderCalcMargin(action,symbol,volume,price,margin) ? EMPTY_VALUE : margin); #else return this.MarginFree()-::AccountFreeMarginCheck(symbol,action,volume); #endif } //+------------------------------------------------------------------+
在 MQL5 中,利用 OrderCalcMargin() 函数接收开仓或下挂单所需的保证金。 如果出于某种原因该函数返回错误,则返回最大值 DBL_MAX (该值为 EMPTY_VALUE 常量)。 否则,返回计算出的所需保证金。
在 MQL4 中,返回现有可用保证金减去(开立指定仓位,或利用 AccountFreeMarginCheck() 函数计算的下挂单)后的剩余资金。
帐户对象类的改进至此完毕。
现在我们来改进交易对象基类。 我们需要为所有交易事件语音添加设置音频的能力。
在类的私密部分中保存数据,创建结构为各种事件存储启用语音标志和相应的音频文件名:
//+------------------------------------------------------------------+ //| Trading object class | //+------------------------------------------------------------------+ class CTradeObj { private: struct SActionsFlags { private: bool m_use_sound_open; // The flag of using the position opening/order placing sound bool m_use_sound_close; // The flag of using the position closing/order removal sound bool m_use_sound_modify_sl; // The flag of using the StopLoss position/order modification sound bool m_use_sound_modify_tp; // The flag of using the TakeProfit position/order modification sound bool m_use_sound_modify_price; // The flag of using the order placement price modification sound //--- string m_sound_open; // Position opening/order placing sound string m_sound_close; // Position closing/order removal sound string m_sound_modify_sl; // StopLoss position/order modification sound string m_sound_modify_tp; // TakeProfit position/order modification sound string m_sound_modify_price; // Order placement price modification sound //--- string m_sound_open_err; // Position opening/order placing error sound string m_sound_close_err; // Position closing/order removal error sound string m_sound_modify_sl_err; // StopLoss position/order modification error sound string m_sound_modify_tp_err; // TakeProfit position/order modification error sound string m_sound_modify_price_err; // Order placement price modification error sound public: //--- Method of placing/accessing flags and file names void UseSoundOpen(const bool flag) { this.m_use_sound_open=flag; } void UseSoundClose(const bool flag) { this.m_use_sound_close=flag; } void UseSoundModifySL(const bool flag) { this.m_use_sound_modify_sl=flag; } void UseSoundModifyTP(const bool flag) { this.m_use_sound_modify_tp=flag; } void UseSoundModifyPrice(const bool flag) { this.m_use_sound_modify_price=flag; } bool UseSoundOpen(void) const { return this.m_use_sound_open; } bool UseSoundClose(void) const { return this.m_use_sound_close; } bool UseSoundModifySL(void) const { return this.m_use_sound_modify_sl; } bool UseSoundModifyTP(void) const { return this.m_use_sound_modify_tp; } bool UseSoundModifyPrice(void) const { return this.m_use_sound_modify_price; } //--- void SoundOpen(const string sound) { this.m_sound_open=sound; } void SoundClose(const string sound) { this.m_sound_close=sound; } void SoundModifySL(const string sound) { this.m_sound_modify_sl=sound; } void SoundModifyTP(const string sound) { this.m_sound_modify_tp=sound; } void SoundModifyPrice(const string sound) { this.m_sound_modify_price=sound; } string SoundOpen(void) const { return this.m_sound_open; } string SoundClose(void) const { return this.m_sound_close; } string SoundModifySL(void) const { return this.m_sound_modify_sl; } string SoundModifyTP(void) const { return this.m_sound_modify_tp; } string SoundModifyPrice(void) const { return this.m_sound_modify_price; } //--- void SoundErrorOpen(const string sound) { this.m_sound_open_err=sound; } void SoundErrorClose(const string sound) { this.m_sound_close_err=sound; } void SoundErrorModifySL(const string sound) { this.m_sound_modify_sl_err=sound; } void SoundErrorModifyTP(const string sound) { this.m_sound_modify_tp_err=sound; } void SoundErrorModifyPrice(const string sound) { this.m_sound_modify_price_err=sound; } string SoundErrorOpen(void) const { return this.m_sound_open_err; } string SoundErrorClose(void) const { return this.m_sound_close_err; } string SoundErrorModifySL(void) const { return this.m_sound_modify_sl_err; } string SoundErrorModifyTP(void) const { return this.m_sound_modify_tp_err; } string SoundErrorModifyPrice(void) const { return this.m_sound_modify_price_err; } }; struct SActions { SActionsFlags Buy; SActionsFlags BuyStop; SActionsFlags BuyLimit; SActionsFlags BuyStopLimit; SActionsFlags Sell; SActionsFlags SellStop; SActionsFlags SellLimit; SActionsFlags SellStopLimit; }; SActions m_datas;
该结构由两个嵌套结构组成:SActionsFlags 包含有关标志和标志名称的数据,而 SActions m_data 包含每笔仓位的 SActionsFlags 结构类型的数据和订单类型。 这令我们能够访问所有订单或仓位结构字段的标志和标志名称,从而为任何事件设置和使用声音提供了更大的灵活性。
此外,在类的私密部分中声明类成员变量,该变量存储交易对象启用交易事件声音的标志:
bool m_use_sound; // The flag of using sounds of the object trading events
该标志将成为公用的切换开关,指示品种交易对象的所有交易事件中启用/禁用声音。 该标志允许同时启用/禁用每个交易品种交易事件的声音。
在该类的公开部分,声明所有必要的方法,针对品种基准交易对象设置和接收所有交易事件启用声音的标志和音频文件名称:
public: //--- Constructor CTradeObj(); //--- Set default values void Init(const string symbol, const ulong magic, const double volume, const ulong deviation, const int stoplimit, const datetime expiration, const bool async_mode, const ENUM_ORDER_TYPE_FILLING type_filling, const ENUM_ORDER_TYPE_TIME type_expiration, ENUM_LOG_LEVEL log_level); //--- Set default sounds and flags of using sounds, void InitSounds(const bool use_sound=false, const string sound_open=NULL, const string sound_close=NULL, const string sound_sl=NULL, const string sound_tp=NULL, const string sound_price=NULL, const string sound_error=NULL); //--- Allow working with sounds and set standard sounds void SetSoundsStandart(void); //--- Set the flag of using the sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type void UseSoundOpen(const ENUM_ORDER_TYPE action,const bool flag); void UseSoundClose(const ENUM_ORDER_TYPE action,const bool flag); void UseSoundModifySL(const ENUM_ORDER_TYPE action,const bool flag); void UseSoundModifyTP(const ENUM_ORDER_TYPE action,const bool flag); void UseSoundModifyPrice(const ENUM_ORDER_TYPE action,const bool flag); //--- Return the flag of using the sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type bool UseSoundOpen(const ENUM_ORDER_TYPE action) const; bool UseSoundClose(const ENUM_ORDER_TYPE action) const; bool UseSoundModifySL(const ENUM_ORDER_TYPE action) const; bool UseSoundModifyTP(const ENUM_ORDER_TYPE action) const; bool UseSoundModifyPrice(const ENUM_ORDER_TYPE action) const; //--- Set the sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type void SetSoundOpen(const ENUM_ORDER_TYPE action,const string sound); void SetSoundClose(const ENUM_ORDER_TYPE action,const string sound); void SetSoundModifySL(const ENUM_ORDER_TYPE action,const string sound); void SetSoundModifyTP(const ENUM_ORDER_TYPE action,const string sound); void SetSoundModifyPrice(const ENUM_ORDER_TYPE action,const string sound); //--- Set the error sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type void SetSoundErrorOpen(const ENUM_ORDER_TYPE action,const string sound); void SetSoundErrorClose(const ENUM_ORDER_TYPE action,const string sound); void SetSoundErrorModifySL(const ENUM_ORDER_TYPE action,const string sound); void SetSoundErrorModifyTP(const ENUM_ORDER_TYPE action,const string sound); void SetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action,const string sound); //--- Return the sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type string GetSoundOpen(const ENUM_ORDER_TYPE action) const; string GetSoundClose(const ENUM_ORDER_TYPE action) const; string GetSoundModifySL(const ENUM_ORDER_TYPE action) const; string GetSoundModifyTP(const ENUM_ORDER_TYPE action) const; string GetSoundModifyPrice(const ENUM_ORDER_TYPE action) const; //--- Return the error sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type string GetSoundErrorOpen(const ENUM_ORDER_TYPE action) const; string GetSoundErrorClose(const ENUM_ORDER_TYPE action) const; string GetSoundErrorModifySL(const ENUM_ORDER_TYPE action) const; string GetSoundErrorModifyTP(const ENUM_ORDER_TYPE action) const; string GetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action) const; //--- Play the sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type void PlaySoundOpen(const ENUM_ORDER_TYPE action); void PlaySoundClose(const ENUM_ORDER_TYPE action); void PlaySoundModifySL(const ENUM_ORDER_TYPE action); void PlaySoundModifyTP(const ENUM_ORDER_TYPE action); void PlaySoundModifyPrice(const ENUM_ORDER_TYPE action); //--- Play the error sound of (1) opening/placing a specified position/order type, //--- (2) closing/removal of a specified position/order type, (3) StopLoss modification for a specified position/order type, //--- (4) TakeProfit modification for a specified position/order type, (5) placement price modification for a specified order type void PlaySoundErrorOpen(const ENUM_ORDER_TYPE action); void PlaySoundErrorClose(const ENUM_ORDER_TYPE action); void PlaySoundErrorModifySL(const ENUM_ORDER_TYPE action); void PlaySoundErrorModifyTP(const ENUM_ORDER_TYPE action); void PlaySoundErrorModifyPrice(const ENUM_ORDER_TYPE action); //--- Set/return the flag of using sounds void SetUseSound(const bool flag) { this.m_use_sound=flag; } bool IsUseSound(void) const { return this.m_use_sound; } //--- (1) Return the margin calculation mode, (2) hedge account flag
在类构造函数中重置启用声音的标记,并将启用声音的标记和音频文件初始化为默认值,即禁用声音和空文件名:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTradeObj::CTradeObj(void) : m_magic(0), m_deviation(5), m_stop_limit(0), m_expiration(0), m_async_mode(false), m_type_filling(ORDER_FILLING_FOK), m_type_expiration(ORDER_TIME_GTC), m_comment(::MQLInfoString(MQL_PROGRAM_NAME)+" by DoEasy"), m_log_level(LOG_LEVEL_ERROR_MSG) { //--- Margin calculation mode this.m_margin_mode= ( #ifdef __MQL5__ (ENUM_ACCOUNT_MARGIN_MODE)::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else /* MQL4 */ ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ); //--- Set default sounds and flags of using sounds this.m_use_sound=false; this.InitSounds(); } //+------------------------------------------------------------------+
在类主体之外实现用于初始化启用声音的标志,及设置音频文件名的方法:
//+------------------------------------------------------------------+ //| Set default sounds and flags of using sounds | //+------------------------------------------------------------------+ void CTradeObj::InitSounds(const bool use_sound=false, const string sound_open=NULL, const string sound_close=NULL, const string sound_sl=NULL, const string sound_tp=NULL, const string sound_price=NULL, const string sound_error=NULL) { this.m_datas.Buy.UseSoundOpen(use_sound); this.m_datas.Buy.UseSoundClose(use_sound); this.m_datas.Buy.UseSoundModifySL(use_sound); this.m_datas.Buy.UseSoundModifyTP(use_sound); this.m_datas.Buy.UseSoundModifyPrice(use_sound); this.m_datas.Buy.SoundOpen(sound_open); this.m_datas.Buy.SoundClose(sound_close); this.m_datas.Buy.SoundModifySL(sound_sl); this.m_datas.Buy.SoundModifyTP(sound_tp); this.m_datas.Buy.SoundModifyPrice(sound_price); this.m_datas.Buy.SoundErrorClose(sound_error); this.m_datas.Buy.SoundErrorOpen(sound_error); this.m_datas.Buy.SoundErrorModifySL(sound_error); this.m_datas.Buy.SoundErrorModifyTP(sound_error); this.m_datas.Buy.SoundErrorModifyPrice(sound_error); this.m_datas.BuyStop.UseSoundOpen(use_sound); this.m_datas.BuyStop.UseSoundClose(use_sound); this.m_datas.BuyStop.UseSoundModifySL(use_sound); this.m_datas.BuyStop.UseSoundModifyTP(use_sound); this.m_datas.BuyStop.UseSoundModifyPrice(use_sound); this.m_datas.BuyStop.SoundOpen(sound_open); this.m_datas.BuyStop.SoundClose(sound_close); this.m_datas.BuyStop.SoundModifySL(sound_sl); this.m_datas.BuyStop.SoundModifyTP(sound_tp); this.m_datas.BuyStop.SoundModifyPrice(sound_price); this.m_datas.BuyStop.SoundErrorClose(sound_error); this.m_datas.BuyStop.SoundErrorOpen(sound_error); this.m_datas.BuyStop.SoundErrorModifySL(sound_error); this.m_datas.BuyStop.SoundErrorModifyTP(sound_error); this.m_datas.BuyStop.SoundErrorModifyPrice(sound_error); this.m_datas.BuyLimit.UseSoundOpen(use_sound); this.m_datas.BuyLimit.UseSoundClose(use_sound); this.m_datas.BuyLimit.UseSoundModifySL(use_sound); this.m_datas.BuyLimit.UseSoundModifyTP(use_sound); this.m_datas.BuyLimit.UseSoundModifyPrice(use_sound); this.m_datas.BuyLimit.SoundOpen(sound_open); this.m_datas.BuyLimit.SoundClose(sound_close); this.m_datas.BuyLimit.SoundModifySL(sound_sl); this.m_datas.BuyLimit.SoundModifyTP(sound_tp); this.m_datas.BuyLimit.SoundModifyPrice(sound_price); this.m_datas.BuyLimit.SoundErrorClose(sound_error); this.m_datas.BuyLimit.SoundErrorOpen(sound_error); this.m_datas.BuyLimit.SoundErrorModifySL(sound_error); this.m_datas.BuyLimit.SoundErrorModifyTP(sound_error); this.m_datas.BuyLimit.SoundErrorModifyPrice(sound_error); this.m_datas.BuyStopLimit.UseSoundOpen(use_sound); this.m_datas.BuyStopLimit.UseSoundClose(use_sound); this.m_datas.BuyStopLimit.UseSoundModifySL(use_sound); this.m_datas.BuyStopLimit.UseSoundModifyTP(use_sound); this.m_datas.BuyStopLimit.UseSoundModifyPrice(use_sound); this.m_datas.BuyStopLimit.SoundOpen(sound_open); this.m_datas.BuyStopLimit.SoundClose(sound_close); this.m_datas.BuyStopLimit.SoundModifySL(sound_sl); this.m_datas.BuyStopLimit.SoundModifyTP(sound_tp); this.m_datas.BuyStopLimit.SoundModifyPrice(sound_price); this.m_datas.BuyStopLimit.SoundErrorClose(sound_error); this.m_datas.BuyStopLimit.SoundErrorOpen(sound_error); this.m_datas.BuyStopLimit.SoundErrorModifySL(sound_error); this.m_datas.BuyStopLimit.SoundErrorModifyTP(sound_error); this.m_datas.BuyStopLimit.SoundErrorModifyPrice(sound_error); this.m_datas.Sell.UseSoundOpen(use_sound); this.m_datas.Sell.UseSoundClose(use_sound); this.m_datas.Sell.UseSoundModifySL(use_sound); this.m_datas.Sell.UseSoundModifyTP(use_sound); this.m_datas.Sell.UseSoundModifyPrice(use_sound); this.m_datas.Sell.SoundOpen(sound_open); this.m_datas.Sell.SoundClose(sound_close); this.m_datas.Sell.SoundModifySL(sound_sl); this.m_datas.Sell.SoundModifyTP(sound_tp); this.m_datas.Sell.SoundModifyPrice(sound_price); this.m_datas.Sell.SoundErrorClose(sound_error); this.m_datas.Sell.SoundErrorOpen(sound_error); this.m_datas.Sell.SoundErrorModifySL(sound_error); this.m_datas.Sell.SoundErrorModifyTP(sound_error); this.m_datas.Sell.SoundErrorModifyPrice(sound_error); this.m_datas.SellStop.UseSoundOpen(use_sound); this.m_datas.SellStop.UseSoundClose(use_sound); this.m_datas.SellStop.UseSoundModifySL(use_sound); this.m_datas.SellStop.UseSoundModifyTP(use_sound); this.m_datas.SellStop.UseSoundModifyPrice(use_sound); this.m_datas.SellStop.SoundOpen(sound_open); this.m_datas.SellStop.SoundClose(sound_close); this.m_datas.SellStop.SoundModifySL(sound_sl); this.m_datas.SellStop.SoundModifyTP(sound_tp); this.m_datas.SellStop.SoundModifyPrice(sound_price); this.m_datas.SellStop.SoundErrorClose(sound_error); this.m_datas.SellStop.SoundErrorOpen(sound_error); this.m_datas.SellStop.SoundErrorModifySL(sound_error); this.m_datas.SellStop.SoundErrorModifyTP(sound_error); this.m_datas.SellStop.SoundErrorModifyPrice(sound_error); this.m_datas.SellLimit.UseSoundOpen(use_sound); this.m_datas.SellLimit.UseSoundClose(use_sound); this.m_datas.SellLimit.UseSoundModifySL(use_sound); this.m_datas.SellLimit.UseSoundModifyTP(use_sound); this.m_datas.SellLimit.UseSoundModifyPrice(use_sound); this.m_datas.SellLimit.SoundOpen(sound_open); this.m_datas.SellLimit.SoundClose(sound_close); this.m_datas.SellLimit.SoundModifySL(sound_sl); this.m_datas.SellLimit.SoundModifyTP(sound_tp); this.m_datas.SellLimit.SoundModifyPrice(sound_price); this.m_datas.SellLimit.SoundErrorClose(sound_error); this.m_datas.SellLimit.SoundErrorOpen(sound_error); this.m_datas.SellLimit.SoundErrorModifySL(sound_error); this.m_datas.SellLimit.SoundErrorModifyTP(sound_error); this.m_datas.SellLimit.SoundErrorModifyPrice(sound_error); this.m_datas.SellStopLimit.UseSoundOpen(use_sound); this.m_datas.SellStopLimit.UseSoundClose(use_sound); this.m_datas.SellStopLimit.UseSoundModifySL(use_sound); this.m_datas.SellStopLimit.UseSoundModifyTP(use_sound); this.m_datas.SellStopLimit.UseSoundModifyPrice(use_sound); this.m_datas.SellStopLimit.SoundOpen(sound_open); this.m_datas.SellStopLimit.SoundClose(sound_close); this.m_datas.SellStopLimit.SoundModifySL(sound_sl); this.m_datas.SellStopLimit.SoundModifyTP(sound_tp); this.m_datas.SellStopLimit.SoundModifyPrice(sound_price); this.m_datas.SellStopLimit.SoundErrorClose(sound_error); this.m_datas.SellStopLimit.SoundErrorOpen(sound_error); this.m_datas.SellStopLimit.SoundErrorModifySL(sound_error); this.m_datas.SellStopLimit.SoundErrorModifyTP(sound_error); this.m_datas.SellStopLimit.SoundErrorModifyPrice(sound_error); } //+------------------------------------------------------------------+
该方法接收启用交易对象事件声音的标志,开盘、收盘、止损/止盈修改、下单价格和出错声音的音频文件名。 接下来,对于每个交易事件的结构字段,依据所传递数值为每笔发送给服务器的订单填充类型。
所有列举的交易事件,共用一个启用声音的标志和出错声音的文件名称,而对于每个交易事件,可分别设置其它声音。 不过,如果您愿意,还可以使用上述声明的方法为特定事件的错误声音设置自定义声音,以及为对象的每个交易事件分别设置使用声音的标记。 默认情况下,禁用声音及文件名为空。
此外,该类还含有为所有对象交易事件设置标准声音,并允许其在每次交易事件中使用的方法:
//+------------------------------------------------------------------+ //| Allow working with sounds and set standard sounds | //+------------------------------------------------------------------+ void CTradeObj::SetSoundsStandart(void) { this.m_datas.Buy.UseSoundClose(true); this.m_datas.Buy.UseSoundOpen(true); this.m_datas.Buy.UseSoundModifySL(true); this.m_datas.Buy.UseSoundModifyTP(true); this.m_datas.Buy.UseSoundModifyPrice(true); this.m_datas.Buy.SoundOpen(SND_OK); this.m_datas.Buy.SoundClose(SND_OK); this.m_datas.Buy.SoundModifySL(SND_OK); this.m_datas.Buy.SoundModifyTP(SND_OK); this.m_datas.Buy.SoundModifyPrice(SND_OK); this.m_datas.Buy.SoundErrorClose(SND_TIMEOUT); this.m_datas.Buy.SoundErrorOpen(SND_TIMEOUT); this.m_datas.Buy.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.Buy.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.Buy.SoundErrorModifyPrice(SND_TIMEOUT); this.m_datas.BuyStop.UseSoundClose(true); this.m_datas.BuyStop.UseSoundOpen(true); this.m_datas.BuyStop.UseSoundModifySL(true); this.m_datas.BuyStop.UseSoundModifyTP(true); this.m_datas.BuyStop.UseSoundModifyPrice(true); this.m_datas.BuyStop.SoundOpen(SND_OK); this.m_datas.BuyStop.SoundClose(SND_OK); this.m_datas.BuyStop.SoundModifySL(SND_OK); this.m_datas.BuyStop.SoundModifyTP(SND_OK); this.m_datas.BuyStop.SoundModifyPrice(SND_OK); this.m_datas.BuyStop.SoundErrorClose(SND_TIMEOUT); this.m_datas.BuyStop.SoundErrorOpen(SND_TIMEOUT); this.m_datas.BuyStop.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.BuyStop.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.BuyStop.SoundErrorModifyPrice(SND_TIMEOUT); this.m_datas.BuyLimit.UseSoundClose(true); this.m_datas.BuyLimit.UseSoundOpen(true); this.m_datas.BuyLimit.UseSoundModifySL(true); this.m_datas.BuyLimit.UseSoundModifyTP(true); this.m_datas.BuyLimit.UseSoundModifyPrice(true); this.m_datas.BuyLimit.SoundOpen(SND_OK); this.m_datas.BuyLimit.SoundClose(SND_OK); this.m_datas.BuyLimit.SoundModifySL(SND_OK); this.m_datas.BuyLimit.SoundModifyTP(SND_OK); this.m_datas.BuyLimit.SoundModifyPrice(SND_OK); this.m_datas.BuyLimit.SoundErrorClose(SND_TIMEOUT); this.m_datas.BuyLimit.SoundErrorOpen(SND_TIMEOUT); this.m_datas.BuyLimit.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.BuyLimit.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.BuyLimit.SoundErrorModifyPrice(SND_TIMEOUT); this.m_datas.BuyStopLimit.UseSoundClose(true); this.m_datas.BuyStopLimit.UseSoundOpen(true); this.m_datas.BuyStopLimit.UseSoundModifySL(true); this.m_datas.BuyStopLimit.UseSoundModifyTP(true); this.m_datas.BuyStopLimit.UseSoundModifyPrice(true); this.m_datas.BuyStopLimit.SoundOpen(SND_OK); this.m_datas.BuyStopLimit.SoundClose(SND_OK); this.m_datas.BuyStopLimit.SoundModifySL(SND_OK); this.m_datas.BuyStopLimit.SoundModifyTP(SND_OK); this.m_datas.BuyStopLimit.SoundModifyPrice(SND_OK); this.m_datas.BuyStopLimit.SoundErrorClose(SND_TIMEOUT); this.m_datas.BuyStopLimit.SoundErrorOpen(SND_TIMEOUT); this.m_datas.BuyStopLimit.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.BuyStopLimit.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.BuyStopLimit.SoundErrorModifyPrice(SND_TIMEOUT); this.m_datas.Sell.UseSoundClose(true); this.m_datas.Sell.UseSoundOpen(true); this.m_datas.Sell.UseSoundModifySL(true); this.m_datas.Sell.UseSoundModifyTP(true); this.m_datas.Sell.UseSoundModifyPrice(true); this.m_datas.Sell.SoundOpen(SND_OK); this.m_datas.Sell.SoundClose(SND_OK); this.m_datas.Sell.SoundModifySL(SND_OK); this.m_datas.Sell.SoundModifyTP(SND_OK); this.m_datas.Sell.SoundModifyPrice(SND_OK); this.m_datas.Sell.SoundErrorClose(SND_TIMEOUT); this.m_datas.Sell.SoundErrorOpen(SND_TIMEOUT); this.m_datas.Sell.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.Sell.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.Sell.SoundErrorModifyPrice(SND_TIMEOUT); this.m_datas.SellStop.UseSoundClose(true); this.m_datas.SellStop.UseSoundOpen(true); this.m_datas.SellStop.UseSoundModifySL(true); this.m_datas.SellStop.UseSoundModifyTP(true); this.m_datas.SellStop.UseSoundModifyPrice(true); this.m_datas.SellStop.SoundOpen(SND_OK); this.m_datas.SellStop.SoundClose(SND_OK); this.m_datas.SellStop.SoundModifySL(SND_OK); this.m_datas.SellStop.SoundModifyTP(SND_OK); this.m_datas.SellStop.SoundModifyPrice(SND_OK); this.m_datas.SellStop.SoundErrorClose(SND_TIMEOUT); this.m_datas.SellStop.SoundErrorOpen(SND_TIMEOUT); this.m_datas.SellStop.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.SellStop.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.SellStop.SoundErrorModifyPrice(SND_TIMEOUT); this.m_datas.SellLimit.UseSoundClose(true); this.m_datas.SellLimit.UseSoundOpen(true); this.m_datas.SellLimit.UseSoundModifySL(true); this.m_datas.SellLimit.UseSoundModifyTP(true); this.m_datas.SellLimit.UseSoundModifyPrice(true); this.m_datas.SellLimit.SoundOpen(SND_OK); this.m_datas.SellLimit.SoundClose(SND_OK); this.m_datas.SellLimit.SoundModifySL(SND_OK); this.m_datas.SellLimit.SoundModifyTP(SND_OK); this.m_datas.SellLimit.SoundModifyPrice(SND_OK); this.m_datas.SellLimit.SoundErrorClose(SND_TIMEOUT); this.m_datas.SellLimit.SoundErrorOpen(SND_TIMEOUT); this.m_datas.SellLimit.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.SellLimit.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.SellLimit.SoundErrorModifyPrice(SND_TIMEOUT); this.m_datas.SellStopLimit.UseSoundClose(true); this.m_datas.SellStopLimit.UseSoundOpen(true); this.m_datas.SellStopLimit.UseSoundModifySL(true); this.m_datas.SellStopLimit.UseSoundModifyTP(true); this.m_datas.SellStopLimit.UseSoundModifyPrice(true); this.m_datas.SellStopLimit.SoundOpen(SND_OK); this.m_datas.SellStopLimit.SoundClose(SND_OK); this.m_datas.SellStopLimit.SoundModifySL(SND_OK); this.m_datas.SellStopLimit.SoundModifyTP(SND_OK); this.m_datas.SellStopLimit.SoundModifyPrice(SND_OK); this.m_datas.SellStopLimit.SoundErrorClose(SND_TIMEOUT); this.m_datas.SellStopLimit.SoundErrorOpen(SND_TIMEOUT); this.m_datas.SellStopLimit.SoundErrorModifySL(SND_TIMEOUT); this.m_datas.SellStopLimit.SoundErrorModifyTP(SND_TIMEOUT); this.m_datas.SellStopLimit.SoundErrorModifyPrice(SND_TIMEOUT); } //+------------------------------------------------------------------+
在类主体之外,实现为特定交易事件类型播放声音以及设置标志和声音的方法:
//+------------------------------------------------------------------+ //| Set the flag of using sounds | //| of opening/placing a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::UseSoundOpen(const ENUM_ORDER_TYPE action,const bool flag) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.UseSoundOpen(flag); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.UseSoundOpen(flag); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.UseSoundOpen(flag); break; case ORDER_TYPE_SELL : this.m_datas.Sell.UseSoundOpen(flag); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.UseSoundOpen(flag); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.UseSoundOpen(flag); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.UseSoundOpen(flag); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.UseSoundOpen(flag); break; default: break; } } //+------------------------------------------------------------------+ //| Set the flag of using a sound | //| of closing/removal of a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::UseSoundClose(const ENUM_ORDER_TYPE action,const bool flag) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.UseSoundClose(flag); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.UseSoundClose(flag); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.UseSoundClose(flag); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.UseSoundClose(flag); break; case ORDER_TYPE_SELL : this.m_datas.Sell.UseSoundClose(flag); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.UseSoundClose(flag); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.UseSoundClose(flag); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.UseSoundClose(flag); break; default: break; } } //+------------------------------------------------------------------+ //| Set the flag of using a sound | //| of StopLoss modification for a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::UseSoundModifySL(const ENUM_ORDER_TYPE action,const bool flag) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.UseSoundModifySL(flag); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.UseSoundModifySL(flag); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.UseSoundModifySL(flag); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.UseSoundModifySL(flag); break; case ORDER_TYPE_SELL : this.m_datas.Sell.UseSoundModifySL(flag); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.UseSoundModifySL(flag); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.UseSoundModifySL(flag); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.UseSoundModifySL(flag); break; default: break; } } //+------------------------------------------------------------------+ //| Set the flag of using a sound | //| of TakeProfit modification for a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::UseSoundModifyTP(const ENUM_ORDER_TYPE action,const bool flag) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.UseSoundModifyTP(flag); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.UseSoundModifyTP(flag); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.UseSoundModifyTP(flag); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.UseSoundModifyTP(flag); break; case ORDER_TYPE_SELL : this.m_datas.Sell.UseSoundModifyTP(flag); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.UseSoundModifyTP(flag); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.UseSoundModifyTP(flag); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.UseSoundModifyTP(flag); break; default: break; } } //+------------------------------------------------------------------+ //| Set the flag of using a modification sound | //| of the placement price for a specified order type | //+------------------------------------------------------------------+ void CTradeObj::UseSoundModifyPrice(const ENUM_ORDER_TYPE action,const bool flag) { int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.UseSoundModifyPrice(flag); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.UseSoundModifyPrice(flag); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.UseSoundModifyPrice(flag); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.UseSoundModifyPrice(flag); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.UseSoundModifyPrice(flag); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.UseSoundModifyPrice(flag); break; default: break; } } //+------------------------------------------------------------------+ //| Return the flag of using the sound of opening/placing | //| a specified position/order type | //+------------------------------------------------------------------+ bool CTradeObj::UseSoundOpen(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.UseSoundOpen(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.UseSoundOpen(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.UseSoundOpen(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.UseSoundOpen(); case ORDER_TYPE_SELL : return this.m_datas.Sell.UseSoundOpen(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.UseSoundOpen(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.UseSoundOpen(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.UseSoundOpen(); default: return false; } } //+------------------------------------------------------------------+ //| Return the flag of using the sound of closing/removal of | //| a specified position/order type | //+------------------------------------------------------------------+ bool CTradeObj::UseSoundClose(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.UseSoundClose(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.UseSoundClose(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.UseSoundClose(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.UseSoundClose(); case ORDER_TYPE_SELL : return this.m_datas.Sell.UseSoundClose(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.UseSoundClose(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.UseSoundClose(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.UseSoundClose(); default: return false; } } //+------------------------------------------------------------------+ //| Return the flag of using a sound | //| of StopLoss modification for a specified position/order type | //+------------------------------------------------------------------+ bool CTradeObj::UseSoundModifySL(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.UseSoundModifySL(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.UseSoundModifySL(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.UseSoundModifySL(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.UseSoundModifySL(); case ORDER_TYPE_SELL : return this.m_datas.Sell.UseSoundModifySL(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.UseSoundModifySL(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.UseSoundModifySL(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.UseSoundModifySL(); default: return false; } } //+------------------------------------------------------------------+ //| Return the flag of using a sound | //| of TakeProfit modification for a specified position/order type | //+------------------------------------------------------------------+ bool CTradeObj::UseSoundModifyTP(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.UseSoundModifyTP(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.UseSoundModifyTP(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.UseSoundModifyTP(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.UseSoundModifyTP(); case ORDER_TYPE_SELL : return this.m_datas.Sell.UseSoundModifyTP(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.UseSoundModifyTP(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.UseSoundModifyTP(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.UseSoundModifyTP(); default: return false; } } //+------------------------------------------------------------------+ //| Return the flag of using a modification sound | //| of the placement price for a specified order type | //+------------------------------------------------------------------+ bool CTradeObj::UseSoundModifyPrice(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.UseSoundModifyPrice(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.UseSoundModifyPrice(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.UseSoundModifyPrice(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.UseSoundModifyPrice(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.UseSoundModifyPrice(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.UseSoundModifyPrice(); default: return false; } } //+------------------------------------------------------------------+ //| Set the sound of opening/placing | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundOpen(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundOpen(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundOpen(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundOpen(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundOpen(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundOpen(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundOpen(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundOpen(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundOpen(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set the sound of closing/removal of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundClose(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundClose(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundClose(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundClose(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundClose(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundClose(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundClose(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundClose(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundClose(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set StopLoss modification sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundModifySL(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundModifySL(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundModifySL(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundModifySL(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundModifySL(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundModifySL(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundModifySL(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundModifySL(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundModifySL(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set TakeProfit modification sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundModifyTP(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundModifyTP(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundModifyTP(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundModifyTP(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundModifyTP(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundModifyTP(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundModifyTP(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundModifyTP(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundModifyTP(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set price modification sound | //| for a specified order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundModifyPrice(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundModifyPrice(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundModifyPrice(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundModifyPrice(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundModifyPrice(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundModifyPrice(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundModifyPrice(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set the error sound of opening/placing | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundErrorOpen(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundErrorOpen(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundErrorOpen(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundErrorOpen(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundErrorOpen(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundErrorOpen(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundErrorOpen(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundErrorOpen(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundErrorOpen(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set the error sound of closing/removal of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundErrorClose(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundErrorClose(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundErrorClose(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundErrorClose(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundErrorClose(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundErrorClose(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundErrorClose(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundErrorClose(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundErrorClose(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set StopLoss modification error sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundErrorModifySL(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundErrorModifySL(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundErrorModifySL(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundErrorModifySL(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundErrorModifySL(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundErrorModifySL(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundErrorModifySL(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundErrorModifySL(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundErrorModifySL(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set TakeProfit modification error sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundErrorModifyTP(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY : this.m_datas.Buy.SoundErrorModifyTP(sound); break; case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundErrorModifyTP(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundErrorModifyTP(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundErrorModifyTP(sound); break; case ORDER_TYPE_SELL : this.m_datas.Sell.SoundErrorModifyTP(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundErrorModifyTP(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundErrorModifyTP(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundErrorModifyTP(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Set price modification error sound | //| for a specified order type | //+------------------------------------------------------------------+ void CTradeObj::SetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action,const string sound) { int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : this.m_datas.BuyStop.SoundErrorModifyPrice(sound); break; case ORDER_TYPE_BUY_LIMIT : this.m_datas.BuyLimit.SoundErrorModifyPrice(sound); break; case ORDER_TYPE_BUY_STOP_LIMIT : this.m_datas.BuyStopLimit.SoundErrorModifyPrice(sound); break; case ORDER_TYPE_SELL_STOP : this.m_datas.SellStop.SoundErrorModifyPrice(sound); break; case ORDER_TYPE_SELL_LIMIT : this.m_datas.SellLimit.SoundErrorModifyPrice(sound); break; case ORDER_TYPE_SELL_STOP_LIMIT : this.m_datas.SellStopLimit.SoundErrorModifyPrice(sound); break; default: break; } } //+------------------------------------------------------------------+ //| Return the sound of opening/placing | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundOpen(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundOpen(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundOpen(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundOpen(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundOpen(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundOpen(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundOpen(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundOpen(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundOpen(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return the sound of closing/removal of | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundClose(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundClose(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundClose(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundClose(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundClose(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundClose(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundClose(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundClose(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundClose(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return StopLoss modification sound of | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundModifySL(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundModifySL(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundModifySL(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundModifySL(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundModifySL(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundModifySL(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundModifySL(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundModifySL(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundModifySL(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return TakeProfit modification sound of | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundModifyTP(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundModifyTP(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundModifyTP(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundModifyTP(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundModifyTP(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundModifyTP(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundModifyTP(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundModifyTP(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundModifyTP(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return price modification sound | //| for a specified order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundModifyPrice(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundModifyPrice(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundModifyPrice(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundModifyPrice(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundModifyPrice(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundModifyPrice(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundModifyPrice(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return the error sound of opening/placing | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundErrorOpen(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundErrorOpen(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundErrorOpen(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundErrorOpen(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundErrorOpen(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundErrorOpen(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundErrorOpen(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundErrorOpen(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundErrorOpen(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return the error sound of closing/removal of | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundErrorClose(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundErrorClose(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundErrorClose(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundErrorClose(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundErrorClose(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundErrorClose(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundErrorClose(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundErrorClose(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundErrorClose(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return StopLoss modification error sound of | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundErrorModifySL(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundErrorModifySL(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundErrorModifySL(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundErrorModifySL(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundErrorModifySL(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundErrorModifySL(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundErrorModifySL(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundErrorModifySL(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundErrorModifySL(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return TakeProfit modification error sound of | //| a specified position/order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundErrorModifyTP(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY : return this.m_datas.Buy.SoundErrorModifyTP(); case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundErrorModifyTP(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundErrorModifyTP(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundErrorModifyTP(); case ORDER_TYPE_SELL : return this.m_datas.Sell.SoundErrorModifyTP(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundErrorModifyTP(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundErrorModifyTP(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundErrorModifyTP(); default: return NULL; } } //+------------------------------------------------------------------+ //| Return price modification error sound | //| for a specified order type | //+------------------------------------------------------------------+ string CTradeObj::GetSoundErrorModifyPrice(const ENUM_ORDER_TYPE action) const { int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : return this.m_datas.BuyStop.SoundErrorModifyPrice(); case ORDER_TYPE_BUY_LIMIT : return this.m_datas.BuyLimit.SoundErrorModifyPrice(); case ORDER_TYPE_BUY_STOP_LIMIT : return this.m_datas.BuyStopLimit.SoundErrorModifyPrice(); case ORDER_TYPE_SELL_STOP : return this.m_datas.SellStop.SoundErrorModifyPrice(); case ORDER_TYPE_SELL_LIMIT : return this.m_datas.SellLimit.SoundErrorModifyPrice(); case ORDER_TYPE_SELL_STOP_LIMIT : return this.m_datas.SellStopLimit.SoundErrorModifyPrice(); default: return NULL; } } //+------------------------------------------------------------------+ //| Play the sound of opening/placing | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundOpen(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundOpen()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundOpen()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundOpen()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundOpen()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundOpen()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundOpen()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundOpen()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundOpen()); break; default: break; } } //+------------------------------------------------------------------+ //| Play the sound of closing/removal of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundClose(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundClose()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundClose()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundClose()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundClose()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundClose()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundClose()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundClose()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundClose()); break; default: break; } } //+------------------------------------------------------------------+ //| Play StopLoss modification sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundModifySL(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundModifySL()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundModifySL()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundModifySL()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundModifySL()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundModifySL()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundModifySL()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundModifySL()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundModifySL()); break; default: break; } } //+------------------------------------------------------------------+ //| Play TakeProfit modification sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundModifyTP(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundModifyTP()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundModifyTP()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundModifyTP()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundModifyTP()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundModifyTP()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundModifyTP()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundModifyTP()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundModifyTP()); break; default: break; } } //+------------------------------------------------------------------+ //| Play price modification sound | //| for a specified order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundModifyPrice(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundModifyPrice()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundModifyPrice()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundModifyPrice()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundModifyPrice()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundModifyPrice()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundModifyPrice()); break; default: break; } } //+------------------------------------------------------------------+ //| Play the error sound of opening/placing | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundErrorOpen(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundErrorOpen()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorOpen()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorOpen()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorOpen()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundErrorOpen()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundErrorOpen()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorOpen()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorOpen()); break; default: break; } } //+------------------------------------------------------------------+ //| Play the error sound of closing/removal of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundErrorClose(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundErrorClose()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorClose()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorClose()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorClose()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundErrorClose()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundErrorClose()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorClose()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorClose()); break; default: break; } } //+------------------------------------------------------------------+ //| Play StopLoss modification error sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundErrorModifySL(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundErrorModifySL()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorModifySL()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorModifySL()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorModifySL()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundErrorModifySL()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundErrorModifySL()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorModifySL()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorModifySL()); break; default: break; } } //+------------------------------------------------------------------+ //| Play TakeProfit modification error sound of | //| a specified position/order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundErrorModifyTP(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY : CMessage::PlaySound(this.m_datas.Buy.SoundErrorModifyTP()); break; case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorModifyTP()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorModifyTP()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorModifyTP()); break; case ORDER_TYPE_SELL : CMessage::PlaySound(this.m_datas.Sell.SoundErrorModifyTP()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundErrorModifyTP()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorModifyTP()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorModifyTP()); break; default: break; } } //+------------------------------------------------------------------+ //| Play price modification error sound | //| for a specified order type | //+------------------------------------------------------------------+ void CTradeObj::PlaySoundErrorModifyPrice(const ENUM_ORDER_TYPE action) { if(!this.m_use_sound) return; int index=action; switch(index) { case ORDER_TYPE_BUY_STOP : CMessage::PlaySound(this.m_datas.BuyStop.SoundErrorModifyPrice()); break; case ORDER_TYPE_BUY_LIMIT : CMessage::PlaySound(this.m_datas.BuyLimit.SoundErrorModifyPrice()); break; case ORDER_TYPE_BUY_STOP_LIMIT : CMessage::PlaySound(this.m_datas.BuyStopLimit.SoundErrorModifyPrice()); break; case ORDER_TYPE_SELL_STOP : CMessage::PlaySound(this.m_datas.SellStop.SoundErrorModifyPrice()); break; case ORDER_TYPE_SELL_LIMIT : CMessage::PlaySound(this.m_datas.SellLimit.SoundErrorModifyPrice()); break; case ORDER_TYPE_SELL_STOP_LIMIT : CMessage::PlaySound(this.m_datas.SellStopLimit.SoundErrorModifyPrice()); break; default: break; } } //+------------------------------------------------------------------+
此处的所有方法均类似,且一目了然:名称里包含交易事件类型的方法会接收一种订单类型(仓位的入场订单类型),然则该事件会被设置、返回或播放。 接着,根据仓位/订单类型设置/返回/播放指定交易事件的声音。
品种基准交易对象的改进至此完毕。 到了开发基准交易类的时候了。
为了能够正确操作,交易类将接收指向先前创建的集合的指针。 为此,我们为每个集合类添加返回指向集合对象指针的方法:
对于历史集合对象:
public: //--- Return itself CHistoryCollection *GetObject(void) { return &this; }
对于入场集合对象:
public: //--- Return itself CMarketCollection *GetObject(void) { return &this; }
对于品种集合:
public: //--- Return itself CSymbolsCollection *GetObject(void) { return &this; }
当前开发的交易类针对交易操作提供了集中访问。 它汇集了发送交易订单前进行所有验证、处理交易服务器响应、以及根据交易服务器响应和类中交易方法行为的设置对将来的动作做出决策。
在本文中,我们要为今后进一步开发的类打下基础。 但首先,我们检查交易限制:程序、终端、账户和品种等方面。
交易类
在 \MQL5\Include\DoEasy\ 之下,于 Trading.mqh 文件里创建新类 CTrading 。
为了令该类正常工作,我们需要一些预先创建的集合列表,从而在检查权限时存储错误,我们需要包含标准库 int 或 uint 变量的动态数组对象。
因此,我们立即将它们包含到类文件中:
//+------------------------------------------------------------------+ //| Trading.mqh | //| Copyright 2019, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayInt.mqh> #include "Objects\Trade\TradeObj.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\HistoryCollection.mqh" //+------------------------------------------------------------------+ //| Trading class | //+------------------------------------------------------------------+
我们来看看类主体的完整清单,并分析其构成:
//+------------------------------------------------------------------+ //| Trading.mqh | //| Copyright 2019, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayInt.mqh> #include "Objects\Trade\TradeObj.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\HistoryCollection.mqh" //+------------------------------------------------------------------+ //| Trading class | //+------------------------------------------------------------------+ class CTrading { private: CAccount *m_account; // Pointer to the current account object CSymbolsCollection *m_symbols; // Pointer to the symbol collection list CMarketCollection *m_market; // Pointer to the list of the collection of market orders and positions CHistoryCollection *m_history; // Pointer to the list of the collection of historical orders and deals CArrayInt m_list_errors; // Error list bool m_is_trade_enable; // Flag enabling trading ENUM_LOG_LEVEL m_log_level; // Logging level //--- Add the error code to the list bool AddErrorCodeToList(const int error_code); //--- Return the symbol object by (1) position, (2) order ticket CSymbol *GetSymbolObjByPosition(const ulong ticket,const string source_method); CSymbol *GetSymbolObjByOrder(const ulong ticket,const string source_method); //--- Return a symbol trading object by (1) position, (2) order ticket, (3) symbol name CTradeObj *GetTradeObjByPosition(const ulong ticket,const string source_method); CTradeObj *GetTradeObjByOrder(const ulong ticket,const string source_method); CTradeObj *GetTradeObjBySymbol(const string symbol,const string source_method); //--- Return the number of (1) all positions, (2) buy, (3) sell positions int PositionsTotalAll(void) const; int PositionsTotalLong(void) const; int PositionsTotalShort(void) const; //--- Return the number of (1) all pending orders, (2) buy, (3) sell pending orders int OrdersTotalAll(void) const; int OrdersTotalLong(void) const; int OrdersTotalShort(void) const; //--- Return the total volume of (1) buy, (2) sell positions double PositionsTotalVolumeLong(void) const; double PositionsTotalVolumeShort(void) const; //--- Return the total volume of (1) buy, (2) sell orders double OrdersTotalVolumeLong(void) const; double OrdersTotalVolumeShort(void) const; //--- Return the order direction by an operation type ENUM_ORDER_TYPE DirectionByActionType(ENUM_ACTION_TYPE action) const; //--- Check the presence of a (1) position, (2) order by ticket bool CheckPositionAvailablity(const ulong ticket,const string source_method); bool CheckOrderAvailablity(const ulong ticket,const string source_method); //--- Set the desired sound for a trading object void SetSoundByMode(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,CTradeObj *trade_obj); public: //--- Constructor CTrading(); //--- Get the pointers to the lists (make sure to call the method in program's OnInit() since the symbol collection list is created there) void OnInit(CAccount *account,CSymbolsCollection *symbols,CMarketCollection *market,CHistoryCollection *history) { this.m_account=account; this.m_symbols=symbols; this.m_market=market; this.m_history=history; } //--- Return the error list CArrayInt *GetListErrors(void) { return &this.m_list_errors; } //--- Check trading limitations bool CheckTradeConstraints(const double volume, const ENUM_ACTION_TYPE action_type, const CSymbol *symbol_obj, const string source_method, double sl=0, double tp=0); //--- Check if the funds are sufficient bool CheckMoneyFree(const ENUM_ORDER_TYPE order_type,const double volume,const double price,const CSymbol *symbol_obj,const string source_method) const; //--- Set the following for symbol trading objects: //--- (1) correct filling policy, (2) filling policy, //--- (3) correct order expiration type, (4) order expiration type, //--- (5) magic number, (6) comment, (7) slippage, (8) volume, (9) order expiration date, //--- (10) the flag of asynchronous sending of a trading request, (11) logging level void SetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol=NULL); void SetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol=NULL); void SetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol=NULL); void SetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol=NULL); void SetMagic(const ulong magic,const string symbol=NULL); void SetComment(const string comment,const string symbol=NULL); void SetDeviation(const ulong deviation,const string symbol=NULL); void SetVolume(const double volume=0,const string symbol=NULL); void SetExpiration(const datetime expiration=0,const string symbol=NULL); void SetAsyncMode(const bool mode=false,const string symbol=NULL); void SetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol=NULL); //--- Set standard sounds (1 symbol=NULL) for trading objects of all symbols, (2 symbol!=NULL) for a symbol trading object void SetSoundsStandart(const string symbol=NULL); //--- Set a sound for a specified order/position type and symbol //--- 'mode' specifies an event a sound is set for //--- (symbol=NULL) for trading objects of all symbols, //--- (symbol!=NULL) for a trading object of a specified symbol void SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL); //--- Open (1) Buy, (2) Sell position bool OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL); bool OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL); //--- Modify a position bool ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE); //--- Close a position (1) fully, (2) partially, (3) by an opposite one bool ClosePosition(const ulong ticket); bool ClosePositionPartially(const ulong ticket,const double volume); bool ClosePositionBy(const ulong ticket,const ulong ticket_by); //--- Set (1) BuyStop, (2) BuyLimit, (3) BuyStopLimit pending order bool PlaceBuyStop(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC); bool PlaceBuyLimit(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC); bool PlaceBuyStopLimit(const double volume, const string symbol, const double price_stop, const double price_limit, const double sl=0, const double tp=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC); //--- Set (1) SellStop, (2) SellLimit, (3) SellStopLimit pending order bool PlaceSellStop(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC); bool PlaceSellLimit(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC); bool PlaceSellStopLimit(const double volume, const string symbol, const double price_stop, const double price_limit, const double sl=0, const double tp=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC); //--- Modify a pending order bool ModifyOrder(const ulong ticket, const double price=WRONG_VALUE, const double sl=WRONG_VALUE, const double tp=WRONG_VALUE, const double stoplimit=WRONG_VALUE, datetime expiration=WRONG_VALUE, ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE); //--- Remove a pending order bool DeleteOrder(const ulong ticket); }; //+------------------------------------------------------------------+
每个类方法都有一个解释性注释,因此,我认为类方法的结构无需其他阐释。
类交易方法与品种基准交易对象的方法具有几乎相同的签章。 唯一的区别在于开仓和下挂单的方法过程中都存在品种名称,而要执行的交易则针对该品种操作。
我们来研究类方法的实现。
由于可能同时存在多种限制,因此每个错误代码均应放在列表中,并在完成所有必要条件检查后显示检测到的限制列表。 为了不将限制值(在验证代码的各个片段中检测到)重复置于列表中,需检查列表中是否存在相应的限制,并仅在没有该限制的情况下将其放入。 在这种情况下,每种限制类型都只会在列表中放置一次。
利用以下方法在列表中检查限制类型是否存在,并将其添加到列表中:
//+------------------------------------------------------------------+ //| Add the error code to the list | //+------------------------------------------------------------------+ bool CTrading::AddErrorCodeToList(const int error_code) { this.m_list_errors.Sort(); if(this.m_list_errors.Search(error_code)==WRONG_VALUE) return this.m_list_errors.Add(error_code); return false; } //+------------------------------------------------------------------+
方法接收错误代码,识别交易限制原因。 将列表已排序标志置位,在列表中检查是否没有该代码。 如果检查成功,则返回利用 Add() 方法将代码添加到列表中的结果。
如果该代码已出现在列表之中,则返回 false。
由于交易对象属于某个品种(每个品种都有其交易对象),而许多交易方法都要配合订单/仓位单据操作,故我们需要定义一个品种,按其单据会存在一笔持仓或订单。
按持仓单据返回品种对象的方法可解决此任务:
//+------------------------------------------------------------------+ //| Return a symbol object by a position ticket | //+------------------------------------------------------------------+ CSymbol *CTrading::GetSymbolObjByPosition(const ulong ticket,const string source_method) { //--- Get the list of open positions CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL); //--- If failed to get the list of open positions, display the message and return NULL if(list==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_MARKET_POS_LIST)); return NULL; } //--- If the list is empty (no open positions), display the message and return NULL if(list.Total()==0) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_ENG_NO_OPEN_POSITIONS)); return NULL; } //--- Sort the list by a ticket list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL); //--- If failed to get the list of open positions, display the message and return NULL if(list==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_MARKET_POS_LIST)); return NULL; } //--- If the list is empty (no required ticket), display the message and return NULL if(list.Total()==0) { //--- Error. No open position with #ticket if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_OPEN_POSITION_WITH_TICKET),(string)ticket); return NULL; } //--- Get a position with #ticket from the obtained list COrder *pos=list.At(0); //--- If failed to get the position object, display the message and return NULL if(pos==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_POS_OBJ)); return NULL; } //--- Get a symbol object by name CSymbol * symbol_obj=this.m_symbols.GetSymbolObjByName(pos.Symbol()); //--- If failed to get the symbol object, display the message and return NULL if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return NULL; } //--- Return a symbol object return symbol_obj; } //+------------------------------------------------------------------+
按一笔订单票据:
//+------------------------------------------------------------------+ //| Return a symbol object by an order ticket | //+------------------------------------------------------------------+ CSymbol *CTrading::GetSymbolObjByOrder(const ulong ticket,const string source_method) { //--- Get the list of placed orders CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL); //--- If failed to get the list of placed orders, display the message and return NULL if(list==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_PENDING_ORD_LIST)); return NULL; } //--- If the list is empty (no placed orders), display the message and return NULL if(list.Total()==0) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_ENG_NO_PLACED_ORDERS)); return NULL; } //--- Sort the list by a ticket list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL); //--- If failed to get the list of placed orders, display the message and return NULL if(list==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_PENDING_ORD_LIST)); return NULL; } //--- If the list is empty (no required ticket), display the message and return NULL if(list.Total()==0) { //--- Error. No placed order with #ticket if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_PLACED_ORDER_WITH_TICKET),(string)ticket); return NULL; } //--- Get an order with #ticket from the obtained list COrder *ord=list.At(0); //--- If failed to get an object order, display the message and return NULL if(ord==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ)); return NULL; } //--- Get a symbol object by name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(ord.Symbol()); //--- If failed to get the symbol object, display the message and return NULL if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return NULL; } //--- Return a symbol object return symbol_obj; } //+------------------------------------------------------------------+
这两种方法几乎相同。 唯一的区别是,我们在第一个当中按票据搜索持仓,而在第二个当中按票据搜索订单。 该方法接收所需仓位或订单的票据,以及调用该方法的源方法名称。 如果出现任何错误,这可令我们能够在日志中看到方法名称。 辅助方法的名称不提供排查错误发生位置的数据(我们需要指定调用搜索品种对象的源方法)。
对于类方法操作,有时我们需要按持仓票据、订单票据或品种名称接收品种交易对象:
//+------------------------------------------------------------------+ //| Return a symbol trading object by a position ticket | //+------------------------------------------------------------------+ CTradeObj *CTrading::GetTradeObjByPosition(const ulong ticket,const string source_method) { //--- Get a symbol object by a position ticket CSymbol * symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); //--- If failed to get the symbol object, display the message and return NULL if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return NULL; } //--- Get and return the trading object from the symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); return trade_obj; } //+------------------------------------------------------------------+ //| Return a symbol trading object by an order ticket | //+------------------------------------------------------------------+ CTradeObj *CTrading::GetTradeObjByOrder(const ulong ticket,const string source_method) { //--- Get a symbol object by an order ticket CSymbol * symbol_obj=this.GetSymbolObjByOrder(ticket,source_method); //--- If failed to get the symbol object, display the message and return NULL if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return NULL; } //--- Get and return the trading object from the symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); return trade_obj; } //+------------------------------------------------------------------+ //| Return a symbol trading object by a symbol name | //+------------------------------------------------------------------+ CTradeObj *CTrading::GetTradeObjBySymbol(const string symbol,const string source_method) { //--- Get a symbol object by its name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return NULL if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST)); return NULL; } //--- Get and return the trading object from the symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); return trade_obj; } //+------------------------------------------------------------------+
所有这三种辅助方法都返回一个交易对象以便后续的操作。 所有操作都在方法清单中有所注释。
我们需要知道两个方向的持仓和订单数量,以便检查一些限制并做出交易决策。
返回账户里持仓数量的方法:
//+------------------------------------------------------------------+ //| Return the number of positions | //+------------------------------------------------------------------+ int CTrading::PositionsTotalAll(void) const { CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL); return(list==NULL ? 0 : list.Total()); } //+------------------------------------------------------------------+
在此,我们接收所有持仓的列表,并下订单,然后按“在场持仓”订单状态对列表进行排序。
返回获得的列表中对象数量。 如果获取列表失败,则返回零。
返回帐户里持仓数量的方法:
//+------------------------------------------------------------------+ //| Return the number of buy positions | //+------------------------------------------------------------------+ int CTrading::PositionsTotalLong(void) const { CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL); return(list==NULL ? 0 : list.Total()); } //+------------------------------------------------------------------+
在此,我们接收所有持仓的列表,并下订单,然后按“在场持仓”订单状态对列表进行排序。
所获得的列表按买入持仓类型排序。
返回获得的列表中的对象数量。 如果获取列表失败,则返回零。
返回账户持仓数量的方法:
//+------------------------------------------------------------------+ //| Return the number of sell positions | //+------------------------------------------------------------------+ int CTrading::PositionsTotalShort(void) const { CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL); return(list==NULL ? 0 : list.Total()); } //+------------------------------------------------------------------+
在此,我们接收所有持仓的列表,并下订单,然后按“在场持仓”订单状态对列表进行排序。
所获得的列表按卖出持仓类型排序。。
返回获得的列表中的对象数量。 如果获取列表失败,则返回零。
接收帐户中所有挂单里买单和卖单数量的方法:
//+------------------------------------------------------------------+ //| Returns the number of pending orders | //+------------------------------------------------------------------+ int CTrading::OrdersTotalAll(void) const { CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL); return(list==NULL ? 0 : list.Total()); } //+------------------------------------------------------------------+ //| Return the number of buy pending orders | //+------------------------------------------------------------------+ int CTrading::OrdersTotalLong(void) const { CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_BUY,EQUAL); return(list==NULL ? 0 : list.Total()); } //+------------------------------------------------------------------+ //| Return the number of sell pending orders | //+------------------------------------------------------------------+ int CTrading::OrdersTotalShort(void) const { CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_SELL,EQUAL); return(list==NULL ? 0 : list.Total()); } //+------------------------------------------------------------------+
这三种辅助方法与上述三种方法相同。 唯一的区别是,此处我们按“活动挂单”状态和买卖订单类型方向对列表进行排序。
另外,为了定义一些极限,我们需要知道持仓和挂单的总量。
返回购买入持仓总交易量的方法:
//+------------------------------------------------------------------+ //| Return the total volume of buy positions | //+------------------------------------------------------------------+ double CTrading::PositionsTotalVolumeLong(void) const { double vol=0; CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL); if(list==NULL || list.Total()==0) return 0; for(int i=0;i<list.Total();i++) { COrder *obj=list.At(i); if(obj==NULL) continue; vol+=obj.Volume(); } return vol; } //+------------------------------------------------------------------+
此处,我们接收所有持仓和已下订单的列表,并按“在场持仓”订单状态对列表进行排序。
所获列表按买入持仓类型排序。
如果列表为空,返回零。
在所获列表里循环,取得下一个订单对象,并将其交易量加入 vol 变量值。
直至循环完成,返回 vol 变量中所获数值 。
返回卖出持仓总交易量的方法:
//+------------------------------------------------------------------+ //| Return the total volume of sell positions | //+------------------------------------------------------------------+ double CTrading::PositionsTotalVolumeShort(void) const { double vol=0; CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL); if(list==NULL || list.Total()==0) return 0; for(int i=0;i<list.Total();i++) { COrder *obj=list.At(i); if(obj==NULL) continue; vol+=obj.Volume(); } return vol; } //+------------------------------------------------------------------+
除了按卖出持仓排序以外,该方法与上一个方法类似。
该方法返回已下挂单的总交易量,包括买入和卖出 订单:
//+------------------------------------------------------------------+ //| Return the total volume of buy orders | //+------------------------------------------------------------------+ double CTrading::OrdersTotalVolumeLong(void) const { double vol=0; CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_BUY,EQUAL); if(list==NULL || list.Total()==0) return 0; for(int i=0;i<list.Total();i++) { COrder *obj=list.At(i); if(obj==NULL) continue; vol+=obj.Volume(); } return vol; } //+------------------------------------------------------------------+ //| Return the total volume of sell orders | //+------------------------------------------------------------------+ double CTrading::OrdersTotalVolumeShort(void) const { double vol=0; CArrayObj *list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL); list=CSelect::ByOrderProperty(list,ORDER_PROP_DIRECTION,ORDER_TYPE_SELL,EQUAL); if(list==NULL || list.Total()==0) return 0; for(int i=0;i<list.Total();i++) { COrder *obj=list.At(i); if(obj==NULL) continue; vol+=obj.Volume(); } return vol; } //+------------------------------------------------------------------+
这些方法与总持仓量方法相同。 尽管,列表按“在场挂单”类型,且则按订单方向(买入或卖出)排序。
该方法按交易操作类型返回订单方向:
//+------------------------------------------------------------------+ //| Return the order direction by an operation type | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE CTrading::DirectionByActionType(ENUM_ACTION_TYPE action) const { if(action>ACTION_TYPE_SELL_STOP_LIMIT) return WRONG_VALUE; return ENUM_ORDER_TYPE(action%2); } //+------------------------------------------------------------------+
如果该方法收到 "close by"(对冲平仓)或 "modification"(修改)类型,则返回 -1。 否则,返回交易操作类型除以 2 之后的余数,最终导致 0(ORDER_TYPE_BUY)或 1(ORDER_TYPE_SELL)。
按票据检查持仓存在的方法:
//+------------------------------------------------------------------+ //| Check if a position is present by ticket | //+------------------------------------------------------------------+ bool CTrading::CheckPositionAvailablity(const ulong ticket,const string source_method) { CArrayObj* list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL); list.Sort(SORT_BY_ORDER_TICKET); list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL); if(list.Total()==1) return true; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_OPEN_POSITION_WITH_TICKET),(string)ticket); return false; } //+------------------------------------------------------------------+
在此,该方法接收一笔选中的持仓票据和源名称。
获取所有持仓和已下订单的列表,并按“在场持仓”订单状态对列表进行排序 。
为列表设置按票证排序的标志。
获得的列表按输入参数传递的票据排序。
如果列表包含单个对象(含有所需票据的持仓),返回 true。
否则,通知该持仓不存在并返回 false。
按票据检查挂单存在的方法:
//+------------------------------------------------------------------+ //| Check the presence of an order by ticket | //+------------------------------------------------------------------+ bool CTrading::CheckOrderAvailablity(const ulong ticket,const string source_method) { CArrayObj* list=this.m_market.GetList(); list=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL); list.Sort(SORT_BY_ORDER_TICKET); list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL); if(list.Total()==1) return true; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_LIB_SYS_ERROR_NO_PLACED_ORDER_WITH_TICKET),(string)ticket); return false; } //+------------------------------------------------------------------+
该方法与上一个方法相同,除了按“在场挂单”状态为列表排序。
将指定音频分配给交易对象的方法:
//+------------------------------------------------------------------+ //| Set a necessary sound to a trading object | //+------------------------------------------------------------------+ void CTrading::SetSoundByMode(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,CTradeObj *trade_obj) { switch(mode) { case MODE_SET_SOUND_OPEN : trade_obj.SetSoundOpen(action,sound); break; case MODE_SET_SOUND_CLOSE : trade_obj.SetSoundClose(action,sound); break; case MODE_SET_SOUND_MODIFY_SL : trade_obj.SetSoundModifySL(action,sound); break; case MODE_SET_SOUND_MODIFY_TP : trade_obj.SetSoundModifyTP(action,sound); break; case MODE_SET_SOUND_MODIFY_PRICE : trade_obj.SetSoundModifyPrice(action,sound); break; case MODE_SET_SOUND_ERROR_OPEN : trade_obj.SetSoundErrorOpen(action,sound); break; case MODE_SET_SOUND_ERROR_CLOSE : trade_obj.SetSoundErrorClose(action,sound); break; case MODE_SET_SOUND_ERROR_MODIFY_SL : trade_obj.SetSoundErrorModifySL(action,sound); break; case MODE_SET_SOUND_ERROR_MODIFY_TP : trade_obj.SetSoundErrorModifyTP(action,sound); break; case MODE_SET_SOUND_ERROR_MODIFY_PRICE : trade_obj.SetSoundErrorModifyPrice(action,sound); break; default: break; } } //+------------------------------------------------------------------+
该方法接收声音设置模式(每个交易事件都有其声音),交易事件的订单类型和要设置的声音,音频文件名 (要分配给订单或仓位交易事件的声音),和需要配置声音的指向交易对象的指针(要设置自定义交易事件声音的目标品种)。
根据传递给该方法的模式,为交易对象设置相应的放置声音的方法。
配置品种交易对象参数的方法,我们在上一篇文章中已有所研究,并在函数库 CEngine 基准对象类中实现了临时方法:
void TradingSetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL); void TradingSetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL); void TradingSetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL); void TradingSetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL); void TradingSetMagic(const ulong magic,const string symbol_name=NULL); void TradingSetComment(const string comment,const string symbol_name=NULL); void TradingSetDeviation(const ulong deviation,const string symbol_name=NULL); void TradingSetVolume(const double volume=0,const string symbol_name=NULL); void TradingSetExpiration(const datetime expiration=0,const string symbol_name=NULL); void TradingSetAsyncMode(const bool mode=false,const string symbol_name=NULL); void TradingSetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL);
已被移至交易类,并在 CEngine 类中进行了修改(它们仅在此处调用方法)。 我们之前已研究过这些方法,这里没有必要再次讨论它们。 可在下面的文件中找到其实现。
设置标准交易对象的方法听起来像这样:
//+------------------------------------------------------------------+ //| Set standard sounds for a symbol trading object | //+------------------------------------------------------------------+ void CTrading::SetSoundsStandart(const string symbol=NULL) { //--- Declare an empty symbol object CSymbol *symbol_obj=NULL; //--- If NULL is passed as a symbol name, set sounds for trading objects of all symbols if(symbol==NULL) { //--- Get the symbol list CArrayObj *list=this.m_symbols.GetList(); if(list==NULL || list.Total()==0) return; //--- In a loop by the list of symbols int total=list.Total(); for(int i=0;i<total;i++) { //--- get the next symbol object symbol_obj=list.At(i); if(symbol_obj==NULL) continue; //--- get a symbol trading object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) continue; //--- set standard sounds for a trading object trade_obj.SetSoundsStandart(); } } //--- If a symbol name is passed else { //--- get a symbol trading object CTradeObj *trade_obj=this.GetTradeObjBySymbol(symbol,DFUN); if(trade_obj==NULL) return; //--- set standard sounds for a trading object trade_obj.SetSoundsStandart(); } } //+------------------------------------------------------------------+
为指定订单的指定交易事件设置声音的方法:
//+------------------------------------------------------------------+ //| Set a sound for a specified order/position type and symbol | //| 'mode' specifies an event a sound is set for | //| (symbol=NULL) for trading objects of all symbols, | //| (symbol!=NULL) for a trading object of a specified symbol | //+------------------------------------------------------------------+ void CTrading::SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL) { //--- Declare an empty symbol object CSymbol *symbol_obj=NULL; //--- If NULL is passed as a symbol name, set sounds for trading objects of all symbols if(symbol==NULL) { //--- Get the symbol list CArrayObj *list=this.m_symbols.GetList(); if(list==NULL || list.Total()==0) return; //--- In a loop by the list of symbols int total=list.Total(); for(int i=0;i<total;i++) { //--- get the next symbol object symbol_obj=list.At(i); if(symbol_obj==NULL) continue; //--- get a symbol trading object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) continue; //--- set a sound of a necessary event for a trading object this.SetSoundByMode(mode,action,sound,trade_obj); } } //--- If a symbol name is passed else { //--- get a symbol trading object CTradeObj *trade_obj=this.GetTradeObjBySymbol(symbol,DFUN); if(trade_obj==NULL) return; //--- set a sound of a necessary event for a trading object this.SetSoundByMode(mode,action,sound,trade_obj); } } //+------------------------------------------------------------------+
两种方法中的所有动作均在代码注释中进行了阐释。
在本文中,我们将创建初始验证交易限制的方法。 我们可以分配给该类别什么呢? 这是检查进行交易操作时资金是否充足。 如果资金不足,则无必要发送请求。 此类限制需要时间来消除。 我们需要以自然方式等待可用资金的增加 — 根据交易策略计划平仓,从而盈利(亏损)并释放出足够开仓的保证金,或仅为了返还保证金而将亏损持仓强制平仓,再或者就为帐户充值。 对于目前情况,更容易的是于此返回“不可能履行交易请求”的标志。
此外,还有其他一些交易限制 — 在终端中禁用自动交易,在其设置中禁用 EA 的自动交易,从服务器端或特定交易品种禁用自动交易,以及其他一些因素。
这就是我们将在本文中为交易类实现的所有内容。
检查资金是否充足,以便执行交易操作的方法:
//+------------------------------------------------------------------+ //| Check if the funds are sufficient | //+------------------------------------------------------------------+ bool CTrading::CheckMoneyFree(const ENUM_ORDER_TYPE order_type,const double volume,const double price,const CSymbol *symbol_obj,const string source_method) const { ::ResetLastError(); //--- Get the type of a market order by a trading operation type ENUM_ORDER_TYPE action=this.DirectionByActionType((ENUM_ACTION_TYPE)order_type); //--- Get the value of free funds to be left after conducting a trading operation double money_free= ( //--- For MQL5, calculate the difference between free funds and the funds required to conduct a trading operation #ifdef __MQL5__ this.m_account.MarginFree()-this.m_account.MarginForAction(action,symbol_obj.Name(),volume,price) //--- For MQL4, use the operation result of the standard function returning the amount of funds left #else/*__MQL4__*/::AccountFreeMarginCheck(symbol_obj.Name(),order_type,volume) #endif ); //--- If no free funds are left, inform of that and return 'false' if(money_free<=0 #ifdef __MQL4__ || ::GetLastError()==134 #endif ) { if(this.m_log_level>LOG_LEVEL_NO_MSG) { //--- create a message text string message= ( symbol_obj.Name()+" "+::DoubleToString(volume,symbol_obj.DigitsLot())+" "+ ( order_type>ORDER_TYPE_SELL ? OrderTypeDescription(order_type,false,false) : PositionTypeDescription(PositionTypeByOrderType(order_type)) )+" ("+::DoubleToString(money_free,(int)this.m_account.CurrencyDigits())+")" ); //--- display a journal message if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR),message); } return false; } //--- Verification successful return true; } //+------------------------------------------------------------------+
该方法检查进行交易操作的限制:
//+------------------------------------------------------------------+ //| Check trading limitations | //+------------------------------------------------------------------+ bool CTrading::CheckTradeConstraints(const double volume, const ENUM_ACTION_TYPE action_type, const CSymbol *symbol_obj, const string source_method, double sl=0, double tp=0) { //--- the result of conducting all checks bool res=true; //--- Clear the error list (codes of found limitations) this.m_list_errors.Clear(); this.m_list_errors.Sort(); //--- Check connection with the trade server (not in the test mode) if(!::TerminalInfoInteger(TERMINAL_CONNECTED)) { if(!::MQLInfoInteger(MQL_TESTER)) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_TERMINAL_NOT_CONNECTED); res &=false; } } //--- Check if trading is enabled for an account (if there is a connection with the trade server) else if(!this.m_account.TradeAllowed()) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED); res &=false; } //--- Check if trading is allowed for any EAs/scripts for the current account if(!this.m_account.TradeExpert()) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED); res &=false; } //--- Check if auto trading is allowed in the terminal. //--- AutoTrading button (Options --> Expert Advisors --> "Allowed automated trading") if(!::TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED); res &=false; } //--- Check if auto trading is allowed for the current EA. //--- (F7 --> Common --> Allow Automated Trading) if(!::MQLInfoInteger(MQL_TRADE_ALLOWED)) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED); res &=false; } //--- Check if trading is enabled on a symbol. //--- If trading is disabled, add the error code to the list and write 'false' to the result if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_DISABLED) { this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_DISABLED); res &=false; } //--- If not closing/removal/modification if(action_type>WRONG_VALUE && action_type<ACTION_TYPE_CLOSE_BY) { //--- In case of close-only, add the error code to the list and write 'false' to the result if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_CLOSEONLY) { this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_CLOSEONLY); res &=false; } //--- Check the minimum volume if(volume<symbol_obj.LotsMin()) { //--- The volume in a request is less than the minimum allowed one //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME); res &=false; } //--- Check the maximum volume else if(volume>symbol_obj.LotsMax()) { //--- The volume in the request exceeds the maximum acceptable one //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME); res &=false; } //--- Check the minimum volume gradation double step=symbol_obj.LotsStep(); if(fabs((int)round(volume/step)*step-volume)>0.0000001) { //--- The volume in the request is not a multiple of the minimum gradation of the lot change step //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_INVALID_VOLUME_STEP); res &=false; } } //--- When opening a position if(action_type>WRONG_VALUE && action_type<ACTION_TYPE_BUY_LIMIT) { //--- Check if sending market orders is allowed on a symbol. //--- If trading market orders is disabled, add the error code to the list and write 'false' to the result if(!symbol_obj.IsMarketOrdersAllowed()) { this.AddErrorCodeToList(MSG_SYM_MARKET_ORDER_DISABLED); res &=false; } } //--- When placing a pending order else if(action_type>ACTION_TYPE_SELL && action_type<ACTION_TYPE_CLOSE_BY) { //--- If there is a limitation on the number of pending orders on the account //--- and placing a new order exceeds the acceptable number if(this.m_account.LimitOrders()>0 && this.OrdersTotalAll()+1 > this.m_account.LimitOrders()) { //--- The maximum number of pending orders is reached //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(10033); res &=false; } //--- Check if placing limit orders is allowed on a symbol. if(action_type==ACTION_TYPE_BUY_LIMIT || action_type==ACTION_TYPE_SELL_LIMIT) { //--- If it is not, add the error code to the list and write 'false' to the result if(!symbol_obj.IsLimitOrdersAllowed()) { this.AddErrorCodeToList(MSG_SYM_LIMIT_ORDER_DISABLED); res &=false; } } //--- Check if placing stop orders is allowed on a symbol. else if(action_type==ACTION_TYPE_BUY_STOP || action_type==ACTION_TYPE_SELL_STOP) { //--- If placing stop orders is disabled, add the error code to the list and write 'false' to the result if(!symbol_obj.IsStopOrdersAllowed()) { this.AddErrorCodeToList(MSG_SYM_STOP_ORDER_DISABLED); res &=false; } } //--- For MQL5, check if placing stop limit orders is allowed on a symbol. #ifdef __MQL5__ else if(action_type==ACTION_TYPE_BUY_STOP_LIMIT || action_type==ACTION_TYPE_SELL_STOP_LIMIT) { //--- If it is not, add the error code to the list and write 'false' to the result if(!symbol_obj.IsStopLimitOrdersAllowed()) { this.AddErrorCodeToList(MSG_SYM_STOP_LIMIT_ORDER_DISABLED); res &=false; } } #endif } //--- In case of opening/placing/modification if(action_type>WRONG_VALUE && action_type!=ACTION_TYPE_CLOSE_BY) { //--- If not modification if(action_type!=ACTION_TYPE_MODIFY) { //--- When buying, check if long trading is enabled on a symbol if(this.DirectionByActionType(action_type)==ORDER_TYPE_BUY) { //--- If only selling is allowed, add the error code to the list and write 'false' to the result if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_SHORTONLY) { this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_SHORTONLY); res &=false; } //--- If a symbol has the limitation on the total volume of an open position and pending orders in the same direction if(symbol_obj.VolumeLimit()>0) { //--- (If the total volume of placed long orders and open long positions)+open volume exceed the maximum one if(this.OrdersTotalVolumeLong()+this.PositionsTotalVolumeLong()+volume > symbol_obj.VolumeLimit()) { //--- Exceeded maximum allowed aggregate volume of orders and positions in one direction //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED); res &=false; } } } //--- When selling, check if short trading is enabled on a symbol else if(this.DirectionByActionType(action_type)==ORDER_TYPE_SELL) { //--- If only buying is allowed, add the error code to the list and write 'false' to the result if(symbol_obj.TradeMode()==SYMBOL_TRADE_MODE_LONGONLY) { this.AddErrorCodeToList(MSG_SYM_TRADE_MODE_LONGONLY); res &=false; } //--- If a symbol has the limitation on the total volume of an open position and pending orders in the same direction if(symbol_obj.VolumeLimit()>0) { //--- (If the total volume of placed short orders and open short positions)+open volume exceed the maximum one if(this.OrdersTotalVolumeShort()+this.PositionsTotalVolumeShort()+volume > symbol_obj.VolumeLimit()) { //--- Exceeded maximum allowed aggregate volume of orders and positions in one direction //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_MAX_VOLUME_LIMIT_EXCEEDED); res &=false; } } } } //--- If the request features StopLoss and its placing is not allowed if(sl>0 && !symbol_obj.IsStopLossOrdersAllowed()) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_SYM_SL_ORDER_DISABLED); res &=false; } //--- If the request features TakeProfit and its placing is not allowed if(tp>0 && !symbol_obj.IsTakeProfitOrdersAllowed()) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_SYM_TP_ORDER_DISABLED); res &=false; } } //--- When closing by an opposite position else if(action_type==ACTION_TYPE_CLOSE_BY) { //--- When closing by an opposite position is disabled if(!symbol_obj.IsCloseByOrdersAllowed()) { //--- add the error code to the list and write 'false' to the result this.AddErrorCodeToList(MSG_LIB_TEXT_CLOSE_BY_ORDERS_DISABLED); res &=false; } } //--- If there are limitations, display the header and the error list if(!res) { //--- Request was rejected before sending to the server due to: int total=this.m_list_errors.Total(); if(this.m_log_level>LOG_LEVEL_NO_MSG) { //--- For MQL5, first display the list header followed by the error list #ifdef __MQL5__ ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_REQUEST_REJECTED_DUE)); for(int i=0;i<total;i++) ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i))); //--- For MQL4, the journal messages are displayed in the reverse order: the error list is followed by the list header #else for(int i=total-1;i>WRONG_VALUE;i--) ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i))); ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_REQUEST_REJECTED_DUE)); #endif } } return res; } //+------------------------------------------------------------------+
该方法非常庞杂,但于此已经很熟悉了 — 检查程序、终端、帐户或品种的属性,是否会受到限制。 如果存在限制,则将检测到的限制代码添加到列表中,并在结果标记置为 false。 经过所有检查后,如果变量为 false,则显示限制代码列表,在循环中显示检测到的限制列表的标题,并在标题下显示所有检测到的交易限制。 如果存储检查结果的变量为 true(此变量的原始初始化值),则所有检查都已通过,并返回 true。
在当前版本的交易类中,我们将止步于此。 今后,当创建错误处理方法时,所有限制和错误的响应操作都将在这个类中处理。
类中的交易方法:
//+------------------------------------------------------------------+ //| Open Buy position | //+------------------------------------------------------------------+ bool CTrading::OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY,symbol_obj,DFUN,sl,tp)) { return false; } //--- If the funds are insufficient, inform of that and exit if(!this.CheckMoneyFree(ORDER_TYPE_BUY,volume,symbol_obj.Ask(),symbol_obj,DFUN)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.OpenPosition(POSITION_TYPE_BUY,volume,sl,tp,magic,trade_obj.GetDeviation(),comment); } //+------------------------------------------------------------------+ //| Open a Sell position | //+------------------------------------------------------------------+ bool CTrading::OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL,symbol_obj,DFUN,sl,tp)) { return false; } //--- If the funds are insufficient, inform of that and exit if(!this.CheckMoneyFree(ORDER_TYPE_SELL,volume,symbol_obj.Bid(),symbol_obj,DFUN)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.OpenPosition(POSITION_TYPE_SELL,volume,sl,tp,magic,trade_obj.GetDeviation(),comment); } //+------------------------------------------------------------------+ //| Modify a position | //+------------------------------------------------------------------+ bool CTrading::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE) { //--- Get a symbol object by a position ticket CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(0,ACTION_TYPE_MODIFY,symbol_obj,DFUN,sl,tp)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.ModifyPosition(ticket,sl,tp); } //+------------------------------------------------------------------+ //| Close a position in full | //+------------------------------------------------------------------+ bool CTrading::ClosePosition(const ulong ticket) { //--- Get a symbol object by a position ticket CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.ClosePosition(ticket); } //+------------------------------------------------------------------+ //| Close a position partially | //+------------------------------------------------------------------+ bool CTrading::ClosePositionPartially(const ulong ticket,const double volume) { //--- Get a symbol object by a position ticket CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.ClosePositionPartially(ticket,symbol_obj.NormalizedLot(volume)); } //+------------------------------------------------------------------+ //| Close a position by an opposite one | //+------------------------------------------------------------------+ bool CTrading::ClosePositionBy(const ulong ticket,const ulong ticket_by) { //--- Get a symbol object by a position ticket CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(0,ACTION_TYPE_CLOSE_BY,symbol_obj,DFUN)) { return false; } //--- trading object of a closed position CTradeObj *trade_obj_pos=this.GetTradeObjByPosition(ticket,DFUN); if(trade_obj_pos==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- check the presence of an opposite position if(!this.CheckPositionAvailablity(ticket_by,DFUN)) return false; //--- trading object of an opposite position CTradeObj *trade_obj_pos_by=this.GetTradeObjByPosition(ticket_by,DFUN); if(trade_obj_pos_by==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- If a symbol of a closed position is not equal to an opposite position's one, inform of that and exit if(symbol_obj.Name()!=trade_obj_pos_by.GetSymbol()) { //--- Symbols of opposite positions are not equal if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj_pos.ClosePositionBy(ticket,ticket_by); } //+------------------------------------------------------------------+ //| Place BuyStop pending order | //+------------------------------------------------------------------+ bool CTrading::PlaceBuyStop(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_STOP,symbol_obj,DFUN,sl,tp)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.SetOrder(ORDER_TYPE_BUY_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment); } //+------------------------------------------------------------------+ //| Place BuyLimit pending order | //+------------------------------------------------------------------+ bool CTrading::PlaceBuyLimit(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_LIMIT,symbol_obj,DFUN,sl,tp)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.SetOrder(ORDER_TYPE_BUY_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment); } //+------------------------------------------------------------------+ //| Place BuyStopLimit pending order | //+------------------------------------------------------------------+ bool CTrading::PlaceBuyStopLimit(const double volume, const string symbol, const double price_stop, const double price_limit, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_BUY_STOP_LIMIT,symbol_obj,DFUN,sl,tp)) { return false; } #ifdef __MQL5__ //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.SetOrder(ORDER_TYPE_BUY_STOP_LIMIT,volume,price_stop,sl,tp,price_limit,magic,expiration,type_time,comment); //--- MQL4 #else return true; #endif } //+------------------------------------------------------------------+ //| Place SellStop pending order | //+------------------------------------------------------------------+ bool CTrading::PlaceSellStop(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_STOP,symbol_obj,DFUN,sl,tp)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.SetOrder(ORDER_TYPE_SELL_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment); } //+------------------------------------------------------------------+ //| Place SellLimit pending order | //+------------------------------------------------------------------+ bool CTrading::PlaceSellLimit(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_LIMIT,symbol_obj,DFUN,sl,tp)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.SetOrder(ORDER_TYPE_SELL_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment); } //+------------------------------------------------------------------+ //| Place SellStopLimit pending order | //+------------------------------------------------------------------+ bool CTrading::PlaceSellStopLimit(const double volume, const string symbol, const double price_stop, const double price_limit, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(volume,ACTION_TYPE_SELL_STOP_LIMIT,symbol_obj,DFUN,sl,tp)) { return false; } #ifdef __MQL5__ //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.SetOrder(ORDER_TYPE_SELL_STOP_LIMIT,volume,price_stop,sl,tp,price_limit,magic,expiration,type_time,comment); //--- MQL4 #else return true; #endif } //+------------------------------------------------------------------+ //| Modify a pending order | //+------------------------------------------------------------------+ bool CTrading::ModifyOrder(const ulong ticket, const double price=WRONG_VALUE, const double sl=WRONG_VALUE, const double tp=WRONG_VALUE, const double stoplimit=WRONG_VALUE, datetime expiration=WRONG_VALUE, ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE) { //--- Get a symbol object by an order ticket CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(0,ACTION_TYPE_MODIFY,symbol_obj,DFUN,sl,tp)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.ModifyOrder(ticket,price,sl,tp,stoplimit,expiration,type_time); } //+------------------------------------------------------------------+ //| Remove a pending order | //+------------------------------------------------------------------+ bool CTrading::DeleteOrder(const ulong ticket) { //--- Get a symbol object by an order ticket CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Update symbol quotes symbol_obj.RefreshRates(); //--- If there are trading limitations, inform of that and exit if(!this.CheckTradeConstraints(0,WRONG_VALUE,symbol_obj,DFUN)) { return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { //--- Error. Failed to get trading object if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Return the result of sending a trading request in a symbol trading object return trade_obj.DeleteOrder(ticket); } //+------------------------------------------------------------------+
在创建基准交易对象时,我们已经在上一篇文章中研究了交易方法(将交易请求发送到服务器)。 在此,具有相似签章的方法接收交易请求的必要参数,检查上述的交易限制,并调用基准品种交易对象的相应方法。 操作方法的结果返回给程序。
在此阶段,所有这些都是要在发送交易请求之前进行的检查。 由于我们需要检查和处理交易请求参数的有效性,因此我们要进一步扩展它们。 现在假设所有参数都为有效。
所有计划中的功能在当前实现的交易类里均已准备就绪。
现在我们需要从函数库 CEngine 基类中访问它,并通过它操控类中的交易方法。
打开 \MQL5\Include\DoEasy\Engine.mqh,并在其中进行所有必要的修改。
首先,在其内包含交易类文件:
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2019, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Services\TimerCounter.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\EventsCollection.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\ResourceCollection.mqh" #include "Trading.mqh" //+------------------------------------------------------------------+
在类的私密部分中,声明交易类对象:
//+------------------------------------------------------------------+ //| Library basis class | //+------------------------------------------------------------------+ class CEngine { private: CHistoryCollection m_history; // Collection of historical orders and deals CMarketCollection m_market; // Collection of market orders and deals CEventsCollection m_events; // Event collection CAccountsCollection m_accounts; // Account collection CSymbolsCollection m_symbols; // Symbol collection CResourceCollection m_resource; // Resource list CTrading m_trading; // Trading class object CArrayObj m_list_counters; // List of timer counters int m_global_error; // Global error code bool m_first_start; // First launch flag bool m_is_hedge; // Hedge account flag bool m_is_tester; // Flag of working in the tester bool m_is_market_trade_event; // Account trading event flag bool m_is_history_trade_event; // Account history trading event flag bool m_is_account_event; // Account change event flag bool m_is_symbol_event; // Symbol change event flag ENUM_TRADE_EVENT m_last_trade_event; // Last account trading event int m_last_account_event; // Last event in the account properties int m_last_symbol_event; // Last event in the symbol properties //--- Return the counter index by id
这些方法
//--- Set the following for the trading classes: //--- (1) correct filling policy, (2) filling policy, //--- (3) correct order expiration type, (4) order expiration type, //--- (5) magic number, (6) comment, (7) slippage, (8) volume, (9) order expiration date, //--- (10) the flag of asynchronous sending of a trading request, (11) logging level void SetTradeCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL); void SetTradeTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL); void SetTradeCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL); void SetTradeTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL); void SetTradeMagic(const ulong magic,const string symbol_name=NULL); void SetTradeComment(const string comment,const string symbol_name=NULL); void SetTradeDeviation(const ulong deviation,const string symbol_name=NULL); void SetTradeVolume(const double volume=0,const string symbol_name=NULL); void SetTradeExpiration(const datetime expiration=0,const string symbol_name=NULL); void SetTradeAsyncMode(const bool mode=false,const string symbol_name=NULL); void SetTradeLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL);
重命名为
//--- Set the following for the trading classes: //--- (1) correct filling policy, (2) filling policy, //--- (3) correct order expiration type, (4) order expiration type, //--- (5) magic number, (6) comment, (7) slippage, (8) volume, (9) order expiration date, //--- (10) the flag of asynchronous sending of a trading request, (11) logging level void TradingSetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL); void TradingSetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL); void TradingSetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL); void TradingSetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL); void TradingSetMagic(const ulong magic,const string symbol_name=NULL); void TradingSetComment(const string comment,const string symbol_name=NULL); void TradingSetDeviation(const ulong deviation,const string symbol_name=NULL); void TradingSetVolume(const double volume=0,const string symbol_name=NULL); void TradingSetExpiration(const datetime expiration=0,const string symbol_name=NULL); void TradingSetAsyncMode(const bool mode=false,const string symbol_name=NULL); void TradingSetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL);
因此,它们的名称表示它们属于该交易类。
在类的公开部分,加入设置标准声音的方法,指定持仓/订单类型以及交易事件的声音,还有将指向全部所需集合列表的指针发送给交易类的方法。 此外,声明按其描述播放声音的方法:
//--- Set standard sounds (symbol==NULL) for a symbol trading object, (symbol!=NULL) for trading objects of all symbols void SetSoundsStandart(const string symbol=NULL) { this.m_trading.SetSoundsStandart(symbol); } //--- Set a sound for a specified order/position type and symbol. 'mode' specifies an event a sound is set for //--- (symbol=NULL) for trading objects of all symbols, (symbol!=NULL) for a trading object of a specified symbol void SetSound(const ENUM_MODE_SET_SOUND mode,const ENUM_ORDER_TYPE action,const string sound,const string symbol=NULL) { this.m_trading.SetSound(mode,action,sound,symbol); } //--- Play a sound by its description bool PlaySoundByDescription(const string sound_description); //--- Pass the pointers to all the necessary collections to the trading class void TradingOnInit(void) { this.m_trading.OnInit(this.GetAccountCurrent(),m_symbols.GetObject(),m_market.GetObject(),m_history.GetObject()); }
三种方法仅调用相同名称的交易类方法。 我们通过下面的阐述来研究播放声音的方法:
//+------------------------------------------------------------------+ //| Play a sound by its description | //+------------------------------------------------------------------+ bool CEngine::PlaySoundByDescription(const string sound_description) { string file_name=NULL; //--- Get the list of resources CArrayObj* list=this.GetListResource(); if(list==NULL) return false; //--- Get an index of a resource object by its description int index=this.m_resource.GetIndexResObjByDescription(sound_description); //--- If a resource object with a specified description is found in the list if(index>WRONG_VALUE) { //--- Get a resource object by its index in the list CResObj *res_obj=list.At(index); if(res_obj==NULL) return false; //--- Get a resource object file name file_name=res_obj.FileName(); } //--- If there is no resource object with a specified description in the list, attempt to play the file by the name written in its description //--- To do this, make sure that either a standard audio file (macro substitution of its name), //--- or a name of a new *.wav audio file is passed as a description else if(::StringFind(sound_description,"SND_")==0 || StringSubstr(sound_description,StringLen(sound_description)-4)==".wav") file_name=sound_description; //--- Return the file playing result return(file_name!=NULL ? CMessage::PlaySound(file_name) : false); } //+------------------------------------------------------------------+
之前,我们创建了资源对象,可以在其中存储音频和图像文件。 我们曾增加了为每种资源添加说明的功能。 所以,我们可以轻松地指定需要播放的音频文件。 例如,记住自定义文件描述比记住其名称容易得多。 如果文件名是 “featureless”(如 sound_01.wav),我们可以为其设置任何描述,例如 “EURUSD 买入开仓声音”。
该方法允许在其参数中指定必要的文件说明。 它检测含有匹配说明的资源对象,并播放声音。 可选地,该方法能够通过我们在 Defines.mqh 中创建的名称宏替换,以及任何未知的声音文件来播放标准声音。 我们只需要传递其名称作为其描述即可。 这样的文件应位于终端沙箱中,拥有 wav 扩展名,并在其名称中含有指定的正确路径。
我们暂时放置在 CEngine 类中的交易方法,以及设置交易对象参数的方法,还有那些暂时位于 CEngine 中的方法已被修改 — 所有这些方法及其实现已移至交易类,而相应的交易类方法只需简单地从 CEngine 类方法中调用即可:
//+------------------------------------------------------------------+ //| Open Buy position | //+------------------------------------------------------------------+ bool CEngine::OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL) { return this.m_trading.OpenBuy(volume,symbol,magic,sl,tp,comment); } //+------------------------------------------------------------------+ //| Open a Sell position | //+------------------------------------------------------------------+ bool CEngine::OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL) { return this.m_trading.OpenSell(volume,symbol,magic,sl,tp,comment); } //+------------------------------------------------------------------+ //| Modify a position | //+------------------------------------------------------------------+ bool CEngine::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE) { return this.m_trading.ModifyPosition(ticket,sl,tp); } //+------------------------------------------------------------------+ //| Close a position in full | //+------------------------------------------------------------------+ bool CEngine::ClosePosition(const ulong ticket) { return this.m_trading.ClosePosition(ticket); } //+------------------------------------------------------------------+ //| Close a position partially | //+------------------------------------------------------------------+ bool CEngine::ClosePositionPartially(const ulong ticket,const double volume) { return this.m_trading.ClosePositionPartially(ticket,volume); } //+------------------------------------------------------------------+ //| Close a position by an opposite one | //+------------------------------------------------------------------+ bool CEngine::ClosePositionBy(const ulong ticket,const ulong ticket_by) { return this.m_trading.ClosePositionBy(ticket,ticket_by); } //+------------------------------------------------------------------+ //| Place BuyStop pending order | //+------------------------------------------------------------------+ bool CEngine::PlaceBuyStop(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { return this.m_trading.PlaceBuyStop(volume,symbol,price,sl,tp,magic,comment,expiration,type_time); } //+------------------------------------------------------------------+ //| Place BuyLimit pending order | //+------------------------------------------------------------------+ bool CEngine::PlaceBuyLimit(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { return this.m_trading.PlaceBuyLimit(volume,symbol,price,sl,tp,magic,comment,expiration,type_time); } //+------------------------------------------------------------------+ //| Place BuyStopLimit pending order | //+------------------------------------------------------------------+ bool CEngine::PlaceBuyStopLimit(const double volume, const string symbol, const double price_stop, const double price_limit, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { return this.m_trading.PlaceBuyStopLimit(volume,symbol,price_stop,price_limit,sl,tp,magic,comment,expiration,type_time); } //+------------------------------------------------------------------+ //| Place SellStop pending order | //+------------------------------------------------------------------+ bool CEngine::PlaceSellStop(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { return this.m_trading.PlaceSellStop(volume,symbol,price,sl,tp,magic,comment,expiration,type_time); } //+------------------------------------------------------------------+ //| Place SellLimit pending order | //+------------------------------------------------------------------+ bool CEngine::PlaceSellLimit(const double volume, const string symbol, const double price, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { return this.m_trading.PlaceSellLimit(volume,symbol,price,sl,tp,magic,comment,expiration,type_time); } //+------------------------------------------------------------------+ //| Place SellStopLimit pending order | //+------------------------------------------------------------------+ bool CEngine::PlaceSellStopLimit(const double volume, const string symbol, const double price_stop, const double price_limit, const double sl=0, const double tp=0, const ulong magic=WRONG_VALUE, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC) { return this.m_trading.PlaceSellStopLimit(volume,symbol,price_stop,price_limit,sl,tp,magic,comment,expiration,type_time); } //+------------------------------------------------------------------+ //| Modify a pending order | //+------------------------------------------------------------------+ bool CEngine::ModifyOrder(const ulong ticket, const double price=WRONG_VALUE, const double sl=WRONG_VALUE, const double tp=WRONG_VALUE, const double stoplimit=WRONG_VALUE, datetime expiration=WRONG_VALUE, ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE) { return this.m_trading.ModifyOrder(ticket,price,sl,tp,stoplimit,expiration,type_time); } //+------------------------------------------------------------------+ //| Remove a pending order | //+------------------------------------------------------------------+ bool CEngine::DeleteOrder(const ulong ticket) { return this.m_trading.DeleteOrder(ticket); } //+------------------------------------------------------------------+ //| Set the valid filling policy | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL) { this.m_trading.SetCorrectTypeFilling(type,symbol_name); } //+------------------------------------------------------------------+ //| Set the filling policy | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL) { this.m_trading.SetTypeFilling(type,symbol_name); } //+------------------------------------------------------------------+ //| Set a correct order expiration type | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL) { this.m_trading.SetCorrectTypeExpiration(type,symbol_name); } //+------------------------------------------------------------------+ //| Set an order expiration type | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL) { this.m_trading.SetTypeExpiration(type,symbol_name); } //+------------------------------------------------------------------+ //| Set a magic number for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetMagic(const ulong magic,const string symbol_name=NULL) { this.m_trading.SetMagic(magic,symbol_name); } //+------------------------------------------------------------------+ //| Set a comment for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetComment(const string comment,const string symbol_name=NULL) { this.m_trading.SetComment(comment,symbol_name); } //+------------------------------------------------------------------+ //| Set a slippage | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetDeviation(const ulong deviation,const string symbol_name=NULL) { this.m_trading.SetDeviation(deviation,symbol_name); } //+------------------------------------------------------------------+ //| Set a volume for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetVolume(const double volume=0,const string symbol_name=NULL) { this.m_trading.SetVolume(volume,symbol_name); } //+------------------------------------------------------------------+ //| Set an order expiration date | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetExpiration(const datetime expiration=0,const string symbol_name=NULL) { this.m_trading.SetExpiration(expiration,symbol_name); } //+------------------------------------------------------------------+ //| Set the flag of asynchronous sending of trading requests | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetAsyncMode(const bool mode=false,const string symbol_name=NULL) { this.m_trading.SetAsyncMode(mode,symbol_name); } //+------------------------------------------------------------------+ //| Set a logging level of trading requests | //| for trading objects of all symbols | //+------------------------------------------------------------------+ void CEngine::TradingSetLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL) { this.m_trading.SetLogLevel(log_level,symbol_name); } //+------------------------------------------------------------------+
CEngine 类的改进至此完毕。 现在,我们需要检查所有这些如何操作。
测试
为了执行测试,我们利用来自前篇文章里的 EA,将其保存至 \MQL5\Experts\TestDoEasy\Part22\ 之下,并命名为 TestDoEasyPart22.mq5。
在以前的 EA 中,OnInit() 响应程序在日志中显示了许多文本验证数据。 当前,我们不需要它,因此我们删除所有多余的 Print(),并添加交易类初始化,以及通过宏替换检查标准声音播放和按其说明播放自定义声音:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Calling the function displays the list of enumeration constants in the journal //--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity //EnumNumbersTest(); //--- Set EA global variables prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_"; for(int i=0;i<TOTAL_BUTT;i++) { butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i); butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i); } lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0)); magic_number=InpMagic; stoploss=InpStopLoss; takeprofit=InpTakeProfit; distance_pending=InpDistance; distance_stoplimit=InpDistanceSL; slippage=InpSlippage; trailing_stop=InpTrailingStop*Point(); trailing_step=InpTrailingStep*Point(); trailing_start=InpTrailingStart; stoploss_to_modify=InpStopLossModify; takeprofit_to_modify=InpTakeProfitModify; //--- Check if working with the full list is selected used_symbols_mode=InpModeUsedSymbols; if((ENUM_SYMBOLS_MODE)used_symbols_mode==SYMBOLS_MODE_ALL) { int total=SymbolsTotal(false); string ru_n="\nКоличество символов на сервере "+(string)total+".\nМаксимальное количество: "+(string)SYMBOLS_COMMON_TOTAL+" символов."; string en_n="\nNumber of symbols on server "+(string)total+".\nMaximum number: "+(string)SYMBOLS_COMMON_TOTAL+" symbols."; string caption=TextByLanguage("Внимание!","Attention!"); string ru="Выбран режим работы с полным списком.\nВ этом режиме первичная подготовка списка коллекции символов может занять длительное время."+ru_n+"\nПродолжить?\n\"Нет\" - работа с текущим символом \""+Symbol()+"\""; string en="Full list mode selected.\nIn this mode, the initial preparation of the collection symbols list may take a long time."+en_n+"\nContinue?\n\"No\" - working with the current symbol \""+Symbol()+"\""; string message=TextByLanguage(ru,en); int flags=(MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2); int mb_res=MessageBox(message,caption,flags); switch(mb_res) { case IDNO : used_symbols_mode=SYMBOLS_MODE_CURRENT; break; default: break; } } //--- Fill in the array of used symbols used_symbols=InpUsedSymbols; CreateUsedSymbolsArray((ENUM_SYMBOLS_MODE)used_symbols_mode,used_symbols,array_used_symbols); //--- Set the type of the used symbol list in the symbol collection engine.SetUsedSymbols(array_used_symbols); //--- Displaying the selected mode of working with the symbol object collection Print(engine.ModeSymbolsListDescription(),TextByLanguage(". Number of used symbols: ",". Number of symbols used: "),engine.GetSymbolsCollectionTotal()); //--- Create resource text files engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_01",TextByLanguage("Звук упавшей монетки 1","Sound of falling coin 1"),sound_array_coin_01); engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_02",TextByLanguage("Звук упавших монеток","Falling coins"),sound_array_coin_02); engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_03",TextByLanguage("Звук монеток","Coins"),sound_array_coin_03); engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_04",TextByLanguage("Звук упавшей монетки 2","Sound of falling coin 2"),sound_array_coin_04); engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_01",TextByLanguage("Звук щелчка по кнопке 1","Click on button sound 1"),sound_array_click_01); engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_02",TextByLanguage("Звук щелчка по кнопке 2","Click on button sound 1"),sound_array_click_02); engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_03",TextByLanguage("Звук щелчка по кнопке 3","Click on button sound 1"),sound_array_click_03); engine.CreateFile(FILE_TYPE_WAV,"sound_array_cash_machine_01",TextByLanguage("Звук кассового аппарата","Sound of cash machine"),sound_array_cash_machine_01); engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_green",TextByLanguage("Изображение \"Зелёный светодиод\"","Image \"Green Spot lamp\""),img_array_spot_green); engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_red",TextByLanguage("Изображение \"Красный светодиод\"","Image \"Red Spot lamp\""),img_array_spot_red); //--- Pass all existing collections to the trading class engine.TradingOnInit(); //--- Set synchronous passing of orders for all used symbols engine.TradingSetAsyncMode(); //--- Set standard sounds for trading objects of all used symbols engine.SetSoundsStandart(); //--- Check playing a standard sound by macro substitution and a custom sound by description engine.PlaySoundByDescription(SND_OK); Sleep(600); engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","Falling coin 2")); //--- Set controlled values for symbols //--- Get the list of all collection symbols CArrayObj *list=engine.GetListAllUsedSymbols(); if(list!=NULL && list.Total()!=0) { //--- In a loop by the list, set the necessary values for tracked symbol properties //--- By default, the LONG_MAX value is set to all properties, which means "Do not track this property" //--- It can be enabled or disabled (by setting the value less than LONG_MAX or vice versa - set the LONG_MAX value) at any time and anywhere in the program for(int i=0;i<list.Total();i++) { CSymbol* symbol=list.At(i); if(symbol==NULL) continue; //--- Set control of the symbol price increase by 100 points symbol.SetControlBidInc(100*symbol.Point()); //--- Set control of the symbol price decrease by 100 points symbol.SetControlBidDec(100*symbol.Point()); //--- Set control of the symbol spread increase by 40 points symbol.SetControlSpreadInc(40); //--- Set control of the symbol spread decrease by 40 points symbol.SetControlSpreadDec(40); //--- Set control of the current spread by the value of 40 points symbol.SetControlSpreadLevel(40); } } //--- Set controlled values for the current account CAccount* account=engine.GetAccountCurrent(); if(account!=NULL) { //--- Set control of the profit increase to 10 account.SetControlledValueINC(ACCOUNT_PROP_PROFIT,10.0); //--- Set control of the funds increase to 15 account.SetControlledValueINC(ACCOUNT_PROP_EQUITY,15.0); //--- Set profit control level to 20 account.SetControlledValueLEVEL(ACCOUNT_PROP_PROFIT,20.0); } //--- Check and remove remaining EA graphical objects if(IsPresentObects(prefix)) ObjectsDeleteAll(0,prefix); //--- Create the button panel if(!CreateButtons(InpButtShiftX,InpButtShiftY)) return INIT_FAILED; //--- Set trailing activation button status ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
编译并启动 EA 之后,将播放标准的 “ok.wav” 声音。 在 1/6 秒内,接着按 “Falling coin 2” 说明播放自定义声音。
若要验证交易限制检查方法的操作,我们需要人为地创建它们。
例如:
- 禁用 Internet 访问(模拟交易服务器断连),
- 在 EA 设置中禁用自动交易(按 F7 并在 EA 设置窗口的 “常用” 标签中取消勾选 “允许自动交易”),
- 在终端中禁用自动交易(自动交易按钮)。
单击 EA 交易面板中的开仓按钮。 以下条目出现在日志中:
2019.09.26 15:07:55.582 CTrading::OpenBuy: Request rejected before being sent to server due to: 2019.09.26 15:07:55.582 1. No permission to conduct trading operations in terminal ("AutoTrading" button disabled) 2019.09.26 15:07:55.582 2. No connection to trade server 2019.09.26 15:07:55.582 3. EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")
我们来一一消除这些限制。
启用 Internet 连接后,尝试开仓时我们会收到以下消息:
2019.09.26 15:10:36.766 CTrading::OpenBuy: Request rejected before being sent to server due to: 2019.09.26 15:10:36.766 1. No permission to conduct trading operations in terminal ("AutoTrading" button disabled) 2019.09.26 15:10:36.766 2. EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")
在终端上启用自动交易,单击自动交易按钮。 尝试开仓时,我们获得以下消息:
2019.09.26 15:13:03.424 CTrading::OpenBuy: Request rejected before being sent to server due to: 2019.09.26 15:13:03.424 EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")
按 F7 并在其设置里允许 EA 进行交易。 当尝试开仓时,我们终于成功了:
2019.09.26 15:14:32.619 - Position is open: 2019.09.26 11:14:32.711 - 2019.09.26 15:14:32.619 EURUSD Opened 0.10 Buy #455179802 [0.10 Market-order Buy #455179802] at price 1.09441, Magic number 123
其他限制可以在测试器或模拟帐户中测试,激活其中一个限制并创建一种情况来进行检查,例如,该帐户中挂单的最大数量限制。
下一步是什么?
在下一篇文章中,我们将实现交易订单参数有效性的验证。
文后附有当前版本含糊库的所有文件,以及测试 EA 文件,供您测试和下载。
请在评论中留下您的问题、意见和建议。
系列中的前几篇文章:
第一部分 概念,数据管理
第二部分 历史订单和成交集合
第三部分 在场订单和持仓集合,安排搜索
第四部分 交易事件, 概念
第五部分 交易事件类和集合。 将事件发送至程序
第六部分 净持帐户事件
第七部分 StopLimit 挂单激活事件,为订单和持仓修改事件准备功能
第八部分 订单和持仓修改事件
第九部分 与 MQL4 的兼容性 - 准备数据
第十部分 与 MQL4 的兼容性 - 开仓和激活挂单事件
第十一部分 与 MQL4 的兼容性 - 平仓事件
第十二部分 帐户对象类和帐户对象集合
第十三部分 账户对象事件
第十四部分 品种对象
第十五部份 品种对象集合
第十六部分 品种集合事件
第十七部分 函数库对象之间的交互
第十八部分 帐户与任意其他函数库对象的交互
第十九部分 函数库消息类
第二十部分 创建和存储程序资源
第二十一部分 交易类 - 基准跨平台交易对象
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/7258