
Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte XXII): Clases comerciales - Clase comercial principal, control de limitaciones
Contenido
- Concepto
- Ampliando la funcionalidad del objeto comercial básico
- La clase comercial
- Simulación
- ¿Qué es lo próximo?
En el artículo anterior, inauguramos un amplio apartado de la biblioteca dedicado a las funciones comerciales, y también creamos el objeto comercial básico del símbolo. Este objeto comercial obtiene en sus parámetros todas las propiedades de la solicitud comercial enviada al servidor, rellena la estructura de la solicitud comercial de acuerdo con el tipo de método de clase llamado (apertura de posición/colocación de orden pendiente/modificación/cierre/eliminación) y envía la orden comercial al servidor. Y nos veíamos condicionados por la idea de que, para enviar una orden comercial, al objeto comercial básico se le transmiten los valores correctos de las propiedades de la solicitud comercial. Pero, para poder usar plenamente el objeto comercial, primero necesitaremos comprobar las limitaciones existentes en cuanto a la ejecución de operaciones comerciales en el terminal, el programa, la cuenta y el símbolo. Y ya después de superar estas verificaciones iniciales, podemos comprobar que las propiedades de la solicitud comercial sean correctas.
Hoy comenzaremos a crear la clase comercial completa, y lo primero que haremos para implementar un trabajo completo y cómodo con la
funcionalidad de la biblioteca será comprobar las limitaciones a la hora de realizar operaciones comerciales.
Concepto
Ya tenemos un objeto comercial básico que se incluye entre los elementos del objeto de símbolo. Este ejecuta una tarea sencilla: rellena la estructura de la solicitud comercial de acuerdo con los parámetros transmitidos a uno de los métodos de la clase, y envía la orden comercial al servidor. En el presente artículo, antes de comenzar a crear una clase comercial plenamente funcional, completaremos la funcionalidad del objeto comercial básico, y también añadiremos la posibilidad de reproducir los resultados del envío de la orden comercial. Como resultado, podremos establecer cualquier sonido para reproducir los eventos comerciales. Además, podremos establecer para cada símbolo nuestros propios sonidos para cada uno de los eventos comerciales. Y además, como es natural, podremos establecer un conjunto general de sonidos para cada uno de los eventos iguales para todos los símbolos. En general, el objeto comercial básico ofrecerá amplias posibilidades para asignar sonidos a los eventos comerciales, tanto iguales para todos los símbolos y eventos, como individuales para un símbolo o evento particular.
A continuación, crearemos una clase comercial, a partir de la cual realizaremos en lo sucesivo todas las clases comerciales. Hoy, esta
clase dispondrá de una funcionalidad mínima: la comprobación del permiso de realización de operaciones comerciales y la llamada de los
métodos requeridos de los objetos comerciales básicos de los símbolos necesarios.
Ampliando la funcionalidad del objeto comercial básico
Bien, para asignar los sonidos a los eventos comerciales, necesitaremos macrosustituciones y enumeraciones. Abrimos el archivo Defines.mqh y le añadimos macrosustituciones que reemplacen los nombres de los archivos de sonido estándar:
//+------------------------------------------------------------------+ //| 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
De esta forma, resulta más cómodo indicar los nombres para establecer los archivos de los sonidos estándar, si queremos usarlos como archivos de sonido para reproducir los eventos comerciales.
El final del listado, en el bloque de datos para trabajar con las clases comerciales,
añadimos la
enumeración de los tipos de operaciones comerciales y la enumeración
de los modos de establecimiento de los sonidos:
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| 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 }; //+------------------------------------------------------------------+
A partir de la versión del terminal 2155, en MQL5 han aparecido nuevas propiedades para el símbolo y la cuenta:
- MQL5: Añadidos a la enumeración ENUM_SYMBOL_INFO_STRING
los siguientes valores:
- SYMBOL_CATEGORY — categoría del símbolo. Se usa para el marcado adicional de los instrumentos financieros. Por ejemplo, con su ayuda se pueden indicar los sectores del mercado a los que pertenece el símbolo: Agriculture, Oil & Gas, etcétera.
- SYMBOL_EXCHANGE — nombre de la bolsa o plataforma en la que se comercia con el símbolo.
- MQL5: Añadido el soporte de cierre de posiciones según la norma FIFO.
- Añadido a la enumeración ENUM_ACCOUNT_INFO_INTEGER el valor ACCOUNT_FIFO_CLOSE, señal de que las posicioens se pueden cerrar según la norma FIFO. Si el valor es igua a true, las posiciones de cada símbolo se pueden cerrar solo en el orden en el que han sido abiertas, primero la más antigua, después la que la sigue, etcétera. Si intentamos cerrar las posiciones en otro orden, obtendremos error. Para las cuentas sin registro de posiciones con cobertura (ACCOUNT_MARGIN_MODE!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING), la propiedad es siempre igual a false.
- Añadido un nuevo código de retorno del servidor TRADE_RETCODE_FIFO_CLOSE,
la solicitud ha sido rechazada, dado que para la cuenta comercial se ha establecido la norma "Las posiciones existentes solo se
pueden cerrar según la norma FIFO".
El cierre de posiciones se puede realizar de tres formas principales:
- Cierre a través del terminal de cliente: cierre manual de posiciones, con la ayuda de un robot comercial, a través del servicio "Señales", etcétera. Si el tráder intenta cerrar una posición sin atenerse a la norma FIFO, obtendrá el error correspondiente.
- El cierre al activarse un Stop Loss o Take Profit: etas órdenes se procesan en el lado del servidor, por consiguiente, también el cierre de posiciones en este caso es iniciado, no por el tráder (terminal), sino por le propio servidor. Si para la posición se ha activado un Stop Loss o Take Profit, y esta posición no se corresponde con la norma FIFO (existen posiciones anteriores del mismo instrumento), esta no se cerrará.
- Cierre por activación de Stop Out: estas operaciones también se procesan en el lado del servidor. En el modo habitual, cuando el cierre segíún la norma FIFO ha sido desactivado, al darse un Stop Out, las posiciones se cierran comenzando por la menos rentable. Si activamos esta opción, para las posiciones no rentables cerradas se comprobará adicionalmente su hora de cierre. El servidor determina las posiciones no rentables de cada símbolo, encuentra para cada símbolo la posición más antigua, y después, cierra de entre las posiciones encontradas aquella que tiene las mayores pérdidas.
Debido a ello, se han añadido nuevas propiedades al objeto de símbolo y al objeto de cuenta.
Hemos añadido una nueva propiedad al bloque de propiedades
de tipo entero de la cuenta, con lo que el número de propiedades de tipo entero ha aumentado a
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 //+------------------------------------------------------------------+
Asimismo, hemos añadido al bloque de posibles criterios de clasificación un nuevo criterio de clasificación según las propiedades de tipo entero:
//+------------------------------------------------------------------+ //| 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
Exactamente de la misma forma hemos añadido las propiedades del objeto de símbolo.
También hemos añadido dos nuevas propiedades al bloque de propiedades de tipo string , con lo que el número de estas ha aumentado a 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 //+------------------------------------------------------------------+
Asimismo, hemos añadido al bloque de posibles criterios de clasificación de los símbolos dos nuevos criterios de clasificación según las propiedades del símbolo:
//--- 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 }; //+------------------------------------------------------------------+
Además, hemos añadido algunas nuevas constantes de los índices de los mensajes de texto de la biblioteca para trabajar con las nuevas propiedades
de los objetos, clases y métodos.
Vamos a analizar las nuevas constantes añadidas en el
archivo 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 };
También vamos a añadir a las matrices de los mensajes de texto los textos que se corresponden con las constantes declaradas:
//+------------------------------------------------------------------+ //| 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" }, }; //+------------------------------------------------------------------+
Como ya sabemos, todas las manipulaciones realizadas sirven para añadir a la biblioteca sus nuevos mensajes, y para acceder rápidamente a un mensaje según su índice, registrado en la constante del mensaje.
Ahora, vamos a completar la clase de mensajes, ubicada en el archivo \MQL5\Include\DoEasy\Services\Message.mqh.
En la sección pública de la clase, añadidmos el método para establecer la reproducción de cualquier archivo de sonido:
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
Y lo implementamos fuera del cuerpo de la clase:
//+------------------------------------------------------------------+ //| Stop playing any sound | //+------------------------------------------------------------------+ bool CMessage::StopPlaySound(void) { bool res=::PlaySound(NULL); CMessage::m_global_error=(res ? ERR_SUCCESS : ::GetLastError()); return res; } //+------------------------------------------------------------------+
Aquí, todo es sencillo: al transmitir como nombre del archivo la constante NULL,
la función estándar
PlaySound() detiene la reproducción del archivo de sonido que
suena en ese momento.
Para que tengamos la posibilidad de reproducir los archivos estándar de sonido que se adjuntan con el terminal, deberemos indicar en el nombre
del archivo, o bien solo el nombre del archivo (para reproducir los sonidos de la ubicación estándar de sonidos:
carpeta_de_ubicación_del_terminal\Sounds), o bien el nombre del archivo con un prefijo donde se indiquen la barra oblicua inversa
doble y la carpeta en la que se encuentran los archivos de sonido no estándar.
Por eso, vamos a completar el método 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; } //+------------------------------------------------------------------+
Qué tenemos aquí:
Si hemos transmitido como nombre
del archivo el nombre de un archivo de sonido estándar, anotamos
en el prefijo del nombre del archivo una línea vacía.
De lo
contrario, anotamos en el prefijo una barra oblicua inversa doble y el nombre de
la subcarpeta de ubicación de los sonidos de la biblioteca.
A continuación, formamos el nombre del archivo a partir del prefijo
y el nombre transmitido al método.
Ahora, al
transmitir el nombre a la función PlaySound(), se seleccionará automáticamente el lugar de ubicación del archivo de sonido, o bien
el directorio estándar de sonidos, o bien la carpeta de ubicación de los archivos de sonido de la biblioteca; asimismo, tamién se
reproducirá el archivo correspondiente.
Dado que ahora tenemos un nuevo código de retorno del servidor comercial, cambiamos en el método de obtención de mensajes de la matriz de textos
según el indetificador
void CMessage::GetTextByID() los
límites de los códigos de retorno del servidor comercial a 1 más
(era 10044, ahora es 10045):
//--- 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] );
Estos son todos los cambios en la clase de los mensajes de la biblioteca.
A veces, necesitamos saber según el tipo de orden en qué dirección se abrirá la posición al activarse dicha orden. Por ejemplo, hemos colocado una orden pendiente con el tipo ORDER_TYPE_BUY_LIMIT. Al activarse, se colocará una orden de mercado ORDER_TYPE_BUY, que generará una transacción DEAL_ENTRY_IN con el tipo DEAL_TYPE_BUY, y ella, a su vez, generará una posición con el tipo POSITION_TYPE_BUY.
Así, para saber en qué dirección se abrirá una posición según el tipo de orden pendiente, tenemos que obtener el tipo de orden de mercado (para
este ejemplo) ORDER_TYPE_BUY.
Anteriormente, lo determinábamos con la ayuda de un operador ternario, comparándolo con el tipo de la orden pendiente. Pero podemos
hacerlo de una forma más simple: podemos simplemente tomar el resto de la división del tipo de orden comprobada por 2. Para las órdenes pares,
siempre se retornará el tipo 0 (ORDER_TYPE_BUY), y para las órdenes impares, el tipo 1 (ORDER_TYPE_SELL). Precisamente eso hemos hecho en
ciertas funciones y métodos.
En la clase de orden abstracta (\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; } //+------------------------------------------------------------------+
y en la biblioteca de funciones de servicio (\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); } //+------------------------------------------------------------------+
En este mismo archivo de funciones de servicio, la función que retorna el nombre de la orden ha sufrido ciertos cambios.
Se
ha añadido la bandera que indica la necesidad de mostrar la descripción, que
retorna el tipo de orden de mercado: dependiendo de esta bandera,
o bien se añade la descripción que especifica que se trata de una orden de mercado, o bien no. También se han añadido a los tipos de órdenes
pendientes
la descripciones del tipo de orden:
//+------------------------------------------------------------------+ //| 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) ); } //+------------------------------------------------------------------+
Debido a la aparición de nuevas propiedades para los objetos de símbolo y cuenta, debemos añadir estas propiedades a los mismos.
Abrimos el archivo \MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh y añadimos al mismo los valores necesarios.
En la sección protegida de la clase, añadimos los métodos para obtener las dos nuevas propiedades:
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:
En la sección pública de la clase, en el bloque de obtención simplificada de propiedades del objeto, añadimos la determinación de los dos nuevos métodos:
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); } //+------------------------------------------------------------------+
En el constructor parámetrico cerrado de la clase, añadimos la obtención de estas dos nuevas propiedades:
//--- 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
Vamos a implementar los métodos de obtención de las dos nuevas propiedades fuera del cuerpo de la clase.
//+------------------------------------------------------------------+ //| 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 ); } //+------------------------------------------------------------------+
Aquí: para MQL5, comprobamos el número de compilación del terminal, y si es
inferior a 2155, retornamos un mensaje informando de que esta propiedad no es
soportada en una versión inferior a 2155, de lo contrario, retornamos la nueva
propiedad
SYMBOL_EXCHANGE.
Para MQL4, retornamos de inmediato un mensaje informando de que la propiedad no es
soportada en MQL4.
Añadimos a la implementación del método que retorna la descripción de una propiedad de tipo string del símbolo el retorno de las descripciones de las dos nuevas propiedades:
//+------------------------------------------------------------------+ //| 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)+"\"") ) : "" ); } //+------------------------------------------------------------------+
Ahora, añadimos la nueva propiedad al objeto de cuenta en el archivo \MQL5\Include\DoEasy\Objects\Accounts\Account.mqh.
Asimismo, añadimos un nuevo campo a la estructura de las propiedades de la cuenta:
//+------------------------------------------------------------------+ //| 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
En la sección pública de la clase, en el bloque de los métodos de acceso simplificado a las propiedades del objeto, añadimos el
método que retorna la nueva propiedad:
//+------------------------------------------------------------------+ //| 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
En el constructor de la clase, añadimos el guardado de la nueva propiedad del objeto de cuenta:
//+------------------------------------------------------------------+ //| 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
Si el build del terminal es inferior a 2155, añadimos false, de lo contrario,
añadimos el valor de la propiedad de la cuenta
ACCOUNT_FIFO_CLOSE.
En el método de actualización de las propiedades de la cuenta Refresh(), también añadimos el guardado de esta propiedad:
//+------------------------------------------------------------------+ //| 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
En el método de creación del objeto de cuenta de la estructura escribimos
el rellenado de la nueva propiedad:
//+------------------------------------------------------------------+ //| 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
En el método que retorna la descripción de las propiedades del objeto de cuenta, añadimos la muestra de la descripción de la nueva propiedad:
//+------------------------------------------------------------------+ //| 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) : "" ); } //+------------------------------------------------------------------+
Debemos tener en cuenta que la introdución de la nueva propiedad en el objeto de cuenta ha invalidado los objetos de cuenta guardados
anteriormente en la carpeta general de todos los terminales; así, para que no haya errores a la hora de leerlos, deberemos eliminar por
nosotros mismos todos los archivos de las cuentas creados en la carpeta general de todos los terminales, en la subcarpeta
\DoEasy\Accounts\. En lo sucesivo, al cambiar de cuenta por una nueva, la biblioteca guardará por sí misma los objetos de cuenta en el
nuevo formato.
Para abrir la carpeta general de todos los terminales, debemos usar el comando del editor "Archivo --> Abrir carpeta general de
datos". En la ventana que se abrirá, debemos entrar en la carpeta Files, y una vez en ella, en la subcarpeta de la biblioteca
\DoEasy\Accounts\
Añadimos en la sección pública de la clase la determinación del
método que retorna el tamaño de margen necesario para abrir la posición indicada o colocar una orden pendiente:
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; //+------------------------------------------------------------------+
Y lo implementamos fuera del cuerpo de la clase:
//+------------------------------------------------------------------+ //| 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 } //+------------------------------------------------------------------+
Aquí: para MQL5, obtenemos con la ayuda de la función OrderCalcMargin()
el tamaño de margen necesario para abrir una nueva posición o colocar una orden pendiente. En este caso, además, si por algún motivo la
función ha retornado error, devolvemos el valor máximo
DBL_MAX
(este valor tiene la constante EMPTY_VALUE), de lo contrario, retornamos el tamaño
calculado del margen necesario.
Para MQL4, retornamos el margen libre disponible restándole los fondos que queden después de abrir la posición indicada o colocar una
orden pendiente, calculados con la ayuda de la función
AccountFreeMarginCheck().
Ya hemos terminado las mejoras en la clase del objeto de cuenta.
Ahora, vamos a mejorar la clase del objeto comercial básico. Para ello, deberemos añadirle la posibilidad de establecer cualquier sonido para
reproducir cualquier evento comercial.
Para guardar los datos, creamos en la sección privada de la clase una
estructura que guarde las banderas de uso de los sonidos y el nombre de los archivos para diferentes eventos:
//+------------------------------------------------------------------+ //| 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;
La estructua consta de dos estructuras incorporadas: SActionsFlags,
la estructura con los datos sobre las banderas y los nombres de los archivos, y
SActions m_data, la estructura que incluye los datos con el tipo
de estructura SActionsFlags para cada uno de los tipos de las posiciones y órdenes. De esta forma, siempre podremos recurrir al campo de la
estructura con las banderas y los nombres de los archivos para cada orden o posición, lo que nos ofrecerá mayor flexibilidad al establecer y
utilizar los sonidos para cualquier evento.
Asimismo,
declaramos en la sección privada de la clase la variable de miembro de clase que guarda la bandera de uso del objeto
comercial de los sonidos para los eventos comerciales:
bool m_use_sound; // The flag of using sounds of the object trading events
Esta bandera será el interruptor de activación/desactivación del uso de sonidos para todos los eventos comerciales del objeto de símbolo.
Con la ayuda de esta bandera, podremos activar/desactivar el uso de sonidos para los eventos comerciales de cada símbolo de una sola vez.
En la sección pública de la clase, declaramos todos los métodos necesarios para establecer y obtener las banderas de uso de sonidos y los nombres de los archivos de sonido para todos los eventos comerciales del objeto comercial básico del símbolo:
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
En el constructor de la clase, reseteamos la bandera general
e inicializamos las banderas de uso de sonidos y los archivos de sonido en los valores por
defecto como la prohibición del uso de sonidos y los nombres vacíos de los archivos:
//+------------------------------------------------------------------+ //| 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(); } //+------------------------------------------------------------------+
Vamos a implementar fuera del cuerpo de la clase el método para inicializar las banderas de uso de sonidos y establecer los nombres de los archivos de sonido.
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Transmitimos al método la bandera de uso de los sonidos de los eventos del
objeto comercial, del nombre de los archivos del sonido de apertura,
de cierre, de
modificación del StopLoss y del TakeProfit, del
precio de colocación de una orden y el sonido de error. A
continuación, se rellenan los campos de las estructuras para cada evento comercial para cada tipo de orden enviado al servidor con los
valores transmitidos.
La bandera de uso de sonidos y el nombre del archivo de sonido aquí se establecen como uno solo para todos los eventos comerciales enumerados,
mientras que para los eventos comerciales, el sonido se establece individualmente para cada uno. Además, si así lo queremos, podremos
establecer nuestro propio sonido para los sonidos de error de eventos concretos con la ayuda de los métodos declarados anteriormente, al
igual que se establece individualmente la bandera de uso de un sonido para cada evento comercial del objeto. Por defecto, se establecen la
prohibición del uso de sonidos y los nombres vacíos de los archivos.
Asimismo, se ha previsto un método que permite establecer sonidos estándar simultáneamente para todos los eventos comerciales del objeto, y también permite los mismos para cada evento comercial:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Vamos a implementar fuera del cuerpo de la clase los métodos para reproducir los sonidos y establecer las banderas y sonidos para un tipo concreto de evento comercial.
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Aquí todo es igual para todos los métodos, y todo resulta comprensible a primera vista: transmitimos al método en cuyo nombre está presente el tipo de evento comercial el tipo de orden (para las posiciones, el tipo de orden de mercado) cuyo evento se debe establecer, retornar o reproducir. Y a continuación, partiendo del tipo de posición/orden, se establece/retorna/reproduce el sonido del evento comercial dado.
Con esto, podemos considerar terminadas las mejoras del objeto comercial del símbolo, por lo que vamos a proceder a a crear la clase comercial principal.
Debemos destacar que, para que la clase comercial funcione correctamente, tenemos que transmitir a la misma los punteros a las colecciones creadas anteriormente. Para ello, añadiremos en cada clase de colección un método que retorna el puntero al objeto de colección:
Para el objeto de colección histórica:
public: //--- Return itself CHistoryCollection *GetObject(void) { return &this; }
Para el objeto de colección de mercado:
public: //--- Return itself CMarketCollection *GetObject(void) { return &this; }
Para la colección de símbolos:
public: //--- Return itself CSymbolsCollection *GetObject(void) { return &this; }
La clase comercial que hemos creado ofrecerá acceso centralizado a las operaciones comerciales. En ella se acumularán todas las
comprobaciones antes del envío de la orden comercial, el procesamiento de las respuestas del servidor comercial y la toma de decisiones
sobre las acciones posteriores, dependiendo de la respuesta del servidor comercial y los ajustes del comportamiento de los métodos
comerciales de la clase.
Hoy vamos a crear una nueva clase, que desarrollaremos posteriormente. Mientras tanto, nos ocuparemos de la comprobación de las
limitaciones para el comercio en la parte del programa, el terminal, la cuenta y el símbolo.
La clase comercial
En la carpeta principal de la biblioteca \MQL5\Include\DoEasy\, creamos la nueva claseCTrading en el
archivo
Trading.mqh.
Puesto que, para que la clase funcione, necesitaremos las listas de
algunas colecciones que hemos creado anteriormente, y que para guardar los errores al realizar la comprobación de
los permisos necesitaremos
el
objeto de
matriz dinámica de las variables del tipo int o uint de la biblioteca estándar,
incluiremos directamente estos en el
archivo de clase:
//+------------------------------------------------------------------+ //| Trading.mqh | //| Copyright 2019, MetaQuotes Software Corp. | //| https://mql5.com/ru/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "https://mql5.com/ru/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 | //+------------------------------------------------------------------+
Vamos a echar un vistazo al listado completo, y luego analizaremos sus componentes:
//+------------------------------------------------------------------+ //| 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); }; //+------------------------------------------------------------------+
Todos los métodos de la clase disponen de comentarios aclarativos, por lo que estos seguramente no requerirán de explicaciones adicionales.
Los métodos comerciales de la clase tienen prácticamente la misma signatura que los métodos del objeto comercial básico del símbolo. La
únicas diferencias son: la presencia de la denominación del símbolo en el que se debe realizar la operación comercial, los métodos de
apertura de posición y la colocación de órdenes pendientes.
Vamos a ver los métodos de implementación de la clase.
Puesto que al realizar una comprobación pueden existir varias limitaciones al mismo tiempo, para representarlas todas, deberemos ubicar el
código de cada error en una lista, y a continuación, después de finalizar la comprobación de todas las condiciones necesarias, mostrar la
lista de limitaciones detectadas. Para no ubicar dos veces en la lista un mismo valor de limitación detectado en distintos lugares del
código comprobado, deberemos comprobar si dicha limitación se encuentra en la lista, y añadirla solo si no está en la misma. En este caso,
cada tipo de limitación se encontrará solo una vez en la lista.
Para comprobar la presencia de un tipo de limitación en la lista y añadirlo a la misma, se ha creado el método:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Transmitimos al método el código del error que constituye el
motivo de la limitación del trading.
Asignamos a la lista la bandera de lista clasificada, comprobamos
la ausencia de dicho código en la lista y, si la comprobación ha tenido
éxito, retornamos el código a la lista
con el método Add().
Si el código ya se encuentra en la lista,
retornamos false.
Como los objetos comerciales pertenecen a un símbolo, y cada símbolo tiene su propio objeto comercial (y muchos métodos comerciales trabajan
con el ticket de una orden o posición), vamos a necesitar determinar según el ticket el símbolo en el que existe tal posición u orden.
Para ello, existen los métodos que retornan un objeto de símbolo según el ticket de la posición:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
y según el ticket de la orden:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Estos dos métodos son prácticamente idénticos. Conla diferencia de que en el primero buscamos una posición según el ticket, y en el segundo, una orden. Transmitimos al método el ticket de la posición u orden buscada y la denominación del método desde el que se ha llamado este método, para que, si se da algún error, podamos imprimir en el diario el nombre del método desde el que se ha llamado este método, y es que si imprimimos el nombre de dicho método auxiliar, esto no nos proporcionará ninguna información para determinar el lugar en el que ha sucedido el desajuste (necesitamos indicar desde qué método se ha llamado la búsqueda del objeto de símbolo).
Para que los métodos de clase funcionen, necesitamos obtener el objeto
comercial del símbolo según el ticket de la posición, según el ticket de la
orden o según el nombre del símbolo:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Los tres métodos auxiliares retornan el objeto comercial para el posterior trabajo con él. Todas las acciones se comentan en los listados de los métodos.
Para comprobar algunas limitaciones y tomar decisiones comerciales, vamos a necesitar el valor del número de posiciones abiertas y órdenes
colocadas, tanto en una misma dirección, como en todas.
Método que retorna el número de posiciones abiertas en la cuenta:
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+
Aquí: obtenemos la lista con todas las posiciones abiertas
y órdenes colocadas,
y filtramos la lista según
el estado de la orden "posición de mercado".
Retornamos
el número de objetos en la lista obtenida. Si no hemos logrado obtener la
lista, retornamos cero.
Método que retorna el número de posiciones de compra abiertas en la cuenta:
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+
Aquí: obtenemos la lista con todas las posiciones abiertas
y órdenes colocadas,
y
filtramos la lista según el estado de la orden "posición de mercado".
La lista obtenida la filtramos según el tipo de posición de compra.
Retornamos
el número de objetos en la lista obtenida. Si no hemos logrado obtener la
lista, retornamos cero.
Método que retorna el número de posiciones de venta abiertas en la cuenta:
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+
Aquí: obtenemos la lista con todas las posiciones abiertas
y órdenes colocadas,
y
filtramos la lista según el estado de la orden "posición de mercado".
La lista obtenida la filtramos según el tipo de posición de venta.
Retornamos
el número de objetos en la lista obtenida. Si no hemos logrado obtener la
lista, retornamos cero.
Método para obtener el número total de órdenes pendientes, órdenes de compra y órdenes de venta en la cuenta:
//+------------------------------------------------------------------+ //| 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()); } //+------------------------------------------------------------------+
Estos tres métodos auxiliares son idénticos a los tres métodos analizados anteriormente. La única diferencia es que filtraremos
la lista según el estado "orden pendiente activa" y según la dirección del
tipo de orden de compra o venta.
Asimismo, para determinar ciertas limitaciones, necesitaremos conocer el volumen total de posiciones abiertas y órdenes pendientes colocadas.
Método que retorna el volumen total de las posiciones de compra:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Aquí: obtenemos la lista con todas las posiciones abiertas y órdenes pendientes,
y filtramos la
lista según el estado de la orden "posición de mercado".
La
lista obtenida la filtramos según el tipo de posición de compra.
Si
la lista está vacía, retornamos cero.
Obtenemos
en un ciclo por la lista conseguida el siguiente objeto de orden
y añadimos su volumen al valor de la variable vol.
Al finalizar el ciclo,
retornamos el valor obtenido a la variable vol.
Método que retorna el volumen total de las posiciones de venta:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
El método es idéntico al anterior, con la excepción del filtrado, realizado según el tipo de posición de venta.
Métodos que retornan el volumen total de las órdenes pendientes colocadas de compra y de venta:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Los métodos son idénticos a los métodos de volumen total de posiciones que hemos analizado. Pero las
listas las filtraremos según el tipo "orden pendiente de mercado" y según
la dirección de la orden, o bien de compra, o bien de venta.
Método que retorna la dirección de una orden según el tipo de operación comercial:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Si al método se ha transmitido el modo de operación comercial "cierre por opuesta" o "modificación", retornamos -1, de lo contrario, retornamos el resto de la división del valor del tipo de la operación comercial por 2, lo que nos dará como resultado la dirección, o bien 0 (ORDER_TYPE_BUY), o bien 1 (ORDER_TYPE_SELL).
Método para comprobar la existencia de una posición según el ticket:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Aquí: transmitimos al método el ticket de la posición comprobada y la denominacion de la fuente.
Obtenemos
la lista con todas las posiciones abiertas y órdenes colocadas,
y
filtramos la lista según el estado de la orden "posición de mercado".
Asignamos a la lista la bandera de clasifición según el ticket.
Filtramos la lista obtenida según el ticket transmitido con el parámetro de
entrada.
Si la lista contiene un objeto (posición con el ticket
buscado), retornamos true.
De lo contrario, informamos
de la ausencia de posición y retornamos
false.
Método para comprobar la existencia de una orden pendiente según el ticket:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
El método es idéntico al anteriormente analizado, con la excepción de que la
lista se filtra según el estado "orden pendiente de mercado".
Método que establece para un objeto comercial el sonido indicado:
//+------------------------------------------------------------------+ //| 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; } } //+------------------------------------------------------------------+
Transmitimos al método el modo de establecimiento del sonido
(a qué evento comercial pertenecerá el sonido), el tipo de orden del evento
comercial para el cual se establece el sonido, la denominación del
archivo de sonido (el sonido que se asignará al evento comercial de una orden o posición) y el
puntero al objeto comercial en el que se debe establecer el sonido (para qué símbolo establecemos nuestros propios sonidos de los
eventos comerciales).
Dependiendo del modo transmitido al método, se llaman los
métodos existentes de establecimiento de sonidos para el objeto comercial.
Los métodos para establecer los parámetros de los objetos comerciales de los símbolos, ya analizados en
el artículo anterior e implementados temporalmente en la clase del objeto básico de la biblioteca 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);
han sido ahora trasladados a la clase comercial y reelaborados en la clase CEngine (simplemente llaman a estos métodos, ubicados aquí). Estos métodos ya los hemos estudiado antes, por lo que no vamos a regresar a ellos: el lector podrá ver su implementación en los archivos adjuntos al final del artículo.
Método para asignar sonidos estándar a un objeto comercial:
//+------------------------------------------------------------------+ //| 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(); } } //+------------------------------------------------------------------+
Método que asigna a un objeto comercial el sonido de un evento comercial establecido para la orden indicada:
//+------------------------------------------------------------------+ //| 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); } } //+------------------------------------------------------------------+
En ambos métodos, todas las acciones han sido descritas en los comentarios al código.
Hoy estamos creando para las operaciones comerciales métodos de comprobación primaria de las limitaciones del comercio. ¿Qué podemos
incluir en esta categoría? La comprobación de fondos suficientes para realizar operaciones comerciales, ya que si no hay fondos
suficientes, carece de sentido tratar de enviar una solicitud. Este tipo de limitación requiere tiempo para su eliminación, debemos,
o bien esperar a que aumenten los fondos libres de forma natural, planeando el cierre de posiciones según el sistema comercial y
obteniendo beneficios (pérdidas), con la consecuente liberación de los fondos reservados necesarios para mantener la posición
abierta; o bien cerrar forzosamente una posición no rentable para recuperar solo los fondos reservados; o bien ingresar fondos en la
cuenta. Por el momento, aquí será más fácil retornar la bandera de imposibilidad de ejecutar la solicitud comercial.
También existen otras limitaciones para el comercio: la prohibición del autotrading en el terminal, la prohibición del
autotrading para el asesor en sus ajustes, la prohibición del autotrading en el lado del servidor o para un símbolo concreto, y otros
factores adicionales.
Todo esto vamos a implementar hoy para la clase comercial.
Método que comprueba que haya fondos suficientes para realizar una operación comercial:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+
Método que comprueba las limitaciones para realizar operaciones comerciales
:
//+------------------------------------------------------------------+ //| 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; } //+------------------------------------------------------------------+El método es bastante voluminoso, pero aquí todo es muy monótono: comprobamos las propiedades del programa, el terminal, la cuenta o el símbolo según el cual son posibles las limitaciones, y si existe una limitación, añadimos el código de la limitación encontrada a la lista, agregando false a la bandera del resultado. Después de realizar todas las comprobaciones, si en la variable que contiene el resultado tenemos false, mostraremos el encabezado de la lista de limitaciones encontradas, y en un ciclo por la lista de códigos de limitaciones, mostraremos bajo el encabezado todas las limitaciones encontradas para el comercio; de lo contrario, si en la variable que guarda el resultado de las comprobaciones se contiene true, con el que se ha inicializado al principio esta variable, significará que todas las comprobaciones han sido superadas, y retornaremos true.
En esta versión de la clase comercial, nos limitaremos a lo expuesto. Posteriormente, al crear los métodos de procesamiento de errores,
todas las acciones en cuanto a la reacción a las limitaciones y errores serán procesadas en esta clase.
Métodos comerciales de la clase:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
En cuanto a los métodos comerciales — el envío de solicitudes comerciales al servidor —, ya los analizamos en
el artículo anterior, al crear el objeto comercial básico. Aquí mismo, transmitimos a los métodos con signatura similar los parámetros
de la solicitud comercial, comprobamos las limitaciones para el comercio (que hemos analizado antes), y llamamos el método
correspondiente del objeto comercial básico del símbolo. El resultado del funcionamiento del método se retorna al programa.
Por ahora, en esta etapa, encontramos solo las comprobaciones que se realizan antes de enviar la solicitud comercial. Posteriormente,
como es natural, las ampliaremos. Y es que ahora necesitamos comprobar que los parámetros de la solicitud comercial sean correctos, y
también procesar los mismos. En este momento, ya se supone que todos los parámetros son correctos.
La clase comercial en su implementación actual (y con la funconalidad planeada), está lista.
Ahora,
debemos obtener para la misma acceso a su objeto básico de la biblioteca
CEngine, y ya a través de él trabajar con los métodos comerciales de clase.
Abrimos el archivo \MQL5\Include\DoEasy\Engine.mqh y realizamos los cambios necesarios.
En primer lugar, incluimos en este el archivo de la clase comercial:
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2019, MetaQuotes Software Corp. | //| https://mql5.com/ru/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, MetaQuotes Software Corp." #property link "https://mql5.com/ru/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" //+------------------------------------------------------------------+
Y declaramos en la sección privada de la clase el objeto de la clase comercial:
//+------------------------------------------------------------------+ //| 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
Los métodos
//--- 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);
los renombramos como
//--- 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);
Simplemente para que su nombre indique la pertenencia a la clase comercial.
Declaramos en la sección pública de la clase los métodos para establecer
los sonidos estándar, los sonidos para el tipo indicado de
posición/orden y el evento comercial, y el método para
enviar a la clase comercial los punteros a todas las listas de colección necesarias para su funcionamiento; , asimismo, declaramos
el método para reproducir el sonido según su descripción:
//--- 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()); }
Los tres métodos simplemente llaman a los métodos homónimos de la clase comercial. El método de reproducción del sonido según su descripción lo veremos más abajo:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Anteriormente, creamos objetos de recurso en los que
podíamos guardar archivos de sonido y archivos de imagen. Para cada recurso, implementamos la posibilidad de añadir una descripción. De
esta forma, nos resultará sencillo indicar qué archivo de sonido debemos reproducir. Por ejemplo, resulta bastante más sencillo recordar
nuestra propia descripción que recordar su nombre. Mientras que el nombre de un archivo parece impersonal, supongamos sound_01.wav, su
descripción puede ser cualquiera que deseemos, por ejemplo "sonido de apertura de una posición Buy en EURUSD".
Este método nos permite precisamente indicar en sus parámetros la descripción de archivo necesaria. El método encontrará el objeto de
recurso con esta descripción y lo reproducirá. De forma opcional, el método tiene la posibilidad de reproducir sonidos estándar según las
macrosustituciones de sus nombres que hayamos creado en Defines.mqh, así como cualquier archivo de sonido desconocido, basta con
transmitir su nombre como descripción. Lo importante es que ese archivo se encuentre en el sandbox del terminal, que tenga la extensión wav y
que en nombre contenga la ruta correcta hacia el mismo.
Los métodos comerciales que en el artículo anterior ubicamos en la clase CEngine, así como los métodos que establecen los parámetros del
objeto comercial, también ubicados de forma temporal en CEngine, ahora han sufrido ciertos cambios: todos estos métodos, su
implementación, han sido trasladados a la clase comercial,
mientras que desde los métodos de la clase CEngine simplemente se llaman los métodos correspondientes de la clase comercial:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Con ello, podemos dar por finalizada la mejora de la clase CEngine, solo nos queda comprobar cómo funciona ahora todo esto.
Simulación
Para la simulación, vamos a tomar el asesor del artículo anterior y guardarlo en la nueva carpeta \MQL5\Experts\TestDoEasy\Part22\, con el nuevo nombre TestDoEasyPart22.mq5.
En el diario del manejador OnInit() del asesor anterior, se mostraba mucha información textual de comprobación. Ahora que ya no la necesitamos, vamos a eliminar todos los Print() innecesarios y añadir la inicialización de la clase comercial y la comprobación del sonido estándar según la macrosustitución y del sonido de usuario según su descripción:
//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+
Después de compilar e iniciar el asesor, en primer lugar se reproducirá el sonido estándar "ok.wav", y tras 1/6 segundos, el sonido de usuario con la descripción "Sonido de moneda al caer 2".
Para verificar el funcionamiento de los métodos de comprobación de las limitaciones comerciales, deberemos crearlos artificialmente.
Por ejemplo:
- desconectamos internet (emulamos una pérdida de conexión con el servidor comercial),
- en los ajustes del asesor, le prohibimos comerciar (pulsamos F7 y en la ventana que se abrirá para el ajuste del asesor, en la pestaña
"General", quitamos el aspa "Permitir comerciar al asesor"),
- prohibimos el autotrading en el terminal (desactivamos el botón "Autotrading")
Y probamos a pulsar el botón de apertura de posición en el panel comercial del asesor. Como resultado, obtenemos la siguiente entrada en el diario:
2019.09.26 15:07:55.582 CTrading::OpenBuy: The request was rejected before being sent to the server due to: 2019.09.26 15:07:55.582 1. There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.09.26 15:07:55.582 2. No connection to the trading server 2019.09.26 15:07:55.582 3. EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")
Vamos quitando las limitaciones por turno.
Conectamos internet, y al intentar abrir una posición, obtenemos:
2019.09.26 15:10:36.766 CTrading::OpenBuy: The request was rejected before being sent to the server due to: 2019.09.26 15:10:36.766 1. There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.09.26 15:10:36.766 2. EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")
Permitimos el autotrading en el terminal pulsando el botón Autotrading, y al intentar abrir una posición, obtenemos:
2019.09.26 15:13:03.424 CTrading::OpenBuy: The request was rejected before being sent to the server due to: 2019.09.26 15:13:03.424 EA does not have permission to conduct trading operations (F7 --> Common --> "Allow Automatic Trading")
Pulsamos F7, y en los ajustes del asesor permitimos a este que comercie. Si intentamos abrir una posición, obtendremos la posición abierta.
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
El resto de las limitaciones se pueden comprobar en el simulador de estrategias o en una cuenta demo, creando una situación en la que se active
una de las limitaciones, por ejemplo, la limitación del número máximo de órdenes pendientes en la cuenta.
¿Qué es lo próximo?
En el próximo artículo, crearemos el control de la corrección de los parámetros de las órdenes comerciales.
Más abajo se adjuntan todos los archivos de la versión actual de la biblioteca y los archivos del asesor de prueba. El lector podrá
descargar y poner a prueba todo por sí mismo.
Si tiene cualquier duda, observación o sugerencia, podrá formularla en los comentarios al artículo.
Artículos de esta serie:
Parte 1. Concepto, organización de datos
Parte
2. Colección de órdenes y transacciones históricas
Parte 3. Colección de órdenes y
posiciones de mercado, organización de la búsqueda
Parte 4. Eventos comerciales.
Concepto
Parte 5. Clases y concepto de los eventos comerciales. Envío de eventos al
programa
Parte 6. Eventos en las cuentas de compensación
Parte
7. Eventos de activación de órdenes StopLimit, preparación de la funcionalidad para los eventos de modificación de órdenes y posiciones
Parte 8. Eventos de modificación de órdenes y posiciones
Parte
9. Compatibilidad con MQL4 - Preparando los datos
Parte 10. Compatibilidad con
MQL4 - Eventos de apertura de posición y activación de órdenes pendientes
Parte 11.
Compatibilidad con MQL4 - Eventos de cierre de posición
Parte 12. Implementando la
clase de objeto "cuenta" y la colección de objetos de cuenta
Parte 13. Eventos del
objeto "cuenta"
Parte 14. El objeto "Símbolo"
Parte
15. Colección de objetos de símbolo
Parte 16. Eventos de la colección de símbolos
Parte 17. Interactividad de los objetos de la biblioteca
Parte
18. Interactividad del objeto de cuenta con cualquier otro objeto de la biblioteca
Parte
19. Clase de mensajes de la biblioteca
Parte 20. Creación y guardado de los recursos
del programa
Parte 21. Clases comerciales - El objeto comercial multiplataforma
básico
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/7258





- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso