
Торговый инструментарий MQL5 (Часть 3): Разработка EX5-библиотеки для управления отложенными ордерами
Введение
В первой и второй статьях мы познакомились с разработкой и программированием EX5-библиотек с нуля, а также с тем, как создавать подробную документацию, которая поможет конечным пользователям внедрять их в свои проекты MQL5. Также мы получили практическую пошаговую демонстрацию того, как импортировать и внедрять их в различные приложения MQL5.
В этой статье мы разработаем комплексную EX5-библиотеку для управления отложенными ордерами (Pending Orders Management EX5 library) и создадим панель графического пользовательского интерфейса (GUI), чтобы на практическом примере продемонстрировать, как импортировать и внедрить библиотеку. Библиотека будет использовать только стандартные функции MQL5 для открытия, изменения и удаления различных типов отложенных ордеров. Она послужит ценным учебным пособием для новичков в MQL5-программировании, желающих научиться писать простые и сложные модули управления отложенными ордерами. Вы также узнаете, как сортировать отложенные ордера по различным категориям.
Функции, которые мы создадим ниже, будут экспортированы и скомпилированы в EX5-библиотеку, что сделает ее ценным активом, который значительно сократит время разработки будущих MQL5-проектов. Просто импортировав EX5-библиотеку управления отложенными ордерами, вы сможете реализовать эти функции, тем самым значительно сократив как кодовую базу, так и общий процесс разработки.
Создаем файл исходного кода EX5-библиотеки (.mq5)
Откройте MetaEditor IDE и запустите Мастер MQL с помощью команды меню "Создать". Необходимо создать файл исходного кода библиотеки. Назовем его PendingOrdersManager.mq5. Этот файл будет содержать основные функции для управления отложенными ордерами. Сохраним его в папке Libraries\Toolkit, которую мы создали в первой статье. Это тот же каталог, в котором мы в прошлый раз сохранили EX5-библиотеку для управления позициями (Positions Manager EX5 library).
Если вам нужно освежить в памяти, как создать EX5-библиотеку, вернитесь к первой статье. Там мы подробно рассмотрели пошаговый процесс настройки структуры папок и создания библиотек. Такой подход не только поможет оптимизировать разработку, но и облегчит поддержку и повторное использование ваших библиотек в будущих MQL5-проектах.
Директивы препроцессора, глобальные переменные и импорт EX5-библиотеки для управления позициями
Начнем с определения всех директив препроцессора, глобальных переменных, импорта библиотеки и торговых структур в нашем только что созданном файле исходного кода библиотеки PendingOrdersManager.mq5. Это гарантирует их доступность во всей нашей библиотеке управления отложенными ордерами и возможность их повторного использования в различных функциях по мере необходимости.
Начнем с определения макроса препроцессора, используя #define для создания константы, представляющей пустую строку. Эта константа, названная ALL_SYMBOLS, будет действовать как заполнитель в функциях управления отложенными ордерами, которым требуется строка символов в качестве входного параметра. При передаче этой пустой строки функции будут интерпретировать ее как команду применить указанное действие ко всем доступным символам, а не к одному.
Этот подход прост, но очень эффективен, особенно при управлении несколькими инструментами, поскольку он оптимизирует процесс обработки отложенных ордеров по разным символам. Для реализации определим константу ALL_SYMBOLS и поместим ее непосредственно под директивами #property в вашем коде.
#define ALL_SYMBOLS "" //-- Used as a function parameter to select all symbols
Нам также необходимо создать две дополнительные константы: одну для определения максимального количества повторных попыток отправки ордера на торговый сервер в случае неудачи, а другую для установки длительности задержки между повторными попытками. Это помогает предотвратить перегрузку торгового сервера быстрыми последовательными запросами. Назовем первую константу MAX_ORDER_RETRIES и установим ее значение на 600. Вторая константа - ORDER_RETRY_DELAY, равная 500 (миллисекунд).
Это означает, что если не возникнет критической ошибки, мы можем попытаться открыть, изменить или удалить ордер до 600 раз. После каждой попытки функция будет останавливаться на полсекунды (500 миллисекунд) прежде чем повторить попытку. Эта задержка гарантирует, что мы не перегрузим сервер и что ресурсы будут использоваться эффективно. Это также позволяет устранить любые задержки, такие как отсутствие активности на рынке или недоступность тиковых данных, до того, как будут исчерпаны все попытки повторения, что повышает вероятность успешного исполнения ордера.
#define MAX_ORDER_RETRIES 600 //-- Sets the order sending retry limit #define ORDER_RETRY_DELAYS 500//-- Sets the duration to pause before re-sending a failed order request in milliseconds
Далее добавим структуры данных MqlTradeRequest и MqlTradeResult. Эти структуры важны, так как они будут обрабатывать все коммуникации с торговым сервером при открытии, изменении и удалении различных отложенных ордеров. Структура tradeRequest будет отвечать за хранение сведений о торговых действиях, которые мы выполним, включая параметры ордера, такие как цена, стоп-лосс и тейк-профит. Структура tradeResult будет фиксировать и сохранять результат торговой операции, предоставляя нам обратную связь с сервером о том, был ли наш запрос успешным или возникла ошибка.
//-- Trade operations request and result data structures global variables MqlTradeRequest tradeRequest; MqlTradeResult tradeResult;
Чтобы отслеживать и хранить статус различных отложенных ордеров, нам необходимо создать несколько типов переменных, которые будут содержать информацию об этом статусе. Эти переменные статуса ордера будут объявлены как глобальные переменные, чтобы обеспечить их доступность из любой области действия нашей библиотеки, что позволит любой функции ссылаться на них и обновлять их по мере необходимости. Мы инициализируем эти переменные значениями по умолчанию при их объявлении, а затем обновим их точными данными в реальном времени в функции GetPendingOrdersData(...), которую мы разработаем далее в этой статье. Это гарантирует, что статус всех отложенных ордеров будет оставаться неизменным и точно обновляться на протяжении всего выполнения вызывающих функций.
//-- Pending orders status global variables //------------------------------------------------------------------------------------------------------------------- int accountBuyStopOrdersTotal = 0, accountSellStopOrdersTotal = 0, accountBuyLimitOrdersTotal = 0, accountSellLimitOrdersTotal = 0, symbolPendingOrdersTotal = 0, symbolBuyStopOrdersTotal = 0, symbolSellStopOrdersTotal = 0, symbolBuyLimitOrdersTotal = 0, symbolSellLimitOrdersTotal = 0, magicPendingOrdersTotal = 0, magicBuyStopOrdersTotal = 0, magicSellStopOrdersTotal = 0, magicBuyLimitOrdersTotal = 0, magicSellLimitOrdersTotal = 0; double accountPendingOrdersVolumeTotal = 0.0, accountBuyStopOrdersVolumeTotal = 0.0, accountSellStopOrdersVolumeTotal = 0.0, accountBuyLimitOrdersVolumeTotal = 0.0, accountSellLimitOrdersVolumeTotal = 0.0, symbolPendingOrdersVolumeTotal = 0.0, symbolBuyStopOrdersVolumeTotal = 0.0, symbolSellStopOrdersVolumeTotal = 0.0, symbolBuyLimitOrdersVolumeTotal = 0.0, symbolSellLimitOrdersVolumeTotal = 0.0, magicPendingOrdersVolumeTotal = 0.0, magicBuyStopOrdersVolumeTotal = 0.0, magicSellStopOrdersVolumeTotal = 0.0, magicBuyLimitOrdersVolumeTotal = 0.0, magicSellLimitOrdersVolumeTotal = 0.0;
При открытии, изменении или удалении ордеров часто возникают различные типы ошибок. Для эффективной обработки и устранения этих ошибок нам понадобится специальная функция, предназначенная для управления ими. Кроме того, нам необходима функция проверки критически важных торговых разрешений, например, имеет ли наш советник право на торговлю, включена ли в терминале алгоритмическая торговля или разрешил ли наш брокер алгоритмическую торговлю для данного счета.
К счастью, мы уже разработали подобные функции в библиотеке PositionsManager.ex5 из предыдущих статей. Вместо того, чтобы заново создавать эти функции, мы просто импортируем эту библиотеку, сделав эти функции обработки ошибок и проверки разрешений легкодоступными для использования в нашей библиотеке для управления отложенными ордерами. Импортируем функции ErrorAdvisor(...) и TradingIsAllowed().
//+----------------------------------------------------------------------------+ //| PositionsManager.ex5 imports | //+----------------------------------------------------------------------------+ #import "Toolkit/PositionsManager.ex5" //-- Opening import directive //-- Function descriptions for the imported function prototypes //-- Error Handling and Permission Status Functions bool ErrorAdvisor(string callingFunc, string symbol, int tradeServerErrorCode); bool TradingIsAllowed(); #import //--- Closing import directive
Функция PrintOrderDetails
Функция PrintOrderDetails(...) регистрирует подробную информацию о торговом запросе и ответе сервера в журнале советника в MetaTrader 5. Он принимает два строковых параметра: header, который содержит пользовательское сообщение, и symbol, который представляет собой обрабатываемый торговый символ или инструмент. Функция выводит подробный отчет, включающий основные сведения об ордере, такие как к символ, тип ордера, объем, цена, стоп-лосс, тейк-профит, комментарий, магическое число и любые отклонения. Кроме того, он регистрирует важную информацию о результате торговли, включая ответ сервера и любые ошибки выполнения. Основная цель функции — помочь в отладке и мониторинге торговых операций путем предоставления четкого, отформатированного обзора параметров и статуса каждого ордера.
void PrintOrderDetails(string header, string symbol) { string orderDescription; int symbolDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); //-- Print the order details orderDescription += "_______________________________________________________________________________________\r\n"; orderDescription += "--> " + tradeRequest.symbol + " " + EnumToString(tradeRequest.type) + " " + header + " <--\r\n"; orderDescription += "Volume: " + StringFormat("%d", tradeRequest.volume) + "\r\n"; orderDescription += "Price: " + DoubleToString(tradeRequest.price, symbolDigits) + "\r\n"; orderDescription += "Stop Loss: " + DoubleToString(tradeRequest.sl, symbolDigits) + "\r\n"; orderDescription += "Take Profit: " + DoubleToString(tradeRequest.tp, symbolDigits) + "\r\n"; orderDescription += "Comment: " + tradeRequest.comment + "\r\n"; orderDescription += "Magic Number: " + StringFormat("%d", tradeRequest.magic) + "\r\n"; orderDescription += "Order filling: " + EnumToString(tradeRequest.type_filling)+ "\r\n"; orderDescription += "Deviation points: " + StringFormat("%G", tradeRequest.deviation) + "\r\n"; orderDescription += "RETCODE: " + (string)(tradeResult.retcode) + "\r\n"; orderDescription += "Runtime Code: " + (string)(GetLastError()) + "\r\n"; orderDescription += "---"; Print(orderDescription); }
Функция OpenBuyLimit
Функция OpenBuyLimit(...) будет отвечать за размещение отложенных ордеров buy limit в терминале MetaTrader 5. Функция гарантирует выполнение всех необходимых условий перед отправкой запроса на ордер, а встроенная обработка ошибок позволяет устранить потенциальные проблемы. Она проверяет, что все параметры действительны и соответствуют требованиям брокера. Кроме того, она реализует цикл повторных попыток, что увеличивает вероятность успешного размещения ордера. Это делает функцию надежным и эффективным инструментом для управления отложенными ордерами. Обработка ошибок и возможности журналирования дополнительно помогают в выявлении и решении проблем, которые могут возникнуть в процессе размещения ордера. Функция возвращает булево значение true при успешном открытии ордера buy limit и false, если запрос не удался.
Что такое ордер Buy Limit?
Ордер Buy Limit (лимитный ордер на покупку) - это запрос на покупку по цене Ask, равной или ниже указанной цены входа. Цена входа по лимитному ордеру на покупку действительна только в том случае, если текущая рыночная цена выше цены входа. Этот тип ордера полезен, когда вы ожидаете, что цена символа упадет до желаемого вами уровня, а затем вырастет, что позволит вам получить прибыль от восходящего движения.
Начнем с определения функции, которая будет принимать семь параметров, каждый из которых играет определенную роль в процессе размещения лимитного ордера на покупку. Функция будет экспортируемой, что позволит осуществлять к ней внешний доступ в EX5-библиотеке. Параметры:
- magicNumber (unsigned long) - уникальный идентификатор сделки, используемый для различения ордеров, размещенных нашим советником, от других.
- symbol (string) - торговый инструмент или символ (например, EURUSD), на котором будет размещен ордер.
- entryPrice (double) - уровень срабатывания лимитного ордера на покупку. Это целевая цена, по которой вы хотите купить актив.
- lotSize (double) - объем или размер размещаемого ордера, показывающий (сколько лотов актива будет использовано в торговле).
- sl (int) - стоп-лосс в пипсах. Определяет максимальный убыток, который может понести сделка, прежде чем она будет автоматически закрыта.
- tp (int) - тейк-профит в пипсах. Уровень цен, при котором прибыль будет автоматически зафиксирована.
- orderComment (string) - комментарий или примечание, прилагаемое к ордеру для целей идентификации или отслеживания.
bool OpenBuyLimit(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment) export {
После определения функции и ее параметров первым шагом является проверка того, включена ли алгоритмическая торговля или торговля с использованием советника в MetaTrader 5. Если эта функция отключена, мы немедленно выйдем из функции, не допуская размещения ордера.
if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function }
Далее создадим переменные tpPrice и slPrice для сохранения значений тейк-профита и стоп-лосса, а затем для извлечения ключевой информации о торговом символе, например, количества знаков после запятой (digits), минимального стоп-уровня и спреда. Эти данные помогут нам гарантировать, что цена входа и параметры ордера установлены правильно для выбранного символа.
double tpPrice = 0.0, slPrice = 0.0; //-- Get some information about the orders symbol int symbolDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbolStopLevel = (int)SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(symbol, SYMBOL_SPREAD); //-- Save the order type enumeration ENUM_ORDER_TYPE orderType = ORDER_TYPE_BUY_LIMIT;
Прежде чем отправить ордер, нам необходимо проверить, действительна ли цена входа, убедившись, что она не находится слишком близко к рыночной цене и не ниже стоп-уровня брокера. Если цена недействительна, зафиксируем ошибку и выйдем из функции.
//-- check if the entry price is valid if( SymbolInfoDouble(symbol, SYMBOL_ASK) - (symbolStopLevel * symbolPoint) < entryPrice + (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't open a new ", EnumToString(orderType), ". (Reason --> INVALID ENTRY PRICE: ", DoubleToString(entryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid entry price, log the error, exit the function and return false }
Убедимся, что значения стоп-лосса (SL) и тейк-профита (TP) соответствуют минимальным требованиям брокера. При необходимости, прежде чем продолжить, скорректируем SL и TP для соответствия правилам.
//-- Check the validity of the sl and tp if(sl > 0 && sl < symbolStopLevel) { sl = symbolStopLevel; } if(tp > 0 && tp < symbolStopLevel) { tp = symbolStopLevel; } slPrice = (sl > 0) ? NormalizeDouble(entryPrice - sl * symbolPoint, symbolDigits) : 0; tpPrice = (tp > 0) ? NormalizeDouble(entryPrice + tp * symbolPoint, symbolDigits) : 0;
После того, как мы проверим цену и другие параметры, мы подготовим структуру tradeRequest с подробной информацией, такой как тип ордера, символ, цена, объем, стоп-лосс, тейк-профит и комментарий. Мы также обеспечим соответствие размера лота допустимым брокером лимитам и сбросим все предыдущие результаты торговли или ошибки.
//-- reset the the tradeRequest and tradeResult values by zeroing them ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the parameters to open a buy limit order tradeRequest.type = orderType; tradeRequest.action = TRADE_ACTION_PENDING; tradeRequest.magic = magicNumber; tradeRequest.symbol = symbol; tradeRequest.price = NormalizeDouble(entryPrice, symbolDigits); tradeRequest.tp = tpPrice; tradeRequest.sl = slPrice; tradeRequest.comment = orderComment; tradeRequest.deviation = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * 2; //-- Set and moderate the lot size or volume //-- Verify that volume is not less than allowed minimum lotSize = MathMax(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN)); //-- Verify that volume is not more than allowed maximum lotSize = MathMin(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX)); //-- Round down to nearest volume step lotSize = MathFloor(lotSize / SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)) * SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); tradeRequest.volume = lotSize; //--- Reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function ResetLastError();
Если запрос на ордера действителен, мы попытаемся отправить его на торговый сервер брокера. Если размещение ордера не удалось, мы повторим попытку отправки запроса на ордер до 600 раз с паузой в полсекунды (500 миллисекунд) перед повторной попыткой, предпринимая несколько попыток, чтобы убедиться в успешном размещении ордера. Этот механизм повторных попыток значительно увеличивает вероятность успешного открытия ордера, особенно в случаях временных проблем с сетью или сервером.
Если ордер успешно размещен, мы зафиксируем его данные и подтвердим, что торговый сервер обработал его. Если ордер не будет выполнен даже после нескольких попыток, мы используем функцию ErrorAdvisor(..), импортированную из библиотеки PositionsManager.ex5 для диагностики проблемы и возврата false, чтобы указать, что ордер не был размещен.
for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try opening the order until it is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Print the order details PrintOrderDetails("Sent OK", symbol); //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { Print( __FUNCTION__, ": CONFIRMED: Successfully openend a ", symbol, " ", EnumToString(orderType), " #", tradeResult.order, ", Price: ", tradeResult.price ); PrintFormat("retcode=%u deal=%I64u order=%I64u", tradeResult.retcode, tradeResult.deal, tradeResult.order); Print("_______________________________________________________________________________________"); return(true); //-- exit the function //break; //--- success - order placed ok. exit the for loop } } else //-- Order request failed { //-- Print the order details PrintOrderDetails("Sending Failed", symbol); //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, symbol, tradeResult.retcode) || IsStopped()) { Print( __FUNCTION__, ": ", symbol, " ERROR opening a ", EnumToString(orderType), " at: ", tradeRequest.price, ", Lot\\Vol: ", tradeRequest.volume ); Print("_______________________________________________________________________________________"); return(false); //-- exit the function //break; //-- exit the for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } }
Ниже приведен полный код функции со всеми сегментами в правильной последовательности. Убедитесь, что ваша функция OpenBuyLimit(...) содержит следующий код полностью.
bool OpenBuyLimit(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } double tpPrice = 0.0, slPrice = 0.0; //-- Get some information about the orders symbol int symbolDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbolStopLevel = (int)SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(symbol, SYMBOL_SPREAD); //-- Save the order type enumeration ENUM_ORDER_TYPE orderType = ORDER_TYPE_BUY_LIMIT; //-- check if the entry price is valid if( SymbolInfoDouble(symbol, SYMBOL_ASK) - (symbolStopLevel * symbolPoint) < entryPrice + (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't open a new ", EnumToString(orderType), ". (Reason --> INVALID ENTRY PRICE: ", DoubleToString(entryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid entry price, log the error, exit the function and return false } //-- Check the validity of the sl and tp if(sl > 0 && sl < symbolStopLevel) { sl = symbolStopLevel; } if(tp > 0 && tp < symbolStopLevel) { tp = symbolStopLevel; } slPrice = (sl > 0) ? NormalizeDouble(entryPrice - sl * symbolPoint, symbolDigits) : 0; tpPrice = (tp > 0) ? NormalizeDouble(entryPrice + tp * symbolPoint, symbolDigits) : 0; //-- reset the the tradeRequest and tradeResult values by zeroing them ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the parameters to open a buy limit order tradeRequest.type = orderType; tradeRequest.action = TRADE_ACTION_PENDING; tradeRequest.magic = magicNumber; tradeRequest.symbol = symbol; tradeRequest.price = NormalizeDouble(entryPrice, symbolDigits); tradeRequest.tp = tpPrice; tradeRequest.sl = slPrice; tradeRequest.comment = orderComment; tradeRequest.deviation = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * 2; //-- Set and moderate the lot size or volume //-- Verify that volume is not less than allowed minimum lotSize = MathMax(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN)); //-- Verify that volume is not more than allowed maximum lotSize = MathMin(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX)); //-- Round down to nearest volume step lotSize = MathFloor(lotSize / SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)) * SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); tradeRequest.volume = lotSize; //--- Reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function ResetLastError(); for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try opening the order until it is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Print the order details PrintOrderDetails("Sent OK", symbol); //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { Print( __FUNCTION__, ": CONFIRMED: Successfully openend a ", symbol, " ", EnumToString(orderType), " #", tradeResult.order, ", Price: ", tradeResult.price ); PrintFormat("retcode=%u deal=%I64u order=%I64u", tradeResult.retcode, tradeResult.deal, tradeResult.order); Print("_______________________________________________________________________________________"); return(true); //-- exit the function //break; //--- success - order placed ok. exit the for loop } } else //-- Order request failed { //-- Print the order details PrintOrderDetails("Sending Failed", symbol); //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, symbol, tradeResult.retcode) || IsStopped()) { Print( __FUNCTION__, ": ", symbol, " ERROR opening a ", EnumToString(orderType), " at: ", tradeRequest.price, ", Lot\\Vol: ", tradeRequest.volume ); Print("_______________________________________________________________________________________"); return(false); //-- exit the function //break; //-- exit the for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } } return(false); }
Функция OpenBuyStop
Функция OpenBuyStop(...) отвечает за размещение отложенных ордеров Buy Stop. Функция схожа с описанной ранее OpenBuyLimit(...). Она возвращает true при успешном размещении ордера buy stop и false, если запрос на ордер на выполнен.
Что такое ордер Buy Stop?
Ордер Buy Stop (стоп-ордер на покупку) - запрос на покупку по цене Ask, равной или выше указанной цены входа. Цена входа по стоп-ордеру на покупку действительна только в том случае, если текущая рыночная цена ниже цены входа. Этот тип ордера полезен, когда вы ожидаете, что цена символа вырастет до желаемого вами уровня, а затем продолжит расти, что позволит вам получить прибыль от бычьего тренда.
Ниже представлена функция OpenBuyStop(...) с пояснительными комментариями, которые помогут вам быстро понять, как работает каждая часть кода.
bool OpenBuyStop(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } double tpPrice = 0.0, slPrice = 0.0; //-- Get some information about the orders symbol int symbolDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbolStopLevel = (int)SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(symbol, SYMBOL_SPREAD); //-- Save the order type enumeration ENUM_ORDER_TYPE orderType = ORDER_TYPE_BUY_STOP; //-- check if the entry price is valid if( SymbolInfoDouble(symbol, SYMBOL_ASK) + (symbolStopLevel * symbolPoint) > entryPrice + (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't open a new ", EnumToString(orderType), ". (Reason --> INVALID ENTRY PRICE: ", DoubleToString(entryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid entry price, log the error, exit the function and return false } //--- Validate Stop Loss (sl) and Take Profit (tp) if(sl > 0 && sl < symbolStopLevel) { sl = symbolStopLevel; } if(tp > 0 && tp < symbolStopLevel) { tp = symbolStopLevel; } slPrice = (sl > 0) ? NormalizeDouble(entryPrice - sl * symbolPoint, symbolDigits) : 0; tpPrice = (tp > 0) ? NormalizeDouble(entryPrice + tp * symbolPoint, symbolDigits) : 0; //-- reset the the tradeRequest and tradeResult values by zeroing them ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the parameters to open a buy stop order tradeRequest.type = orderType; tradeRequest.action = TRADE_ACTION_PENDING; tradeRequest.magic = magicNumber; tradeRequest.symbol = symbol; tradeRequest.price = NormalizeDouble(entryPrice, symbolDigits); tradeRequest.tp = tpPrice; tradeRequest.sl = slPrice; tradeRequest.comment = orderComment; tradeRequest.deviation = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * 2; //-- Set and moderate the lot size or volume //-- Verify that volume is not less than allowed minimum lotSize = MathMax(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN)); //-- Verify that volume is not more than allowed maximum lotSize = MathMin(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX)); //-- Round down to nearest volume step lotSize = MathFloor(lotSize / SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)) * SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); tradeRequest.volume = lotSize; //--- Reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function ResetLastError(); for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try opening the order until it is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Print the order details PrintOrderDetails("Sent OK", symbol); //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { Print( __FUNCTION__, ": CONFIRMED: Successfully openend a ", symbol, " ", EnumToString(orderType), " #", tradeResult.order, ", Price: ", tradeResult.price ); PrintFormat("retcode=%u deal=%I64u order=%I64u", tradeResult.retcode, tradeResult.deal, tradeResult.order); Print("_______________________________________________________________________________________"); return(true); //-- exit the function //break; //--- success - order placed ok. exit the for loop } } else //-- Order request failed { //-- Print the order details PrintOrderDetails("Sending Failed", symbol); //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, symbol, tradeResult.retcode) || IsStopped()) { Print( __FUNCTION__, ": ", symbol, " ERROR opening a ", EnumToString(orderType), " at: ", tradeRequest.price, ", Lot\\Vol: ", tradeRequest.volume ); Print("_______________________________________________________________________________________"); return(false); //-- exit the function //break; //-- exit the for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } } return(false); }
Функция OpenSellLimit
Функция OpenSellLimit(...) отвечает за размещение отложенных ордеров Sell Limit. Функция возвращает true при успешном размещении ордера sell limit и false, если запрос на ордер на выполнен.
Что такое ордер Sell Limit?
Ордер Sell Limit (лимитный ордер на продажу) - это запрос на продажу по цене Bid, равной или выше указанной цены входа. Цена входа по ордеру действительна только в том случае, если текущая рыночная цена ниже цены входа. Этот тип ордера полезен, когда вы ожидаете, что цена символа вырастет до указанного уровня, а затем изменит направление, что позволит вам получить прибыль от ожидаемого медвежьего тренда.
Ниже представлена функция OpenSellLimit(...) с пояснительными комментариями, которые помогут вам быстро понять, как работает каждая часть кода.
bool OpenSellLimit(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } double tpPrice = 0.0, slPrice = 0.0; //-- Get some information about the orders symbol int symbolDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbolStopLevel = (int)SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(symbol, SYMBOL_SPREAD); //-- Save the order type enumeration ENUM_ORDER_TYPE orderType = ORDER_TYPE_SELL_LIMIT; //-- check if the entry price is valid if( SymbolInfoDouble(symbol, SYMBOL_BID) + (symbolStopLevel * symbolPoint) > entryPrice - (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't open a new ", EnumToString(orderType), ". (Reason --> INVALID ENTRY PRICE: ", DoubleToString(entryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid entry price, log the error, exit the function and return false } //-- Check the validity of the sl and tp if(sl > 0 && sl < symbolStopLevel) { sl = symbolStopLevel; } if(tp > 0 && tp < symbolStopLevel) { tp = symbolStopLevel; } slPrice = (sl > 0) ? NormalizeDouble(entryPrice + sl * symbolPoint, symbolDigits) : 0; tpPrice = (tp > 0) ? NormalizeDouble(entryPrice - tp * symbolPoint, symbolDigits) : 0; //-- reset the the tradeRequest and tradeResult values by zeroing them ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the parameters to open a sell limit order tradeRequest.type = orderType; tradeRequest.action = TRADE_ACTION_PENDING; tradeRequest.magic = magicNumber; tradeRequest.symbol = symbol; tradeRequest.price = NormalizeDouble(entryPrice, symbolDigits); tradeRequest.tp = tpPrice; tradeRequest.sl = slPrice; tradeRequest.comment = orderComment; tradeRequest.deviation = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * 2; //-- Set and moderate the lot size or volume //-- Verify that volume is not less than allowed minimum lotSize = MathMax(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN)); //-- Verify that volume is not more than allowed maximum lotSize = MathMin(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX)); //-- Round down to nearest volume step lotSize = MathFloor(lotSize / SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)) * SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); tradeRequest.volume = lotSize; //--- Reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function ResetLastError(); for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try opening the order until it is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Print the order details PrintOrderDetails("Sent OK", symbol); //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { Print( __FUNCTION__, ": CONFIRMED: Successfully openend a ", symbol, " ", EnumToString(orderType), " #", tradeResult.order, ", Price: ", tradeResult.price ); PrintFormat("retcode=%u deal=%I64u order=%I64u", tradeResult.retcode, tradeResult.deal, tradeResult.order); Print("_______________________________________________________________________________________"); return(true); //-- exit the function //break; //--- success - order placed ok. exit the for loop } } else //-- Order request failed { //-- Print the order details PrintOrderDetails("Sending Failed", symbol); //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, symbol, tradeResult.retcode) || IsStopped()) { Print( __FUNCTION__, ": ", symbol, " ERROR opening a ", EnumToString(orderType), " at: ", tradeRequest.price, ", Lot\\Vol: ", tradeRequest.volume ); Print("_______________________________________________________________________________________"); return(false); //-- exit the function //break; //-- exit the for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } } return(false); }
Функция OpenSellStop
Функция OpenSellStop(...) отвечает за размещение отложенных ордеров Sell Stop. Функция возвращает true при успешном размещении ордера sell stop, указывая на то, что запрос был обработан без проблем. При неудачной попытке возвращается false.
Что такое ордер Sell Stop?
Ордер Sell Stop (стоп-ордер на продажу) - это запрос на продажу по цене Bid, равной или ниже указанной цены входа. Цена входа по стоп-ордеру на продажу действительна только в том случае, если текущая рыночная цена выше цены входа. Этот тип ордера полезен, когда вы ожидаете, что цена символа упадет до указанного уровня входа, а затем продолжит снижение, что позволяет вам получить прибыль от ожидаемого медвежьего тренда.
Ниже представлена функция OpenSellStop(...) с пояснительными комментариями, которые помогут вам быстро понять, как работает каждая часть кода.
bool OpenSellStop(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } double slPrice = 0.0, tpPrice = 0.0; //-- Get some information about the orders symbol int symbolDigits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS); int symbolStopLevel = (int)SymbolInfoInteger(symbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(symbol, SYMBOL_SPREAD); //-- Save the order type enumeration ENUM_ORDER_TYPE orderType = ORDER_TYPE_SELL_STOP; //-- check if the entry price is valid if( SymbolInfoDouble(symbol, SYMBOL_BID) - (symbolStopLevel * symbolPoint) < entryPrice - (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't open a new ", EnumToString(orderType), ". (Reason --> INVALID ENTRY PRICE: ", DoubleToString(entryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid entry price, log the error, exit the function and return false } //-- Check the validity of the sl and tp if(sl > 0 && sl < symbolStopLevel) { sl = symbolStopLevel; } if(tp > 0 && tp < symbolStopLevel) { tp = symbolStopLevel; } slPrice = (sl > 0) ? NormalizeDouble(entryPrice + sl * symbolPoint, symbolDigits) : 0; tpPrice = (tp > 0) ? NormalizeDouble(entryPrice - tp * symbolPoint, symbolDigits) : 0; //-- reset the the tradeRequest and tradeResult values by zeroing them ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the parameters to open a sell stop order tradeRequest.type = orderType; tradeRequest.action = TRADE_ACTION_PENDING; tradeRequest.magic = magicNumber; tradeRequest.symbol = symbol; tradeRequest.price = NormalizeDouble(entryPrice, symbolDigits); tradeRequest.tp = tpPrice; tradeRequest.sl = slPrice; tradeRequest.comment = orderComment; tradeRequest.deviation = SymbolInfoInteger(symbol, SYMBOL_SPREAD) * 2; //-- Set and moderate the lot size or volume //-- Verify that volume is not less than allowed minimum lotSize = MathMax(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN)); //-- Verify that volume is not more than allowed maximum lotSize = MathMin(lotSize, SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX)); //-- Round down to nearest volume step lotSize = MathFloor(lotSize / SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)) * SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); tradeRequest.volume = lotSize; //--- Reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function ResetLastError(); for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try opening the order until it is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Print the order details PrintOrderDetails("Sent OK", symbol); //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { Print( __FUNCTION__, ": CONFIRMED: Successfully openend a ", symbol, " ", EnumToString(orderType), " #", tradeResult.order, ", Price: ", tradeResult.price ); PrintFormat("retcode=%u deal=%I64u order=%I64u", tradeResult.retcode, tradeResult.deal, tradeResult.order); Print("_______________________________________________________________________________________"); return(true); //-- exit the function //break; //--- success - order placed ok. exit the for loop } } else //-- Order request failed { //-- Print the order details PrintOrderDetails("Sending Failed", symbol); //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, symbol, tradeResult.retcode) || IsStopped()) { Print( __FUNCTION__, ": ", symbol, " ERROR opening a ", EnumToString(orderType), " at: ", tradeRequest.price, ", Lot\\Vol: ", tradeRequest.volume ); Print("_______________________________________________________________________________________"); return(false); //-- exit the function //break; //-- exit the for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } } return(false); }
Функция ModifyPendingOrderbyTicket
Функция ModifyPendingOrderByTicket(...) предназначена для изменения стоп-лосса (SL), тейк-профита (TP) или цены входа активного вложенного ордера. Она проверяет, что изменения соответствуют правилам брокера, фиксирует ход выполнения и любые возможные ошибки, а также использует механизм повторных попыток для многократной попытки внести изменения в случае сбоя или неблагоприятных условий ввода ордера.
Функция принимает четыре параметра:
- orderTicket (ulong) - уникальный идентификатор ордера. Используется для ссылки на конкретный ордер, который вы хотите изменить.
- newEntryPrice (double) - новая цена входа для отложенного ордера. При 0 сохраняется текущая цена.
- newSl (int) - новое значение стоп-лосса (SL) в пунктах. При 0 SL удаляется либо остается неизменным.
- newTp (int) - новое значение тейк-профита (TP) в пунктах. При 0 TP удаляется либо остается неизменным.
Это булева функция. Она возвращает true при успешном изменении ордера и false при неудаче из-за неверных параметров, неправильно выбранном ордере или проблем с сервером. Начнем с реализации определения функции.
bool ModifyPendingOrderByTicket(ulong orderTicket, double newEntryPrice, int newSl, int newTp) export {
Перед изменением ордера мы должны убедиться, что торговая среда допускает алгоритмическую торговлю. Используем функцию TradingIsAllowed() для подтверждения.
if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function }
Чтобы убедиться, что мы изменяем правильный ордер, нам нужно выбрать ордер с помощью стандартной MQL5-функции OrderSelect() и параметра функции orderTicket. Если тикет ордера недействителен или не был успешно выбран, мы зафиксируем эту ошибку и выйдем из функции, вернув булево значение false. Если выбор тикета ордера прошел успешно, мы распечатаем короткое сообщение журнала и приступим к обработке ордера.
//--- Confirm and select the order using the provided orderTicket ResetLastError(); //--- Reset error cache incase of ticket selection errors if(OrderSelect(orderTicket)) { //---Order selected Print("\r\n_______________________________________________________________________________________"); Print(__FUNCTION__, ": Order with ticket:", orderTicket, " selected and ready to set SLTP."); } else { Print("\r\n_______________________________________________________________________________________"); Print(__FUNCTION__, ": Selecting order with ticket:", orderTicket, " failed. ERROR: ", GetLastError()); return(false); //-- Exit the function }
После выбора ордера мы создадим несколько переменных типа double для хранения цены тейк-профита и стоп-лосса и инициализируем их значениями по умолчанию, равными нулю(0.0). Затем мы получаем подробную информацию об ордере (например, символ, объем, текущие SL/TP и так далее), которая потребуются для проверки и внесения изменений.
double newTpPrice = 0.0, newSlPrice = 0.0; //--- Order ticket selected, save the order properties string orderSymbol = OrderGetString(ORDER_SYMBOL); double currentEntryPrice = OrderGetDouble(ORDER_PRICE_OPEN); double volume = OrderGetDouble(ORDER_VOLUME_INITIAL); double currentOrderSlPrice = OrderGetDouble(ORDER_SL); double currentOrderTpPrice = OrderGetDouble(ORDER_TP); ENUM_ORDER_TYPE orderType = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); double orderPriceCurrent = OrderGetDouble(ORDER_PRICE_CURRENT); //-- Get some information about the orders symbol int symbolDigits = (int)SymbolInfoInteger(orderSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places int symbolStopLevel = (int)SymbolInfoInteger(orderSymbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(orderSymbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(orderSymbol, SYMBOL_SPREAD);
Далее мы проверяем новую цену входа, что она соответствует типу ордера (например, buy limit, buy stop, sell stop или sell limit). Это позволит нам своевременно выявлять и отклонять недействительные цены.
if(newEntryPrice > 0.0) { if(orderType == ORDER_TYPE_BUY_STOP || orderType == ORDER_TYPE_SELL_LIMIT) { if( SymbolInfoDouble(orderSymbol, SYMBOL_ASK) + (symbolStopLevel * symbolPoint) > newEntryPrice - (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't MODIFY ", EnumToString(orderType), ". (Reason --> INVALID NEW ENTRY PRICE: ", DoubleToString(newEntryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid new entry price, log the error, exit the function and return false } } if(orderType == ORDER_TYPE_BUY_LIMIT || orderType == ORDER_TYPE_SELL_STOP) { if( SymbolInfoDouble(orderSymbol, SYMBOL_BID) - (symbolStopLevel * symbolPoint) < newEntryPrice + (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't MODIFY ", EnumToString(orderType), ". (Reason --> INVALID NEW ENTRY PRICE: ", DoubleToString(newEntryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid new entry price, log the error, exit the function and return false } } } else { newEntryPrice = currentEntryPrice; //-- Do not modify the entry price }
Нам также необходимо рассчитать стоп-лосс и тейк-профит на основе входных параметров и сверить эти значения с уровнем стоп-приказа брокера.
if(orderType == ORDER_TYPE_BUY_STOP || orderType == ORDER_TYPE_BUY_LIMIT) { if(newSl == 0) { newSlPrice = 0.0; //-- Remove the sl } else { newSlPrice = newEntryPrice - (newSl * symbolPoint); } if(newTp == 0) { newTpPrice = 0.0; //-- Remove the tp } else { newTpPrice = newEntryPrice + (newTp * symbolPoint); } //-- Check the validity of the newSlPrice if(newSlPrice > 0 && newEntryPrice - newSlPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW SL PRICE: ", DoubleToString(newSlPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid sl price, log the error, exit the function and return false } //-- Check the validity of the newTpPrice if(newTpPrice > 0 && newTpPrice - newEntryPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW TP PRICE: ", DoubleToString(newTpPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid tp price, log the error, exit the function and return false } } if(orderType == ORDER_TYPE_SELL_STOP || orderType == ORDER_TYPE_SELL_LIMIT) { if(newSl == 0) { newSlPrice = 0.0; //-- Remove the sl } else { newSlPrice = newEntryPrice + (newSl * symbolPoint); } if(newTp == 0) { newTpPrice = 0.0; //-- Remove the tp } else { newTpPrice = newEntryPrice - (newTp * symbolPoint); } //-- Check the validity of the newSlPrice if(newSlPrice > 0 && newSlPrice - newEntryPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW SL PRICE: ", DoubleToString(newSlPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid sl price, log the error, exit the function and return false } //-- Check the validity of the newTpPrice if(newTpPrice > 0 && newEntryPrice - newTpPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW TP PRICE: ", DoubleToString(newTpPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid tp price, log the error, exit the function and return false } }
Поскольку мы уже проверили все значения, приступим к подготовке торгового запроса на изменение отложенного ордера, установив соответствующие параметры. Сначала сбросим структуру данных tradeRequest, а затем инициализируем ее нашими проверенными и действительными данными ордера.
ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the parameters to set the sltp tradeRequest.action = TRADE_ACTION_MODIFY; //-- Trade operation type for modifying the pending order tradeRequest.order = orderTicket; tradeRequest.symbol = orderSymbol; tradeRequest.price = newEntryPrice; tradeRequest.sl = newSlPrice; tradeRequest.tp = newTpPrice; tradeRequest.deviation = SymbolInfoInteger(orderSymbol, SYMBOL_SPREAD) * 2;
Далее мы реализуем механизм повторных попыток, чтобы повторно отправлять запрос на изменение несколько раз, если первоначальная попытка не удалась, что увеличивает вероятность успешного изменения ордера. В случае критической ошибки или если все попытки исчерпаны, функция возвращает false и уходит. Если ордер успешно изменен, функция возвращает true и выходит. Чтобы избежать перегрузки торгового сервера быстрой серией последовательных запросов, мы также введем задержку между итерациями с помощью функции Sleep(...).
ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try modifying the price open, sl, and tp until the request is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { PrintFormat("Successfully modified Pending Order: #%I64d %s %s", orderTicket, orderSymbol, EnumToString(orderType)); PrintFormat("retcode=%u runtime_code=%u", tradeResult.retcode, GetLastError()); Print("_______________________________________________________________________________________\r\n\r\n"); return(true); //-- exit function //break; //--- success - order placed ok. exit for loop } } else //-- Order request failed { //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, orderSymbol, tradeResult.retcode) || IsStopped()) { PrintFormat("ERROR modifying Pending Order: #%I64d %s %s", orderTicket, orderSymbol, EnumToString(orderType)); Print("_______________________________________________________________________________________\r\n\r\n"); return(false); //-- exit function //break; //-- exit for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } }
Ниже представлен полный код функции, включая некоторые отсутствующие части, со всеми сегментами кода в правильном порядке.
bool ModifyPendingOrderByTicket(ulong orderTicket, double newEntryPrice, int newSl, int newTp) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } //--- Confirm and select the order using the provided orderTicket ResetLastError(); //--- Reset error cache incase of ticket selection errors if(OrderSelect(orderTicket)) { //---Order selected Print("\r\n_______________________________________________________________________________________"); Print(__FUNCTION__, ": Order with ticket:", orderTicket, " selected and ready to set SLTP."); } else { Print("\r\n_______________________________________________________________________________________"); Print(__FUNCTION__, ": Selecting order with ticket:", orderTicket, " failed. ERROR: ", GetLastError()); return(false); //-- Exit the function } //-- create variables to store the calculated tp and sl prices to send to the trade server double newTpPrice = 0.0, newSlPrice = 0.0; //--- Order ticket selected, save the order properties string orderSymbol = OrderGetString(ORDER_SYMBOL); double currentEntryPrice = OrderGetDouble(ORDER_PRICE_OPEN); double volume = OrderGetDouble(ORDER_VOLUME_INITIAL); double currentOrderSlPrice = OrderGetDouble(ORDER_SL); double currentOrderTpPrice = OrderGetDouble(ORDER_TP); ENUM_ORDER_TYPE orderType = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); double orderPriceCurrent = OrderGetDouble(ORDER_PRICE_CURRENT); //-- Get some information about the orders symbol int symbolDigits = (int)SymbolInfoInteger(orderSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places int symbolStopLevel = (int)SymbolInfoInteger(orderSymbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(orderSymbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(orderSymbol, SYMBOL_SPREAD); //-- Check the validity of the newEntryPrice if(newEntryPrice > 0.0) { if(orderType == ORDER_TYPE_BUY_STOP || orderType == ORDER_TYPE_SELL_LIMIT) { if( SymbolInfoDouble(orderSymbol, SYMBOL_ASK) + (symbolStopLevel * symbolPoint) > newEntryPrice - (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't MODIFY ", EnumToString(orderType), ". (Reason --> INVALID NEW ENTRY PRICE: ", DoubleToString(newEntryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid new entry price, log the error, exit the function and return false } } if(orderType == ORDER_TYPE_BUY_LIMIT || orderType == ORDER_TYPE_SELL_STOP) { if( SymbolInfoDouble(orderSymbol, SYMBOL_BID) - (symbolStopLevel * symbolPoint) < newEntryPrice + (spread * symbolPoint) ) { Print( "\r\n", __FUNCTION__, ": Can't MODIFY ", EnumToString(orderType), ". (Reason --> INVALID NEW ENTRY PRICE: ", DoubleToString(newEntryPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid new entry price, log the error, exit the function and return false } } } else { newEntryPrice = currentEntryPrice; //-- Do not modify the entry price } //-- Calculate and store the non-validated sl and tp prices if(orderType == ORDER_TYPE_BUY_STOP || orderType == ORDER_TYPE_BUY_LIMIT) { if(newSl == 0) { newSlPrice = 0.0; //-- Remove the sl } else { newSlPrice = newEntryPrice - (newSl * symbolPoint); } if(newTp == 0) { newTpPrice = 0.0; //-- Remove the tp } else { newTpPrice = newEntryPrice + (newTp * symbolPoint); } //-- Check the validity of the newSlPrice if(newSlPrice > 0 && newEntryPrice - newSlPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW SL PRICE: ", DoubleToString(newSlPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid sl price, log the error, exit the function and return false } //-- Check the validity of the newTpPrice if(newTpPrice > 0 && newTpPrice - newEntryPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW TP PRICE: ", DoubleToString(newTpPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid tp price, log the error, exit the function and return false } } if(orderType == ORDER_TYPE_SELL_STOP || orderType == ORDER_TYPE_SELL_LIMIT) { if(newSl == 0) { newSlPrice = 0.0; //-- Remove the sl } else { newSlPrice = newEntryPrice + (newSl * symbolPoint); } if(newTp == 0) { newTpPrice = 0.0; //-- Remove the tp } else { newTpPrice = newEntryPrice - (newTp * symbolPoint); } //-- Check the validity of the newSlPrice if(newSlPrice > 0 && newSlPrice - newEntryPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW SL PRICE: ", DoubleToString(newSlPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid sl price, log the error, exit the function and return false } //-- Check the validity of the newTpPrice if(newTpPrice > 0 && newEntryPrice - newTpPrice < symbolStopLevel * symbolPoint) { Print( "\r\n", __FUNCTION__, ": Can't modify ", EnumToString(orderType), ". (Reason --> INVALID NEW TP PRICE: ", DoubleToString(newTpPrice, symbolDigits), ")\r\n" ); return(false); //-- Invalid tp price, log the error, exit the function and return false } } //-- Print order properties before modification string orderProperties = "--> " + orderSymbol + " " + EnumToString(orderType) + " SLTP Modification Details" + " <--\r\n"; orderProperties += "------------------------------------------------------------\r\n"; orderProperties += "Ticket: " + (string)orderTicket + "\r\n"; orderProperties += "Volume: " + DoubleToString(volume, symbolDigits) + "\r\n"; orderProperties += "Price Open: " + DoubleToString(currentEntryPrice, symbolDigits) + " -> New Proposed Price Open: " + DoubleToString(newEntryPrice, symbolDigits) + "\r\n"; orderProperties += "Current SL: " + DoubleToString(currentOrderSlPrice, symbolDigits) + " -> New Proposed SL: " + DoubleToString(newSlPrice, symbolDigits) + "\r\n"; orderProperties += "Current TP: " + DoubleToString(currentOrderTpPrice, symbolDigits) + " -> New Proposed TP: " + DoubleToString(newTpPrice, symbolDigits) + "\r\n"; orderProperties += "Comment: " + OrderGetString(ORDER_COMMENT) + "\r\n"; orderProperties += "Magic Number: " + (string)OrderGetInteger(ORDER_MAGIC) + "\r\n"; orderProperties += "---"; //-- Print verified order properties before modification orderProperties += "--> Validated and Confirmed NewEntry, SL, and TP Prices: <--\r\n"; orderProperties += "Order Price Current: " + DoubleToString(orderPriceCurrent, symbolDigits) + "\r\n"; orderProperties += "Current Entry Price: " + DoubleToString(currentEntryPrice, symbolDigits) + ", New Entry Price: " + DoubleToString(newEntryPrice, symbolDigits) + "\r\n"; orderProperties += "Current SL: " + DoubleToString(currentOrderSlPrice, symbolDigits) + " -> New SL: " + DoubleToString(newSlPrice, symbolDigits) + "\r\n"; orderProperties += "Current TP: " + DoubleToString(currentOrderTpPrice, symbolDigits) + " -> New TP: " + DoubleToString(newTpPrice, symbolDigits) + "\r\n"; Print(orderProperties); //-- reset the the tradeRequest and tradeResult values by zeroing them ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the parameters to set the sltp tradeRequest.action = TRADE_ACTION_MODIFY; //-- Trade operation type for modifying the pending order tradeRequest.order = orderTicket; tradeRequest.symbol = orderSymbol; tradeRequest.price = newEntryPrice; tradeRequest.sl = newSlPrice; tradeRequest.tp = newTpPrice; tradeRequest.deviation = SymbolInfoInteger(orderSymbol, SYMBOL_SPREAD) * 2; ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try modifying the price open, sl, and tp until the request is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { PrintFormat("Successfully modified Pending Order: #%I64d %s %s", orderTicket, orderSymbol, EnumToString(orderType)); PrintFormat("retcode=%u runtime_code=%u", tradeResult.retcode, GetLastError()); Print("_______________________________________________________________________________________\r\n\r\n"); return(true); //-- exit function //break; //--- success - order placed ok. exit for loop } } else //-- Order request failed { //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, orderSymbol, tradeResult.retcode) || IsStopped()) { PrintFormat("ERROR modifying Pending Order: #%I64d %s %s", orderTicket, orderSymbol, EnumToString(orderType)); Print("_______________________________________________________________________________________\r\n\r\n"); return(false); //-- exit function //break; //-- exit for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } } return(false); }
Функция DeletePendingOrderByTicket
Функция DeletePendingOrderByTicket(...) отвечает за удаление отложенного ордера по уникальному номеру тикета. Сначала он проверяет, включена ли алгоритмическая торговля, выбирает ордер, а затем пытается удалить его с торгового сервера. На протяжении всего процесса функция фиксирует важные сведения об ордере на разных этапах и использует механизм повторных попыток, чтобы максимально увеличить шансы на успешное удаление, при необходимости повторяя попытку несколько раз.
Функция принимает один параметр типа ulong - orderTicket, представляющий собой уникальный тикет ордера, подлежащего удалению. Она возвращает булево значение, в котором true указывает на успешное удаление отложенного ордера, а false указывает на то, что удаление не удалось или произошла критическая ошибка.
Ниже приведен полный код функции с подробными комментариями для облегчения понимания.
bool DeletePendingOrderByTicket(ulong orderTicket) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } //--- Confirm and select the order using the provided orderTicket ResetLastError(); //--- Reset error cache incase of ticket selection errors if(OrderSelect(orderTicket)) { //---Order selected Print("..........................................................................................."); Print(__FUNCTION__, ": Order with ticket:", orderTicket, " selected and ready to be deleted."); } else { Print("..........................................................................................."); Print(__FUNCTION__, ": Selecting order with ticket:", orderTicket, " failed. ERROR: ", GetLastError()); return(false); //-- Exit the function } //--- Order ticket selected, save the order properties string orderSymbol = OrderGetString(ORDER_SYMBOL); double orderVolume = OrderGetDouble(ORDER_VOLUME_CURRENT); int symbolDigits = (int)SymbolInfoInteger(orderSymbol, SYMBOL_DIGITS); ENUM_ORDER_TYPE orderType = (ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); //-- Print order properties before deleting it string orderProperties; orderProperties += "-- " + orderSymbol + " " + EnumToString(orderType) + " Details" + " -------------------------------------------------------------\r\n"; orderProperties += "Ticket: " + (string)orderTicket + "\r\n"; orderProperties += "Volume: " + DoubleToString(orderVolume) + "\r\n"; orderProperties += "Price Open: " + DoubleToString(OrderGetDouble(ORDER_PRICE_OPEN), symbolDigits) + "\r\n"; orderProperties += "SL: " + DoubleToString(OrderGetDouble(ORDER_SL), symbolDigits) + "\r\n"; orderProperties += "TP: " + DoubleToString(OrderGetDouble(ORDER_TP), symbolDigits) + "\r\n"; orderProperties += "Comment: " + OrderGetString(ORDER_COMMENT) + "\r\n"; orderProperties += "Magic Number: " + (string)OrderGetInteger(ORDER_MAGIC) + "\r\n"; orderProperties += "_______________________________________________________________________________________"; Print(orderProperties); //-- reset the the tradeRequest and tradeResult values by zeroing them ZeroMemory(tradeRequest); ZeroMemory(tradeResult); //-- initialize the trade reqiest parameters to delete the order tradeRequest.action = TRADE_ACTION_REMOVE; //-- Trade operation type for deleting an order tradeRequest.order = orderTicket; ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function for(int loop = 0; loop <= MAX_ORDER_RETRIES; loop++) //-- try deleting the order until the request is successful { //--- send order to the trade server if(OrderSend(tradeRequest, tradeResult)) { //-- Confirm order execution if(tradeResult.retcode == 10008 || tradeResult.retcode == 10009) { Print(__FUNCTION__, "_________________________________________________________________________"); PrintFormat("Successfully deleted order #%I64d %s %s", orderTicket, orderSymbol, EnumToString(orderType)); PrintFormat("retcode=%u runtime_code=%u", tradeResult.retcode, GetLastError()); Print("_______________________________________________________________________________________"); return(true); //-- exit function //break; //--- success - order placed ok. exit for loop } } else //-- order deleting request failed { //-- order not sent or critical error found if(!ErrorAdvisor(__FUNCTION__, orderSymbol, tradeResult.retcode) || IsStopped()) { Print(__FUNCTION__, "_________________________________________________________________________"); PrintFormat("ERROR deleting order #%I64d %s %s", orderTicket, orderSymbol, EnumToString(orderType)); Print("_______________________________________________________________________________________"); return(false); //-- exit function //break; //-- exit for loop Sleep(ORDER_RETRY_DELAYS);//-- Small pause before retrying to avoid overwhelming the trade server } } } return(false); }
Функция DeleteAllPendingOrders
Функция DeleteAllPendingOrders(...) предназначена для удаления всех отложенных ордеров для заданного символа и магического числа. Прежде всего функция проверяет, включена ли алгоритмическая торговля. Функция будет перебирать все открытые ордера, проверять, соответствуют ли они указанному символу и магическому числу и пытаться удалить их по одному. В случаях, когда некоторые ордера невозможно удалить немедленно, функция использует механизм обратного вызова и повторных попыток для непрерывной попытки удаления до тех пор, пока все необходимые ордера не будут удалены. На протяжении всего процесса она фиксирует ошибки и проверяет наличие критических проблем, чтобы избежать потенциальных бесконечных циклов.
Функция принимает два необязательных параметра:
- symbol (string) - строковый параметр, представляющий собой торговый символ. По умолчанию равен ALL_SYMBOLS, то есть он будет ориентирован на ордера для всех символов, если не указан конкретный.
- magicNumber (ulong) - беззнаковое целое число long, представляющее уникальное магическое число ордеров. По умолчанию равно 0, то есть функция будет нацелена на все ордера независимо от их магического числа, если не указано конкретное значение.
Функция возвращает булево значение (bool), где true означает, что все целевые отложенные ордера были успешно удалены, а false указывает на сбой при удалении некоторых или всех ордеров или на критическую ошибку.
Ниже представлен полный код функции с комментариями для облегчения понимания:
bool DeleteAllPendingOrders(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } bool returnThis = false; //-- Scan for symbol and magic number for the specified orders and close them int totalOpenOrders = OrdersTotal(); for(int x = 0; x < totalOpenOrders; x++) { //--- Get order properties ulong orderTicket = OrderGetTicket(x); //-- Get ticket to select the order string selectedSymbol = OrderGetString(ORDER_SYMBOL); ulong orderMagicNo = OrderGetInteger(ORDER_MAGIC); //-- Filter orders by symbol and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && orderMagicNo != magicNumber) ) { continue; } //-- Delete the order DeletePendingOrderByTicket(orderTicket); } //-- Confirm that we have closed all the orders being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolOrdersTotal(symbol, magicNumber) > 0) { breakerBreaker++; DeleteAllPendingOrders(symbol, magicNumber); //-- We still have some open orders, do a function callback Sleep(ORDER_RETRY_DELAYS); //-- Micro sleep to pace the execution and give some time to the trade server //-- Check for critical errors so that we exit the loop if we run into trouble if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > MAX_ORDER_RETRIES) { break; } } //-- Final confirmations that all targeted orders have been closed if(SymbolOrdersTotal(symbol, magicNumber) == 0) { returnThis = true; //-- Save this status for the function return value } return(returnThis); }
Чтобы ускорить удаление всех отложенных ордеров, перегрузим функцию DeleteAllPendingOrders(...) второй версией, которая не принимает аргументов. При вызове удаляются все отложенные ордера на счете. Ниже представлена перегруженная функция DeleteAllPendingOrders():
bool DeleteAllPendingOrders() export { return(DeleteAllPendingOrders(ALL_SYMBOLS, 0)); }
Функция DeleteAllBuyStops
Функция DeleteAllBuyStops(...) отвечает за удаление всех отложенных стоп-ордеров на покупку для заданного символа и магического числа. Подобно другим функциям удаления, она сначала проверяет, включена ли алгоритмическая торговля. Затем функция просматривает все открытые ордера, находит те, что имеют необходимый символ, магическое число и тип ордера (buy stop) и пытается их удалить. Если какие-либо ордера не были удалены во время первоначального прохода, функция использует механизм обратного вызова и повторных попыток для непрерывной попытки удаления. Она гарантирует отсутствие бесконечных циклов, устанавливая меры безопасности и проверяя наличие ошибок. На протяжении всего процесса функция фиксирует необходимую информацию и управляет критическими ошибками.
Функция принимает два необязательных параметра:
- symbol (string) - строка, представляющая торговый символ. Значение по умолчанию ALL_SYMBOLS означает, что функция будет искать ордера buy stop по всем символам, если не указан конкретный.
- magicNumber (ulong) - беззнаковое целое число long, представляющее уникальное магическое число ордеров. По умолчанию равно 0, то есть функция будет нацелена на все ордера buy stop независимо от их магического числа, если не указано конкретное.
Функция возвращает булево значение (bool), где true означает, что все целевые ордера buy stop были успешно удалены, а false указывает на то, что функция не смогла удалить некоторые или все ордера либо столкнулась с критической проблемой.
Ниже приведен полный код функции с полезными комментариями, облегчающими понимание:
bool DeleteAllBuyStops(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } bool returnThis = false; //-- Scan for symbol and magic number specific buy stop orders and close them int totalOpenOrders = OrdersTotal(); for(int x = 0; x < totalOpenOrders; x++) { //--- Get order properties ulong orderTicket = OrderGetTicket(x); //-- Get ticket to select the order string selectedSymbol = OrderGetString(ORDER_SYMBOL); ulong orderMagicNo = OrderGetInteger(ORDER_MAGIC); ulong orderType = OrderGetInteger(ORDER_TYPE); //-- Filter order by symbol, type and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (orderType != ORDER_TYPE_BUY_STOP) || (magicNumber != 0 && orderMagicNo != magicNumber) ) { continue; } //-- Close the order DeletePendingOrderByTicket(orderTicket); } //-- Confirm that we have closed all the buy stop orders being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolBuyStopOrdersTotal(symbol, magicNumber) > 0) { breakerBreaker++; DeleteAllBuyStops(symbol, magicNumber); //-- We still have some open buy stop orders, do a function callback Sleep(ORDER_RETRY_DELAYS); //-- Micro sleep to pace the execution and give some time to the trade server //-- Check for critical errors so that we exit the loop if we run into trouble if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > MAX_ORDER_RETRIES) { break; } } if(SymbolBuyStopOrdersTotal(symbol, magicNumber) == 0) { returnThis = true; } return(returnThis); }
Функция DeleteAllBuyLimits
Функция DeleteAllBuyLimits(...) направлена на удаление всех отложенных ордеров buy limit для данного символа и магического числа. Функция возвращает булево значение (bool), где true означает, что все целевые ордера buy limit были успешно удалены, а false указывает на то, что функция не смогла удалить некоторые или все ордера либо столкнулась с критической проблемой.
bool DeleteAllBuyLimits(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } bool returnThis = false; //-- Scan for symbol and magic number specific buy limit orders and close them int totalOpenOrders = OrdersTotal(); for(int x = 0; x < totalOpenOrders; x++) { //--- Get order properties ulong orderTicket = OrderGetTicket(x); //-- Get ticket to select the order string selectedSymbol = OrderGetString(ORDER_SYMBOL); ulong orderMagicNo = OrderGetInteger(ORDER_MAGIC); ulong orderType = OrderGetInteger(ORDER_TYPE); //-- Filter order by symbol, type and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (orderType != ORDER_TYPE_BUY_LIMIT) || (magicNumber != 0 && orderMagicNo != magicNumber) ) { continue; } //-- Close the order DeletePendingOrderByTicket(orderTicket); } //-- Confirm that we have closed all the buy limit orders being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolBuyLimitOrdersTotal(symbol, magicNumber) > 0) { breakerBreaker++; DeleteAllBuyLimits(symbol, magicNumber); //-- We still have some open buy limit orders, do a function callback Sleep(ORDER_RETRY_DELAYS); //-- Micro sleep to pace the execution and give some time to the trade server //-- Check for critical errors so that we exit the loop if we run into trouble if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > MAX_ORDER_RETRIES) { break; } } if(SymbolBuyLimitOrdersTotal(symbol, magicNumber) == 0) { returnThis = true; } return(returnThis); }
Функция DeleteAllSellStops
Функция DeleteAllSellStops(...) отвечает за удаление всех отложенных ордеров sell stop для данного символа и магического числа. Функция возвращает булево значение (bool), где true означает, что все целевые ордера sell stop были успешно удалены, а false указывает на то, что функция не смогла удалить некоторые или все ордера либо столкнулась с критической проблемой.
bool DeleteAllSellStops(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } bool returnThis = false; //-- Scan for symbol and magic number specific sell stop orders and close them int totalOpenOrders = OrdersTotal(); for(int x = 0; x < totalOpenOrders; x++) { //--- Get order properties ulong orderTicket = OrderGetTicket(x); //-- Get ticket to select the order string selectedSymbol = OrderGetString(ORDER_SYMBOL); ulong orderMagicNo = OrderGetInteger(ORDER_MAGIC); ulong orderType = OrderGetInteger(ORDER_TYPE); //-- Filter order by symbol, type and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (orderType != ORDER_TYPE_SELL_STOP) || (magicNumber != 0 && orderMagicNo != magicNumber) ) { continue; } //-- Close the order DeletePendingOrderByTicket(orderTicket); } //-- Confirm that we have closed all the sell stop orders being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolSellStopOrdersTotal(symbol, magicNumber) > 0) { breakerBreaker++; DeleteAllSellStops(symbol, magicNumber); //-- We still have some open sell stop orders, do a function callback Sleep(ORDER_RETRY_DELAYS); //-- Micro sleep to pace the execution and give some time to the trade server //-- Check for critical errors so that we exit the loop if we run into trouble if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > MAX_ORDER_RETRIES) { break; } } if(SymbolSellStopOrdersTotal(symbol, magicNumber) == 0) { returnThis = true; } return(returnThis); }
Функция DeleteAllSellLimits
Функция DeleteAllSellLimits(...) обрабатывает удаление всех отложенных ордеров sell limit для определенного символа и магического числа. Функция возвращает булево (bool) значение true, при успешном удалении всех ордеров sell limit и false, если функция не смогла удалить некоторые или все ордера либо столкнулась с критической проблемой.
bool DeleteAllSellLimits(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } bool returnThis = false; //-- Scan for symbol and magic number specific sell limit orders and close them int totalOpenOrders = OrdersTotal(); for(int x = 0; x < totalOpenOrders; x++) { //--- Get order properties ulong orderTicket = OrderGetTicket(x); //-- Get ticket to select the order string selectedSymbol = OrderGetString(ORDER_SYMBOL); ulong orderMagicNo = OrderGetInteger(ORDER_MAGIC); ulong orderType = OrderGetInteger(ORDER_TYPE); //-- Filter order by symbol, type and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (orderType != ORDER_TYPE_SELL_LIMIT) || (magicNumber != 0 && orderMagicNo != magicNumber) ) { continue; } //-- Close the order DeletePendingOrderByTicket(orderTicket); } //-- Confirm that we have closed all the sell limit orders being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolSellLimitOrdersTotal(symbol, magicNumber) > 0) { breakerBreaker++; DeleteAllSellLimits(symbol, magicNumber); //-- We still have some open sell limit orders, do a function callback Sleep(ORDER_RETRY_DELAYS); //-- Micro sleep to pace the execution and give some time to the trade server //-- Check for critical errors so that we exit the loop if we run into trouble if(!ErrorAdvisor(__FUNCTION__, symbol, GetLastError()) || IsStopped() || breakerBreaker > MAX_ORDER_RETRIES) { break; } } if(SymbolSellLimitOrdersTotal(symbol, magicNumber) == 0) { returnThis = true; } return(returnThis); }
Функция DeleteAllMagicOrders
Функция DeleteAllMagicOrders(...) отвечает за удаление всех отложенных ордеров, связанных с определенным магическим числом. Функция возвращает булево значение (bool), где true означает, что все ордера с определенным магическим числом были успешно удалены, а false указывает на то, что функция не смогла удалить некоторые или все ордера либо столкнулась с критической проблемой.
bool DeleteAllMagicOrders(ulong magicNumber) export { //-- first check if the EA is allowed to trade if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function } bool returnThis = false; //-- Variables to store the selected orders data ulong orderTicket, orderMagicNo; string orderSymbol; //-- Scan for magic number specific orders and delete them int totalOpenOrders = OrdersTotal(); for(int x = 0; x < totalOpenOrders; x++) { //--- Get order properties orderTicket = OrderGetTicket(x); //-- Get ticket to select the order orderMagicNo = OrderGetInteger(ORDER_MAGIC); orderSymbol = OrderGetString(ORDER_SYMBOL); //-- Filter orders by magic number if(magicNumber == orderMagicNo) { //-- Delete the order DeletePendingOrderByTicket(orderTicket); } } //-- Confirm that we have deleted all the orders being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(MagicOrdersTotal(magicNumber) > 0) { breakerBreaker++; DeleteAllMagicOrders(magicNumber); //-- We still have some open orders, do a function callback Sleep(ORDER_RETRY_DELAYS); //-- Micro sleep to pace the execution and give some time to the trade server //-- Check for critical errors so that we exit the loop if we run into trouble if(!ErrorAdvisor(__FUNCTION__, orderSymbol, GetLastError()) || IsStopped() || breakerBreaker > MAX_ORDER_RETRIES) { break; } } if(MagicOrdersTotal(magicNumber) == 0) { returnThis = true; } return(returnThis); }
Функция GetPendingOrdersData
Чтобы любая автономная алгоритмическая торговая система или советник были надежными и в конечном итоге приносили постоянную прибыль, они должны знать состояние всех позиций и ордеров на счете. Во второй статье мы разработали функцию мониторинга позиций, которая собирает данные по всем открытым позициям. Поскольку в этой статье основное внимание уделяется отложенным ордерам, мы создадим функцию для сканирования и хранения данных по всем отложенным ордерам, сделав ее доступной по всей библиотеке для использования другими функциями. Мы достигнем этого, используя глобальные переменные, установленные в начале этой статьи.
Поскольку эти глобальные переменные не могут быть экспортированы или доступны за пределами файла исходного кода библиотеки или бинарного файла .EX5, мы передадим их различным экспортируемым функциям статуса отложенных ордеров, что позволит сделать их доступными в конечной .EX5-библиотеке. Начнем с создания функции GetPendingOrdersData(...) для извлечения данных всех отложенных ордеров.
Функция GetPendingOrdersData(...) извлекает и сохраняет состояния открытых отложенных ордеров, включая счет, торговые символы и магическое число советника. Она начинает со сброса различных глобальных переменных, в которых хранятся итоговые значения и объемы для различных типов отложенных ордеров, включая ордера buy stop, buy limit, sell stop и sell limit. Затем функция проверяет наличие открытых отложенных ордеров и выполняет их итерацию для сбора соответствующих данных. Затем она сортирует ордера на основе предоставленных символа и магического числа, накапливая итоговые значения и объемы для соответствующих отложенных ордеров. Такой комплексный подход гарантирует, что функция будет собирать данные в реальном времени о состоянии отложенных ордеров, которые могут быть использованы другими функциями советника.
Функция будет принимать два параметра:
- symbol (string): строка, представляющая торговый символ, для которого будут извлечены данные отложенного ордера. Значение по умолчанию - ALL_SYMBOLS, то есть будут собираться данные всех символов.
- magicNumber (ulong) - беззнаковое целое число long, представляющее уникальное магическое число отложенных ордеров советника. По умолчанию этот параметр равен 0, что позволяет функции извлекать данные по всем отложенным ордерам независимо от их магического числа, если не указано конкретное магическое число.
Функция не вернет никакого значения (void), поскольку ее основная цель — заполнение и обновление глобальных переменных состояния данными об отложенных ордерах. Затем к этим переменным будут обращаться другие части библиотеки для информирования о стратегиях принятия решений и торговли.
Ниже приведен полный код функции с подробными комментариями для лучшего понимания:
void GetPendingOrdersData(string symbol, ulong magicNumber) { //-- Reset the account open pending orders status accountBuyStopOrdersTotal = 0; accountBuyLimitOrdersTotal = 0; accountSellStopOrdersTotal = 0; accountSellLimitOrdersTotal = 0; accountPendingOrdersVolumeTotal = 0.0; accountBuyStopOrdersVolumeTotal = 0.0; accountBuyLimitOrdersVolumeTotal = 0.0; accountSellStopOrdersVolumeTotal = 0.0; accountSellLimitOrdersVolumeTotal = 0.0; //-- Reset the EA's magic open pending orders status magicPendingOrdersTotal = 0; magicBuyStopOrdersTotal = 0; magicBuyLimitOrdersTotal = 0; magicSellStopOrdersTotal = 0; magicSellLimitOrdersTotal = 0; magicPendingOrdersVolumeTotal = 0.0; magicBuyStopOrdersVolumeTotal = 0.0; magicBuyLimitOrdersVolumeTotal = 0.0; magicSellStopOrdersVolumeTotal = 0.0; magicSellLimitOrdersVolumeTotal = 0.0; //-- Reset the symbol open pending orders status symbolPendingOrdersTotal = 0; symbolBuyStopOrdersTotal = 0; symbolBuyLimitOrdersTotal = 0; symbolSellStopOrdersTotal = 0; symbolSellLimitOrdersTotal = 0; symbolPendingOrdersVolumeTotal = 0.0; symbolBuyStopOrdersVolumeTotal = 0.0; symbolBuyLimitOrdersVolumeTotal = 0.0; symbolSellStopOrdersVolumeTotal = 0.0; symbolSellLimitOrdersVolumeTotal = 0.0; //-- Update and save the open pending orders status with realtime data int totalOpenPendingOrders = OrdersTotal(); if(totalOpenPendingOrders > 0) { //-- Scan for symbol and magic number specific pending orders and save their status for(int x = 0; x < totalOpenPendingOrders; x++) { //--- Get the pending orders properties ulong orderTicket = OrderGetTicket(x); //-- Get ticket to select the pending order string selectedSymbol = OrderGetString(ORDER_SYMBOL); ulong orderMagicNo = OrderGetInteger(ORDER_MAGIC); //-- Filter pending orders by magic number if(magicNumber != 0 && orderMagicNo != magicNumber) { continue; } //-- Save the account pending orders status first accountPendingOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) { //-- Account properties ++accountBuyStopOrdersTotal; accountBuyStopOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT) { //-- Account properties ++accountBuyLimitOrdersTotal; accountBuyLimitOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) { //-- Account properties ++accountSellStopOrdersTotal; accountSellStopOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT) { //-- Account properties ++accountSellLimitOrdersTotal; accountSellLimitOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } //-- Filter pending orders openend by EA and save their status if( OrderGetInteger(ORDER_REASON) == ORDER_REASON_EXPERT && orderMagicNo == magicNumber ) { ++magicPendingOrdersTotal; magicPendingOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) { //-- Magic properties ++magicBuyStopOrdersTotal; magicBuyStopOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT) { //-- Magic properties ++magicBuyLimitOrdersTotal; magicBuyLimitOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) { //-- Magic properties ++magicSellStopOrdersTotal; magicSellStopOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT) { //-- Magic properties ++magicSellLimitOrdersTotal; magicSellLimitOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } } //-- Filter positions by symbol if(symbol == ALL_SYMBOLS || selectedSymbol == symbol) { ++symbolPendingOrdersTotal; symbolPendingOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) { ++symbolBuyStopOrdersTotal; symbolBuyStopOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT) { ++symbolBuyLimitOrdersTotal; symbolBuyLimitOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) { ++symbolSellStopOrdersTotal; symbolSellStopOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT) { ++symbolSellLimitOrdersTotal; symbolSellLimitOrdersVolumeTotal += OrderGetDouble(ORDER_VOLUME_CURRENT); } } } } }
Функция BuyStopOrdersTotal
Возвращает целое число, представляющее общее количество открытых стоп-ордеров на покупку на счете.
int BuyStopOrdersTotal() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountBuyStopOrdersTotal); }
Функция BuyLimitOrdersTotal
Возвращает целое число, представляющее общее количество открытых стоп-ордеров на покупку на счете.
int BuyLimitOrdersTotal() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountBuyLimitOrdersTotal); }
Функция SellStopOrdersTotal
Возвращает целое число, представляющее общее количество открытых стоп-ордеров на продажу на счете.
int SellStopOrdersTotal() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountSellStopOrdersTotal); }
Функция SellLimitOrdersTotal
Возвращает целое число, представляющее общее количество открытых лимитных ордеров на продажу на счете.
int SellLimitOrdersTotal() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountSellLimitOrdersTotal); }
Функция OrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых ордеров на счете.
double OrdersTotalVolume() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountPendingOrdersVolumeTotal); }
Функция BuyStopOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых стоп-ордеров на покупку на счете.
double BuyStopOrdersTotalVolume() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountBuyStopOrdersVolumeTotal); }
Функция BuyLimitOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых лимитных ордеров на покупку на счете.
double BuyLimitOrdersTotalVolume() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountBuyLimitOrdersVolumeTotal); }
Функция SellStopOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых стоп-ордеров на продажу на счете.
double SellStopOrdersTotalVolume() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountSellStopOrdersVolumeTotal); }
Функция SellLimitOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых лимитных ордеров на продажу на счете.
double SellLimitOrdersTotalVolume() export { GetPendingOrdersData(ALL_SYMBOLS, 0); return(accountSellLimitOrdersVolumeTotal); }
Функция MagicOrdersTotal
Возвращает целое значение общего количества всех открытых отложенных ордеров для указанного магического числа на счете.
int MagicOrdersTotal(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicPendingOrdersTotal); }
Функция MagicBuyStopOrdersTotal
Возвращает целое число общего количества всех открытых стоп-ордеров на покупку для указанного магического числа на счете.
int MagicBuyStopOrdersTotal(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicBuyStopOrdersTotal); }
Функция MagicBuyLimitOrdersTotal
Возвращает целое число общего количества всех открытых лимитных ордеров на покупку для указанного магического числа на счете.
int MagicBuyLimitOrdersTotal(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicBuyLimitOrdersTotal); }
Функция MagicSellStopOrdersTotal
Возвращает целое число общего количества всех открытых стоп-ордеров на продажу для указанного магического числа на счете.
int MagicSellStopOrdersTotal(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicSellStopOrdersTotal); }
Функция MagicSellLimitOrdersTotal
Возвращает целое число общего количества всех открытых лимитных ордеров на продажу для указанного магического числа на счете.
int MagicSellLimitOrdersTotal(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicSellLimitOrdersTotal); }
Функция MagicOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых отложенных ордеров для указанного магического числа на счете.
double MagicOrdersTotalVolume(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicPendingOrdersVolumeTotal); }
Функция MagicBuyStopOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых стоп-ордеров на покупку для указанного магического числа на счете.
double MagicBuyStopOrdersTotalVolume(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicBuyStopOrdersVolumeTotal); }
Функция MagicBuyLimitOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых лимитных ордеров на покупку для указанного магического числа на счете.
double MagicBuyLimitOrdersTotalVolume(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicBuyLimitOrdersVolumeTotal); }
Функция MagicSellStopOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых стоп-ордеров на продажу для указанного магического числа на счете.
double MagicSellStopOrdersTotalVolume(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicSellStopOrdersVolumeTotal); }
Функция MagicSellLimitOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых лимитных ордеров на продажу для указанного магического числа на счете.
double MagicSellLimitOrdersTotalVolume(ulong magicNumber) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); return(magicSellLimitOrdersVolumeTotal); }
Функция SymbolOrdersTotal
Возвращает целое значение, представляющее общее количество всех открытых отложенных ордеров для указанного символа и магического числа на счете.
int SymbolOrdersTotal(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolPendingOrdersTotal); }
Функция SymbolBuyStopOrdersTotal
Возвращает целое значение, представляющее общее количество всех открытых стоп-ордеров на покупку для указанного символа и магического числа на счете.
int SymbolBuyStopOrdersTotal(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolBuyStopOrdersTotal); }
Функция SymbolBuyLimitOrdersTotal
Возвращает целое значение, представляющее общее количество всех открытых лимитных ордеров на покупку для указанного символа и магического числа на счете.
int SymbolBuyLimitOrdersTotal(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolBuyLimitOrdersTotal); }
Функция SymbolSellStopOrdersTotal
Возвращает целое число, представляющее общее количество всех открытых стоп-ордеров на продажу для указанного символа и магического числа на счете.
int SymbolSellStopOrdersTotal(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolSellStopOrdersTotal); }
Функция SymbolSellLimitOrdersTotal
Возвращает целое значение, представляющее общее количество всех открытых лимитных ордеров на продажу для указанного символа и магического числа на счете.
int SymbolSellLimitOrdersTotal(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolSellLimitOrdersTotal); }
Функция SymbolOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых отложенных ордеров для указанного символа и магического числа на счете.
double SymbolOrdersTotalVolume(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolPendingOrdersVolumeTotal); }
Функция SymbolBuyStopOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых стоп-ордеров на покупку для указанного символа и магического числа на счете.
double SymbolBuyStopOrdersTotalVolume(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolBuyStopOrdersVolumeTotal); }
Функция SymbolBuyLimitOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых лимитных ордеров на покупку для указанного символа и магического числа на счете.
double SymbolBuyLimitOrdersTotalVolume(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolBuyLimitOrdersVolumeTotal); }
Функция SymbolSellStopOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых стоп-ордеров на продажу для указанного символа и магического числа на счете.
double SymbolSellStopOrdersTotalVolume(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolSellStopOrdersVolumeTotal); }
Функция SymbolSellLimitOrdersTotalVolume
Возвращает значение double, представляющее общий объем/лот/количество всех открытых лимитных ордеров на продажу для указанного символа и магического числа на счете.
double SymbolSellLimitOrdersTotalVolume(string symbol, ulong magicNumber) export { GetPendingOrdersData(symbol, magicNumber); return(symbolSellLimitOrdersVolumeTotal); }
Функция AccountOrdersStatus
Возвращает предварительно отформатированную строку, содержащую статус ордеров по счету, которую можно вывести в журнал или отобразить в комментариях к графику. Функция принимает один булевый параметр formatForComment. Если formatForComment равен true, функция форматирует данные для отображения в окне графика; при false она форматирует данные для вкладки журнала советника.
string AccountOrdersStatus(bool formatForComment) export { GetPendingOrdersData(ALL_SYMBOLS, 0); //-- Update the orders status variables before we display their data string spacer = ""; if(formatForComment) //-- Add some formating space for the chart comment string { spacer = " "; } string accountOrdersStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n"; accountOrdersStatus += spacer + "| " + (string)AccountInfoInteger(ACCOUNT_LOGIN) + " - ACCOUNT ORDERS STATUS \r\n"; accountOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; accountOrdersStatus += spacer + "| Total Open: " + (string)OrdersTotal() + "\r\n"; accountOrdersStatus += spacer + "| Total Volume: " + (string)accountPendingOrdersVolumeTotal + "\r\n"; accountOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; accountOrdersStatus += spacer + "| BUY STOP ORDERS: \r\n"; accountOrdersStatus += spacer + "| Total Open: " + (string)accountBuyStopOrdersTotal + "\r\n"; accountOrdersStatus += spacer + "| Total Volume: " + (string)accountBuyStopOrdersVolumeTotal + "\r\n"; accountOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; accountOrdersStatus += spacer + "| BUY LIMIT ORDERS: \r\n"; accountOrdersStatus += spacer + "| Total Open: " + (string)accountBuyLimitOrdersTotal + "\r\n"; accountOrdersStatus += spacer + "| Total Volume: " + (string)accountBuyLimitOrdersVolumeTotal + "\r\n"; accountOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; accountOrdersStatus += spacer + "| SELL STOP ORDERS: \r\n"; accountOrdersStatus += spacer + "| Total Open: " + (string)accountSellStopOrdersTotal + "\r\n"; accountOrdersStatus += spacer + "| Total Volume: " + (string)accountSellStopOrdersVolumeTotal + "\r\n"; accountOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; accountOrdersStatus += spacer + "| SELL LIMIT ORDERS: \r\n"; accountOrdersStatus += spacer + "| Total Open: " + (string)accountSellLimitOrdersTotal + "\r\n"; accountOrdersStatus += spacer + "| Total Volume: " + (string)accountSellLimitOrdersVolumeTotal + "\r\n"; accountOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; accountOrdersStatus += spacer + "\r\n"; return(accountOrdersStatus); }
Функция MagicOrdersStatus
Возвращает предварительно отформатированную строку, указывающую статус ордеров по магическому числу, которую можно вывести в журнал или отобразить в комментариях к графику. Функция принимает два параметра: беззнаковый long под названием magicNumber, чтобы указать целевое магическое число, и булевый под названием formatForComment для определения типа форматирования. Если formatForComment равен true, функция форматирует данные для отображения в окне графика; при false она форматирует данные для вкладки журнала советника.
string MagicOrdersStatus(ulong magicNumber, bool formatForComment) export { GetPendingOrdersData(ALL_SYMBOLS, magicNumber); //-- Update the order status variables before we display their data string spacer = ""; if(formatForComment) //-- Add some formating space for the chart comment string { spacer = " "; } string magicOrdersStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n"; magicOrdersStatus += spacer + "| " + (string)magicNumber + " - MAGIC ORDERS STATUS \r\n"; magicOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; magicOrdersStatus += spacer + "| Total Open: " + (string)magicPendingOrdersTotal + "\r\n"; magicOrdersStatus += spacer + "| Total Volume: " + (string)magicPendingOrdersVolumeTotal + "\r\n"; magicOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; magicOrdersStatus += spacer + "| BUY STOP ORDERS: \r\n"; magicOrdersStatus += spacer + "| Total Open: " + (string)magicBuyStopOrdersTotal + "\r\n"; magicOrdersStatus += spacer + "| Total Volume: " + (string)magicBuyStopOrdersVolumeTotal + "\r\n"; magicOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; magicOrdersStatus += spacer + "| BUY LIMIT ORDERS: \r\n"; magicOrdersStatus += spacer + "| Total Open: " + (string)magicBuyLimitOrdersTotal + "\r\n"; magicOrdersStatus += spacer + "| Total Volume: " + (string)magicBuyLimitOrdersVolumeTotal + "\r\n"; magicOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; magicOrdersStatus += spacer + "| SELL STOP ORDERS: \r\n"; magicOrdersStatus += spacer + "| Total Open: " + (string)magicSellStopOrdersTotal + "\r\n"; magicOrdersStatus += spacer + "| Total Volume: " + (string)magicSellStopOrdersVolumeTotal + "\r\n"; magicOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; magicOrdersStatus += spacer + "| SELL LIMIT ORDERS: \r\n"; magicOrdersStatus += spacer + "| Total Open: " + (string)magicSellLimitOrdersTotal + "\r\n"; magicOrdersStatus += spacer + "| Total Volume: " + (string)magicSellLimitOrdersVolumeTotal + "\r\n"; magicOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; magicOrdersStatus += spacer + "\r\n"; return(magicOrdersStatus); }
Функция SymbolOrdersStatus
Возвращает предварительно отформатированную строку, указывающую статус ордеров по символу, которую можно вывести в журнал или отобразить в комментариях к графику. Функция принимает три параметра: строку symbol, беззнаковый long под названием magicNumber, чтобы указать целевое магическое число (нулевое значение отключает сортировку по магическому числу), и булевый под названием formatForComment для определения типа форматирования. Если formatForComment равен true, функция форматирует данные для отображения в окне графика; при false она форматирует данные для вкладки журнала советника.
string SymbolOrdersStatus(string symbol, ulong magicNumber, bool formatForComment) export { GetPendingOrdersData(symbol, magicNumber); //-- Update the order status variables before we display their data string spacer = ""; if(formatForComment) //-- Add some formating space for the chart comment string { spacer = " "; } string symbolOrdersStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n"; symbolOrdersStatus += spacer + "| " + symbol + " - SYMBOL ORDERS STATUS \r\n"; symbolOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; symbolOrdersStatus += spacer + "| Total Open: " + (string)symbolPendingOrdersTotal + "\r\n"; symbolOrdersStatus += spacer + "| Total Volume: " + (string)symbolPendingOrdersVolumeTotal + "\r\n"; symbolOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; symbolOrdersStatus += spacer + "| BUY STOP ORDERS: \r\n"; symbolOrdersStatus += spacer + "| Total Open: " + (string)symbolBuyStopOrdersTotal + "\r\n"; symbolOrdersStatus += spacer + "| Total Volume: " + (string)symbolBuyStopOrdersVolumeTotal + "\r\n"; symbolOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; symbolOrdersStatus += spacer + "| BUY LIMIT ORDERS: \r\n"; symbolOrdersStatus += spacer + "| Total Open: " + (string)symbolBuyLimitOrdersTotal + "\r\n"; symbolOrdersStatus += spacer + "| Total Volume: " + (string)symbolBuyLimitOrdersVolumeTotal + "\r\n"; symbolOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; symbolOrdersStatus += spacer + "| SELL STOP ORDERS: \r\n"; symbolOrdersStatus += spacer + "| Total Open: " + (string)symbolSellStopOrdersTotal + "\r\n"; symbolOrdersStatus += spacer + "| Total Volume: " + (string)symbolSellStopOrdersVolumeTotal + "\r\n"; symbolOrdersStatus += spacer + "|------------------------------------------------------------------\r\n"; symbolOrdersStatus += spacer + "| SELL LIMIT ORDERS: \r\n"; symbolOrdersStatus += spacer + "| Total Open: " + (string)symbolSellLimitOrdersTotal + "\r\n"; symbolOrdersStatus += spacer + "| Total Volume: " + (string)symbolSellLimitOrdersVolumeTotal + "\r\n"; symbolOrdersStatus += spacer + "|---------------------------------------------------------------------------\r\n"; symbolOrdersStatus += spacer + "\r\n"; return(symbolOrdersStatus); }
Созданные функции составляют нашу EX5-библиотеку для управления отложенными ордерами. В конце статьи приложен файл с исходным кодом PendingOrdersManager.mq5, а также скомпилированный бинарный исполняемый файл PendingOrdersManager.ex5, который вы можете легко импортировать и использовать в своих MQL5-проектах.
Как импортировать и внедрить EX5-библиотеку для управления отложенными ордерами
Мы разработали надежную EX5-библиотеку для управления отложенными ордерами, которая содержит основные функции для обработки отложенных ордеров, получения их состояния и отображения соответствующей информации. Теперь пришло время задокументировать и продемонстрировать, как правильно импортировать и использовать эту библиотеку в любом MQL5-проекте.
Чтобы упростить процесс внедрения, мы начнем с описания всех функций и модулей библиотеки управления отложенными ордерами, а также приведем практические примеры кода в разделе документации ниже. Это даст четкое представление о компонентах, входящих в состав бинарного файла PendingOrdersManager.ex5.
Документация EX5-библиотеки для управления отложенными ордерами
Шаг 1: Скопируйте исполняемые файлы библиотеки (PositionsManager.ex5 и PendingOrdersManager.ex5)Поместите файлы PositionsManager.ex5 и PendingOrdersManager.ex5 в папку MQL5/Libraries/Toolkit или в ту же папку, что и что и файл с исходным кодом, импортирующий библиотеку. Убедитесь, что эти файлы загружены и скопированы в указанное место, если их там еще нет. Для вашего удобства копии обоих файлов прикреплены в конце статьи.
Шаг 2: Импортируйте описания прототипов функций
В разделе заголовка исходного кода, добавьте директивы import для библиотеки управления отложенными ордерами и описаний прототипов ее функций. Используйте следующий фрагмент кода для эффективного импорта всех функций или модулей из библиотеки PendingOrdersManager.ex5. Я также создал пустой шаблон советника (PendingOrdersManager_Imports_Template.mq5), включающий этот сегмент кода. Вы можете закомментировать или удалить любые описания функций, которые не нужны для вашего проекта. Также в конце статьи приложен файл PendingOrdersManager_Imports_Template.mq5.
//+------------------------------------------------------------------------------------------+ //-- Copy and paste the import derictives below to use the Pending Orders Manager EX5 Library //--- //+-------------------------------------------------------------------------------------+ //| PendingOrdersManager.ex5 imports template | //+-------------------------------------------------------------------------------------+ #import "Toolkit/PendingOrdersManager.ex5" //-- Opening import directive //-- Function descriptions for the imported function prototypes //-- Pending Orders Execution and Modification Functions bool OpenBuyLimit(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); bool OpenBuyStop(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); bool OpenSellLimit(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); bool OpenSellStop(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); bool ModifyPendingOrderByTicket(ulong orderTicket, double newEntryPrice, int newSl, int newTp); bool DeletePendingOrderByTicket(ulong orderTicket); bool DeleteAllPendingOrders(string symbol, ulong magicNumber); bool DeleteAllPendingOrders(); bool DeleteAllBuyStops(string symbol, ulong magicNumber); bool DeleteAllBuyLimits(string symbol, ulong magicNumber); bool DeleteAllSellStops(string symbol, ulong magicNumber); bool DeleteAllSellLimits(string symbol, ulong magicNumber); bool DeleteAllMagicOrders(ulong magicNumber); //-- Pending Orders Status Monitoring Functions int BuyStopOrdersTotal(); int BuyLimitOrdersTotal(); int SellStopOrdersTotal(); int SellLimitOrdersTotal(); double OrdersTotalVolume(); double BuyStopOrdersTotalVolume(); double BuyLimitOrdersTotalVolume(); double SellStopOrdersTotalVolume(); double SellLimitOrdersTotalVolume(); //-- Pending Orders Filtered By Magic Number Status Monitoring Functions int MagicOrdersTotal(ulong magicNumber); int MagicBuyStopOrdersTotal(ulong magicNumber); int MagicBuyLimitOrdersTotal(ulong magicNumber); int MagicSellStopOrdersTotal(ulong magicNumber); int MagicSellLimitOrdersTotal(ulong magicNumber); double MagicOrdersTotalVolume(ulong magicNumber); double MagicBuyStopOrdersTotalVolume(ulong magicNumber); double MagicBuyLimitOrdersTotalVolume(ulong magicNumber); double MagicSellStopOrdersTotalVolume(ulong magicNumber); double MagicSellLimitOrdersTotalVolume(ulong magicNumber); //-- Pending Orders Filtered By Symbol and/or Magic Number Status Monitoring Functions int SymbolOrdersTotal(string symbol, ulong magicNumber); int SymbolBuyStopOrdersTotal(string symbol, ulong magicNumber); int SymbolBuyLimitOrdersTotal(string symbol, ulong magicNumber); int SymbolSellStopOrdersTotal(string symbol, ulong magicNumber); int SymbolSellLimitOrdersTotal(string symbol, ulong magicNumber); double SymbolOrdersTotalVolume(string symbol, ulong magicNumber); double SymbolBuyStopOrdersTotalVolume(string symbol, ulong magicNumber); double SymbolBuyLimitOrdersTotalVolume(string symbol, ulong magicNumber); double SymbolSellStopOrdersTotalVolume(string symbol, ulong magicNumber); double SymbolSellLimitOrdersTotalVolume(string symbol, ulong magicNumber); //-- Log and Data Display Functions string AccountOrdersStatus(bool formatForComment); string MagicOrdersStatus(ulong magicNumber, bool formatForComment); string SymbolOrdersStatus(string symbol, ulong magicNumber, bool formatForComment); #import //--- Closing import directive //+-------------------------------------------------------------------------------------+
Теперь, когда функции прототипа библиотеки .EX5 импортированы в ваш MQL5-проект или исходный код, используйте таблицу ниже, где приведена подробная документация и практические примеры того, как реализовать и использовать эти функции в вашем коде.
Описание прототипа функции | Описание | Пример использования |
---|---|---|
bool OpenBuyLimit( ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment ); | Открывает новый лимитный ордер на покупку, соответствующий указанным параметрам. | double symbolPoint = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); //--- ulong magicNo = 123; string symbol = _Symbol; double entryPrice = SymbolInfoDouble( _Symbol, SYMBOL_ASK) - ((spread * 20) * symbolPoint ); double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); int sl = spread * 50; //-- pips int tp = spread * 100; //-- pips string orderComment = "Pending Orders Manager Buy Limit Order"; OpenBuyLimit( magicNumber, symbol, entryPrice, lotSize, sl, tp, orderComment ); |
bool OpenBuyStop( ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment ); | Открывает новый стоп-ордер на покупку, соответствующий указанным параметрам. | double symbolPoint = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); //--- ulong magicNo = 123; string symbol = _Symbol; double entryPrice = SymbolInfoDouble( _Symbol, SYMBOL_ASK) + ((spread * 20) * symbolPoint ); double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); int sl = spread * 50; //-- pips int tp = spread * 100; //-- pips string orderComment = "Pending Orders Manager Buy Stop Order"; OpenBuyStop( magicNumber, symbol, entryPrice, lotSize, sl, tp, orderComment ); |
bool OpenSellLimit( ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment ); | Открывает новый лимитный ордер на продажу, соответствующий указанным параметрам. | double symbolPoint = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); //--- ulong magicNo = 123; string symbol = _Symbol; double entryPrice = SymbolInfoDouble( _Symbol, SYMBOL_ASK) + ((spread * 20) * symbolPoint ); double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); int sl = spread * 50; //-- pips int tp = spread * 100; //-- pips string orderComment = "Pending Orders Manager Sell Limit Order"; OpenSellLimit( magicNumber, symbol, entryPrice, lotSize, sl, tp, orderComment ); |
bool OpenSellStop( ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment ); | Открывает новый стоп-ордер на продажу, соответствующий указанным параметрам. | double symbolPoint = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); //--- ulong magicNo = 123; string symbol = _Symbol; double entryPrice = SymbolInfoDouble( _Symbol, SYMBOL_ASK) - ((spread * 20) * symbolPoint ); double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); int sl = spread * 50; //-- pips int tp = spread * 100; //-- pips string orderComment = "Pending Orders Manager Sell Stop Order"; OpenSellStop( magicNumber, symbol, entryPrice, lotSize, sl, tp, orderComment ); |
bool ModifyPendingOrderByTicket( ulong orderTicket, double newEntryPrice, int newSl, int newTp ); | Изменяет отложенный ордер, используя указанные параметры. | double symbolPoint = SymbolInfoDouble(_Symbol, SYMBOL_POINT); int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); int totalOpenOders = OrdersTotal(); for(int x = 0; x < totalOpenOders; x++) { ulong orderTicket = OrderGetTicket(x); if(orderTicket > 0) { //-- Modify a buy stop order if(OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) { double newEntryPrice = OrderGetDouble( ORDER_PRICE_OPEN) + ((spread * 40) * symbolPoint ); int newSl = 0; //-- Do not modify the stop loss level int newTp = 0; //-- Don not modify the take profit level ModifyPendingOrderByTicket( orderTicket, newEntryPrice, newSl, newTp ); break; } } } |
bool DeletePendingOrderByTicket( ulong orderTicket ); | Удаляет отложенный ордер по номеру тикета. | for(int x = 0; x < totalOpenOders; x++) { ulong orderTicket = OrderGetTicket(x); if(orderTicket > 0) { DeletePendingOrderByTicket(orderTicket); break; } } |
bool DeleteAllPendingOrders( string symbol = ALL_SYMBOLS, ulong magicNumber = 0 ); | Удаляет все отложенные ордера по имени символа и магическому числу. | //Deletes all orders in the account DeleteAllPendingOrders("", 0); //Deletes all orders belonging to the symbol DeleteAllPendingOrders(_Symbol, 0); //Deletes all orders that have a magic number 101 DeleteAllPendingOrders("", 101); //Deletes all EURUSD orders that have a magic number 101 DeleteAllPendingOrders("EURUSD", 101); |
bool DeleteAllPendingOrders() | Удаляет все открытые отложенные ордера на счете. | //Deletes all orders in the account
DeleteAllPendingOrders(); |
bool DeleteAllBuyStops( string symbol = ALL_SYMBOLS, ulong magicNumber = 0 ); | Удаляет все стоп-ордера на покупку по имени символа и магическому числу. | //Deletes all buy stops in the account DeleteAllBuyStops("", 0); //Deletes all buy stops belonging to the symbol DeleteAllBuyStops(_Symbol, 0); //Deletes all buy stops that have a magic number 101 DeleteAllBuyStops("", 101); //Deletes all EURUSD buy stops that have a magic number 101 DeleteAllBuyStops("EURUSD", 101); |
bool DeleteAllBuyLimits( string symbol = ALL_SYMBOLS, ulong magicNumber = 0 ); | Удаляет все лимитные ордера на покупку по имени символа и магическому числу. | //Deletes all buy limits in the account DeleteAllBuyLimits("", 0); //Deletes all buy limits belonging to the symbol DeleteAllBuyLimits(_Symbol, 0); //Deletes all buy limits that have a magic number 101 DeleteAllBuyLimits("", 101); //Deletes all GBPUSD buy limits that have a magic number 101 DeleteAllBuyLimits("GBPUSD", 101); |
bool DeleteAllSellStops( string symbol = ALL_SYMBOLS, ulong magicNumber = 0 ); | Удаляет все стоп-ордера на продажу по имени символа и магическому числу. | //Deletes all sell stops in the account DeleteAllSellStops("", 0); //Deletes all sell stops belonging to the symbol DeleteAllSellStops(_Symbol, 0); //Deletes all sell stops that have a magic number 101 DeleteAllSellStops("", 101); //Deletes all JPYUSD sell stops that have a magic number 101 DeleteAllSellStops("JPYUSD", 101); |
bool DeleteAllSellLimits( string symbol = ALL_SYMBOLS, ulong magicNumber = 0 ); | Удаляет все лимитные ордера на продажу по имени символа и магическому числу. | //Deletes all sell limits in the account DeleteAllSellLimits("", 0); //Deletes all sell limits belonging to the symbol DeleteAllSellLimits(_Symbol, 0); //Deletes all sell limits that have a magic number 101 DeleteAllSellLimits("", 101); //Deletes all AUDJPY sell limits that have a magic number 101 DeleteAllSellLimits("AUDJPY", 101); |
bool DeleteAllMagicOrders( ulong magicNumber ); | Удаляет все отложенные ордера по магическому числу. | //-- Deletes all orders open in the account DeleteAllMagicOrders("", 0); //-- Deletes all orders that have a magic number 101 DeleteAllMagicOrders(101); |
int BuyStopOrdersTotal(); | Возвращает общее количество открытых стоп-ордеров на покупку. | //Get the total number of open buy stops in the account
BuyStopOrdersTotal(); |
int BuyLimitOrdersTotal(); | Возвращает общее количество открытых лимитных ордеров на покупку. | //Get the total number of open buy limits in the account
BuyLimitOrdersTotal(); |
int SellStopOrdersTotal(); | Возвращает общее количество открытых стоп-ордеров на продажу. | //Get the total number of open sell stops in the account SellStopOrdersTotal(); |
int SellLimitOrdersTotal(); | Возвращает общее количество открытых лимитных ордеров на продажу. | //Get the total number of open sell limits in the account
SellLimitOrdersTotal(); |
double OrdersTotalVolume(); | Возвращает общий объем всех открытых ордеров. | //Get the total volume/lot of open orders in the account
OrdersTotalVolume(); |
double BuyStopOrdersTotalVolume(); | Возвращает общий объем всех стоп-ордеров на покупку. | //Get the total volume/lot of open buy stops in the account
BuyStopOrdersTotalVolume(); |
double BuyLimitOrdersTotalVolume(); | Возвращает общий объем всех лимитных ордеров на покупку. | //Get the total volume/lot of open buy limits in the account
BuyLimitOrdersTotalVolume(); |
double SellStopOrdersTotalVolume(); | Возвращает общий объем всех стоп-ордеров на продажу. | //Get the total volume/lot of open sell stops in the account
SellStopOrdersTotalVolume(); |
double SellLimitOrdersTotalVolume(); | Возвращает общий объем всех лимитных ордеров на продажу. | //Get the total volume/lot of open sell limits in the account
SellLimitOrdersTotalVolume(); |
int MagicOrdersTotal( ulong magicNumber ); | Возвращает количество открытых ордеров по указанному магическому числу. | //Get the total open pending orders for magic number 101 MagicOrdersTotal(101); |
int MagicBuyStopOrdersTotal( ulong magicNumber ); | Возвращает количество открытых стоп-ордеров на покупку по указанному магическому числу. | //Get the total open buy stop orders for magic number 101 MagicBuyStopOrdersTotal(101); |
int MagicBuyLimitOrdersTotal( ulong magicNumber ); | Возвращает количество открытых лимитных ордеров на покупку по указанному магическому числу. | //Get the total open buy limit orders for magic number 101 MagicBuyLimitOrdersTotal(101); |
int MagicSellStopOrdersTotal( ulong magicNumber ); | Возвращает количество открытых стоп-ордеров на продажу по указанному магическому числу. | //Get the total open sell stop orders for magic number 101 MagicSellStopOrdersTotal(101); |
int MagicSellLimitOrdersTotal( ulong magicNumber ); | Возвращает количество открытых лимитных ордеров на продажу по указанному магическому числу. | //Get the total open sell limit orders for magic number 101 MagicSellLimitOrdersTotal(101); |
double MagicOrdersTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых ордеров по указанному магическому числу. | //Get the total volume/lot of all open orders for magic 101 MagicOrdersTotalVolume(101); |
double MagicBuyStopOrdersTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых стоп-ордеров на покупку по указанному магическому числу. | //Get the total volume/lot of all buy stop orders for magic 101 MagicBuyStopOrdersTotalVolume(101); |
double MagicBuyLimitOrdersTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых лимитных ордеров на покупку по указанному магическому числу. | //Get the total volume/lot of all buy limit orders for magic 101 MagicBuyLimitOrdersTotalVolume(101); |
double MagicSellStopOrdersTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых стоп-ордеров на продажу по указанному магическому числу. | //Get the total volume/lot of all sell stop orders for magic 101 MagicSellStopOrdersTotalVolume(101); |
double MagicSellLimitOrdersTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых лимитных ордеров на продажу по указанному магическому числу. | //Get the total volume/lot of all sell limit orders for magic 101 MagicSellLimitOrdersTotalVolume(101); |
int SymbolOrdersTotal( string symbol, ulong magicNumber ); | Возвращает количество открытых ордеров по указанному символу и магическому числу. | //Get the total open orders for the symbol SymbolOrdersTotal(_Symbol, 0); //Get the total open orders for the symbol and magic 101 SymbolOrdersTotal(_Symbol, 101); |
int SymbolBuyStopOrdersTotal( string symbol, ulong magicNumber ); | Возвращает количество открытых стоп-ордеров на покупку по указанным символу и магическому числу. | //Get the total buy stop orders for the symbol SymbolBuyStopOrdersTotal(_Symbol, 0); //Get the total buy stop orders for the symbol and magic number 101 SymbolBuyStopOrdersTotal(_Symbol, 101); |
int SymbolBuyLimitOrdersTotal( string symbol, ulong magicNumber ); | Возвращает количество открытых лимитных ордеров на покупку по указанным символу и магическому числу. | //Get the total buy limit orders for the symbol SymbolBuyLimitOrdersTotal(_Symbol, 0); //Get the total buy limit orders for the symbol and magic number 101 SymbolBuyLimitOrdersTotal(_Symbol, 101); |
int SymbolSellStopOrdersTotal( string symbol, ulong magicNumber ); | Возвращает количество открытых стоп-ордеров на продажу по указанным символу и магическому числу. | //Get the total sell stop orders for the symbol SymbolSellStopOrdersTotal(_Symbol, 0); //Get the total sell stop orders for the symbol and magic 101 SymbolSellStopOrdersTotal(_Symbol, 101); |
int SymbolSellLimitOrdersTotal( string symbol, ulong magicNumber ); | Возвращает количество открытых лимитных ордеров на продажу по указанным символу и магическому числу. | //Get the total sell limit orders for the symbol SymbolSellLimitOrdersTotal(_Symbol, 0); //Get the total sell limit orders for the symbol and magic 101 SymbolSellLimitOrdersTotal(_Symbol, 101); |
double SymbolOrdersTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых ордеров по указанным символу и магическому числу. | //Get the total orders volume/lot for the symbol SymbolOrdersTotalVolume(_Symbol, 0); //Get the total orders volume/lot for the symbol and magic 101 SymbolOrdersTotalVolume(_Symbol, 101); |
double SymbolBuyStopOrdersTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых стоп-ордеров на покупку по указанным символу и магическому числу. | //Get the total buy stops volume/lot for the symbol SymbolBuyStopOrdersTotalVolume(_Symbol, 0); //Get the total buy stops volume/lot for the symbol and magic 101 SymbolBuyStopOrdersTotalVolume(_Symbol, 101); |
double SymbolBuyLimitOrdersTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых лимитных ордеров на покупку по указанным символу и магическому числу. | //Get the total buy limits volume/lot for the symbol SymbolBuyLimitOrdersTotalVolume(_Symbol, 0); //Get the total buy limits volume/lot for symbol and magic 101 SymbolBuyLimitOrdersTotalVolume(_Symbol, 101); |
double SymbolSellStopOrdersTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых стоп-ордеров на продажу по указанным символу и магическому числу. | //Get the total sell stops volume/lot for symbol SymbolSellStopOrdersTotalVolume(_Symbol, 0); //Get the total sell stops volume/lot for symbol and magic 101 SymbolSellStopOrdersTotalVolume(_Symbol, 101); |
double SymbolSellLimitOrdersTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых лимитных ордеров на продажу по указанным символу и магическому числу. | //Get the total sell limits volume/lot for symbol SymbolSellLimitOrdersTotalVolume(_Symbol, 0); //Get the total sell limits volume/lot for symbol and magic 101 SymbolSellLimitOrdersTotalVolume(_Symbol, 101); |
string AccountOrdersStatus( bool formatForComment ); | Выводит на экран строковый статус всех открытых ордеров на графике символов или на вкладке "Эксперты" в MetaTrader 5. | //Print the status of all open orders //formatted for the chart comments Comment(AccountOrdersStatus(true)); //Print the status of all open orders //formatted for the Experts tab Print(AccountOrdersStatus(false)); //Activate an alert with the status of all //open orders formatted for printing Print(AccountOrdersStatus(false)); |
string MagicOrdersStatus( ulong magicNumber, bool formatForComment ); | Выводит на экран строковый статус всех открытых ордеров, соответствующих указанному магическому числу, на графике символов или на вкладке "Эксперты" в MetaTrader 5. | //Print the status of all open orders matching //magic number 101 formatted for the chart comments Comment(MagicOrdersStatus(101, true)); //Print the status of all open orders matching //magic number 101 formatted for the Experts tab Print(MagicOrdersStatus(101, false)); //Activate an alert with the status of all open orders //matching magic number 101 formatted for printing Print(MagicOrdersStatus(101, false)); |
string SymbolOrdersStatus( string symbol, ulong magicNumber, bool formatForComment ); | Выводит на экран строковый статус всех открытых ордеров, соответствующих указанным символу и магическому числу, на графике символов или на вкладке "Эксперты" в MetaTrader 5. | //Print the status of all open orders matching //the symbol and magic number 101 formatted for the chart comments Comment(SymbolOrdersStatus(_Symbol, 101, true)); //Print the status of all open orders matching //the symbol and magic number 101 formatted for the Experts tab Print(SymbolOrdersStatus(_Symbol, 101, false)); //Activate an alert with the status of all open orders //matching the symbol and magic number 101 formatted for printing Print(SymbolOrdersStatus(_Symbol, 101, false)); |
Импортировав библиотеку, вы теперь можете легко открыть, изменить, удалить или получить данные о статусе отложенного ордера посредством простых вызовов функций. Чтобы продемонстрировать это, в следующем разделе создадим практичную торговую панель с графическим пользовательским интерфейсом (GUI) для управления отложенными ордерами.
Разработка панели отложенных ордеров (GUI) на основе EX5-библиотеки
В этом разделе мы разработаем графический пользовательский интерфейс (GUI) для панели отложенных ордеров советника на основе EX5-библиотеки для управления отложенными ордерами. Панель позволяет открывать, удалять и отслеживать все ордера, связанные с указанным магическим числом, привязанным к панели. В этом примере наглядно демонстрируется, как импортировать и реализовать EX5-библиотеку, которую мы только что создали, в реальном приложении MQL5.
Панель отложенных ордеров будет использовать стандартную библиотеку MQL5 для панелей и диалоговых окон, что позволит нам сохранить минимальную и эффективную базу кода. Окончательный пользовательский интрефейс панели представлен ниже.
Чтобы сформировать графический интерфейс, создадим советника с помощью мастера MQL в MetaEditor и назовем его PendingOrdersPanel.mq5. Поскольку советник будет использовать библиотеку PendingOrdersManager.ex5, первым шагом является импорт и включение описаний прототипов функций библиотеки, как описано ранее. Разместите код импорта библиотеки чуть ниже директив #property. Учитывая, что библиотека содержит множество функций, мы импортируем только необходимые прототипы функций, перечисленные в коде ниже.
#import "Toolkit/PendingOrdersManager.ex5" //-- Opening import directive //-- Function descriptions for the imported function prototypes //-- Pending Orders Execution and Modification Functions bool OpenBuyLimit(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); bool OpenBuyStop(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); bool OpenSellLimit(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); bool OpenSellStop(ulong magicNumber, string symbol, double entryPrice, double lotSize, int sl, int tp, string orderComment); //-- int MagicOrdersTotal(ulong magicNumber); int MagicBuyStopOrdersTotal(ulong magicNumber); int MagicBuyLimitOrdersTotal(ulong magicNumber); int MagicSellStopOrdersTotal(ulong magicNumber); int MagicSellLimitOrdersTotal(ulong magicNumber); //-- bool DeleteAllBuyStops(string symbol, ulong magicNumber); bool DeleteAllBuyLimits(string symbol, ulong magicNumber); bool DeleteAllSellStops(string symbol, ulong magicNumber); bool DeleteAllSellLimits(string symbol, ulong magicNumber); bool DeleteAllMagicOrders(ulong magicNumber); #import //--- Closing import directive
Создадим глобальные переменные, которые мы будем использовать для хранения свойств ордера.
//-- Global variables //----------------------- ulong magicNo = 10101010; double symbolPoint = SymbolInfoDouble(_Symbol, SYMBOL_POINT); long symbolDigits = SymbolInfoInteger(_Symbol, SYMBOL_DIGITS); int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD); double volumeLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); int sl = (int)spread * 50; int tp = (int)spread * 100;
Далее нам необходимо определить некоторые константы для хранения всех свойств графического объекта. Это упростит для нас задачу обновления или изменения их значений в одном месте, если мы захотим внести какие-либо изменения во внешний вид панелей ордеров.
//-- Define some values for the main panel #define MAIN_PANEL_NAME string("Orders Panel - Trading: " + _Symbol + " - Magic No: " + IntegerToString(magicNo)) #define MAIN_PANEL_SUBWINDOW 0 #define MAIN_PANEL_X1 350 #define MAIN_PANEL_Y1 10 #define MAIN_PANEL_WIDTH int(800 + MAIN_PANEL_X1) #define MAIN_PANEL_X2 MAIN_PANEL_WIDTH //-- Define the GUI objects general properties #define GUI_OBJECTS_MARGIN 5 #define GUI_OBJECTS_HEIGHT 40//40 #define GUI_OBJECTS_WIDTH int((MAIN_PANEL_WIDTH) / 7) #define GUI_OBJECTS_FONT_SIZE 9//10 #define GUI_OBJECTS_HEADER_FONT_SIZE GUI_OBJECTS_FONT_SIZE //----- #define MAIN_PANEL_HEIGHT int(((GUI_OBJECTS_HEIGHT + (GUI_OBJECTS_MARGIN * 2)) * 10) + MAIN_PANEL_Y1) #define MAIN_PANEL_Y2 MAIN_PANEL_HEIGHT //-- Define the GUI objects colors #define GUI_OBJECTS_HEADING_COLOR clrNavy #define GUI_OBJECTS_BUY_BTN_COLOR clrWhite #define GUI_OBJECTS_BUY_BTN_BG_COLOR clrBlue #define GUI_OBJECTS_BUY_EDIT_COLOR clrBlue #define GUI_OBJECTS_BUY_EDIT_BG_COLOR clrAliceBlue #define GUI_OBJECTS_SELL_BTN_COLOR clrWhite #define GUI_OBJECTS_SELL_BTN_BG_COLOR clrCrimson #define GUI_OBJECTS_SELL_EDIT_COLOR clrMaroon #define GUI_OBJECTS_SELL_EDIT_BG_COLOR clrMistyRose /*------------------------------------------------------ * Define GUI components for the heading labels **** *-----------------------------------------------------*/ //-- Define values for the lotVolHeaderLabel #define VOLUME_LOT_LABEL_NAME "Volume Lot Header Label" #define VOLUME_LOT_LABEL_SUBWINDOW 0 #define VOLUME_LOT_LABEL_X1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_WIDTH) #define VOLUME_LOT_LABEL_Y1 int(GUI_OBJECTS_MARGIN * 2) #define VOLUME_LOT_LABEL_TEXT "VOLUME/LOT" //-- Define values for the openPriceHeaderLabel #define OPEN_PRICE_LABEL_NAME "Open Price Header Label" #define OPEN_PRICE_LABEL_SUBWINDOW 0 #define OPEN_PRICE_LABEL_X1 (int(GUI_OBJECTS_WIDTH) * 2) #define OPEN_PRICE_LABEL_Y1 int(GUI_OBJECTS_MARGIN * 2) #define OPEN_PRICE_LABEL_TEXT "OPENING PRICE" //-- Define values for the slHeaderLabel #define SL_LABEL_NAME "Sl Header Label" #define SL_LABEL_SUBWINDOW 0 #define SL_LABEL_X1 (int(GUI_OBJECTS_WIDTH) * 3) #define SL_LABEL_Y1 int(GUI_OBJECTS_MARGIN * 2) #define SL_LABEL_TEXT "SL (Pips)" //-- Define values for the tpHeaderLabel #define TP_LABEL_NAME "Tp Header Label" #define TP_LABEL_SUBWINDOW 0 #define TP_LABEL_X1 (int(GUI_OBJECTS_WIDTH) * 3.75) #define TP_LABEL_Y1 int(GUI_OBJECTS_MARGIN * 2) #define TP_LABEL_TEXT "TP (Pips)" /*------------------------------------------------------ * Define Buy Stop Order GUI components **** *-----------------------------------------------------*/ //-- Define values for the buyStopBtn #define BUY_STOP_BTN_NAME "Buy Stop Button" #define BUY_STOP_BTN_SUBWINDOW 0 #define BUY_STOP_BTN_X1 GUI_OBJECTS_MARGIN #define BUY_STOP_BTN_Y1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) #define BUY_STOP_BTN_TEXT "BUY STOP" //-- Define values for the buyStopVolumeLotEdit #define BUY_STOP_VOLUME_LOT_EDIT_NAME "Buy Stop Volume Lot Edit" #define BUY_STOP_VOLUME_LOT_EDIT_SUBWINDOW 0 #define BUY_STOP_VOLUME_LOT_EDIT_X1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_WIDTH) #define BUY_STOP_VOLUME_LOT_EDIT_Y1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) //-- Define values for the buyStopOpenPriceEdit #define BUY_STOP_OPEN_PRICE_EDIT_NAME "Buy Stop Open Price Edit" #define BUY_STOP_OPEN_PRICE_EDIT_SUBWINDOW 0 #define BUY_STOP_OPEN_PRICE_EDIT_X1 int((GUI_OBJECTS_WIDTH) * 2) #define BUY_STOP_OPEN_PRICE_EDIT_Y1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) //-- Define values for the buyStopSlEdit #define BUY_STOP_SL_EDIT_NAME "Buy Stop SL Edit" #define BUY_STOP_SL_EDIT_SUBWINDOW 0 #define BUY_STOP_SL_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3) #define BUY_STOP_SL_EDIT_Y1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) //-- Define values for the buyStopTpEdit #define BUY_STOP_TP_EDIT_NAME "Buy Stop TP Edit" #define BUY_STOP_TP_EDIT_SUBWINDOW 0 #define BUY_STOP_TP_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3.7) #define BUY_STOP_TP_EDIT_Y1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) /*------------------------------------------------------ * Define Sell Stop Order GUI components **** *-----------------------------------------------------*/ //-- Define values for the sellStopBtn #define SELL_STOP_BTN_NAME "Sell Stop Button" #define SELL_STOP_BTN_SUBWINDOW 0 #define SELL_STOP_BTN_X1 GUI_OBJECTS_MARGIN #define SELL_STOP_BTN_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 2) #define SELL_STOP_BTN_TEXT "SELL STOP" //-- Define values for the sellStopVolumeLotEdit #define SELL_STOP_VOLUME_LOT_EDIT_NAME "Sell Stop Volume Lot Edit" #define SELL_STOP_VOLUME_LOT_EDIT_SUBWINDOW 0 #define SELL_STOP_VOLUME_LOT_EDIT_X1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_WIDTH) #define SELL_STOP_VOLUME_LOT_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 2) //-- Define values for the sellStopOpenPriceEdit #define SELL_STOP_OPEN_PRICE_EDIT_NAME "Sell Stop Open Price Edit" #define SELL_STOP_OPEN_PRICE_EDIT_SUBWINDOW 0 #define SELL_STOP_OPEN_PRICE_EDIT_X1 int((GUI_OBJECTS_WIDTH) * 2) #define SELL_STOP_OPEN_PRICE_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 2) //-- Define values for the sellStopSlEdit #define SELL_STOP_SL_EDIT_NAME "Sell Stop SL Edit" #define SELL_STOP_SL_EDIT_SUBWINDOW 0 #define SELL_STOP_SL_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3) #define SELL_STOP_SL_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 2) //-- Define values for the sellStopTpEdit #define SELL_STOP_TP_EDIT_NAME "Sell Stop TP Edit" #define SELL_STOP_TP_EDIT_SUBWINDOW 0 #define SELL_STOP_TP_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3.7) #define SELL_STOP_TP_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 2) /*------------------------------------------------------ * Define Buy Limit Order GUI components **** *-----------------------------------------------------*/ //-- Define values for the buyLimitBtn #define BUY_LIMIT_BTN_NAME "Buy Limit Button" #define BUY_LIMIT_BTN_SUBWINDOW 0 #define BUY_LIMIT_BTN_X1 GUI_OBJECTS_MARGIN #define BUY_LIMIT_BTN_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 3) #define BUY_LIMIT_BTN_TEXT "BUY LIMIT" //-- Define values for the buyLimitVolumeLotEdit #define BUY_LIMIT_VOLUME_LOT_EDIT_NAME "Buy Limit Volume Lot Edit" #define BUY_LIMIT_VOLUME_LOT_EDIT_SUBWINDOW 0 #define BUY_LIMIT_VOLUME_LOT_EDIT_X1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_WIDTH) #define BUY_LIMIT_VOLUME_LOT_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 3) //-- Define values for the buySLimitOpenPriceEdit #define BUY_LIMIT_OPEN_PRICE_EDIT_NAME "Buy Limit Open Price Edit" #define BUY_LIMIT_OPEN_PRICE_EDIT_SUBWINDOW 0 #define BUY_LIMIT_OPEN_PRICE_EDIT_X1 int((GUI_OBJECTS_WIDTH) * 2) #define BUY_LIMIT_OPEN_PRICE_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 3) //-- Define values for the buyLimitSlEdit #define BUY_LIMIT_SL_EDIT_NAME "Buy Limit SL Edit" #define BUY_LIMIT_SL_EDIT_SUBWINDOW 0 #define BUY_LIMIT_SL_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3) #define BUY_LIMIT_SL_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 3) //-- Define values for the buyLimitTpEdit #define BUY_LIMIT_TP_EDIT_NAME "Buy Limit TP Edit" #define BUY_LIMIT_TP_EDIT_SUBWINDOW 0 #define BUY_LIMIT_TP_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3.7) #define BUY_LIMIT_TP_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 3) /*------------------------------------------------------ * Define Sell Limit Order GUI components **** *-----------------------------------------------------*/ //-- Define values for the sellLimitBtn #define SELL_LIMIT_BTN_NAME "Sell Limit Button" #define SELL_LIMIT_BTN_SUBWINDOW 0 #define SELL_LIMIT_BTN_X1 GUI_OBJECTS_MARGIN #define SELL_LIMIT_BTN_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 4) #define SELL_LIMIT_BTN_TEXT "SELL LIMIT" //-- Define values for the sellLimitVolumeLotEdit #define SELL_LIMIT_VOLUME_LOT_EDIT_NAME "Sell Limit Volume Lot Edit" #define SELL_LIMIT_VOLUME_LOT_EDIT_SUBWINDOW 0 #define SELL_LIMIT_VOLUME_LOT_EDIT_X1 int(GUI_OBJECTS_MARGIN + GUI_OBJECTS_WIDTH) #define SELL_LIMIT_VOLUME_LOT_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 4) //-- Define values for the sellLimitOpenPriceEdit #define SELL_LIMIT_OPEN_PRICE_EDIT_NAME "Sell Limit Open Price Edit" #define SELL_LIMIT_OPEN_PRICE_EDIT_SUBWINDOW 0 #define SELL_LIMIT_OPEN_PRICE_EDIT_X1 int((GUI_OBJECTS_WIDTH) * 2) #define SELL_LIMIT_OPEN_PRICE_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 4) //-- Define values for the sellLimitSlEdit #define SELL_LIMIT_SL_EDIT_NAME "Sell Limit SL Edit" #define SELL_LIMIT_SL_EDIT_SUBWINDOW 0 #define SELL_LIMIT_SL_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3) #define SELL_LIMIT_SL_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 4) //-- Define values for the sellLimitTpEdit #define SELL_LIMIT_TP_EDIT_NAME "Sell Limit TP Edit" #define SELL_LIMIT_TP_EDIT_SUBWINDOW 0 #define SELL_LIMIT_TP_EDIT_X1 int(GUI_OBJECTS_WIDTH * 3.7) #define SELL_LIMIT_TP_EDIT_Y1 int((GUI_OBJECTS_MARGIN + GUI_OBJECTS_HEIGHT) * 4) /*------------------------------------------------------ * Define Order Status GUI components **** *-----------------------------------------------------*/ //-- Define values for the orders status #define STATUS_HEADER_FONT_SIZE int(GUI_OBJECTS_FONT_SIZE)// / 1.1) #define STATUS_EDIT_FONT_SIZE int(GUI_OBJECTS_FONT_SIZE)// / 1.1) #define STATUS_EDIT_WIDTH int((MAIN_PANEL_WIDTH / 1.485) - (GUI_OBJECTS_MARGIN * 2)) #define STATUS_EDIT_COLOR clrBlack #define STATUS_EDIT_BG_COLOR clrLemonChiffon #define STATUS_EDIT_BORDER_COLOR clrMidnightBlue #define DELETE_ORDERS_BTN_COLOR clrLightYellow #define DELETE_BUY_ORDERS_BTN_BG_COLOR clrRoyalBlue #define DELETE_SELL_ORDERS_BTN_BG_COLOR clrCrimson #define DELETE_ALL_ORDERS_BTN_BG_COLOR clrMediumVioletRed #define DELETE_ORDERS_BTN_BORDER_COLOR clrBlack #define DELETE_ORDERS_BTN_WIDTH int((STATUS_EDIT_WIDTH / 1.93) - (GUI_OBJECTS_MARGIN * 3)) #define DELETE_ORDERS_BTN_FONT_SIZE int((GUI_OBJECTS_FONT_SIZE))// / 1.05) //-- Define values for the magicOrderStatusLabel #define MAGIC_ORDER_STATUS_LABEL_NAME "Magic Order Status Label" #define MAGIC_ORDER_STATUS_LABEL_SUBWINDOW 0 #define MAGIC_ORDER_STATUS_LABEL_X1 int(GUI_OBJECTS_MARGIN * 3) #define MAGIC_ORDER_STATUS_LABEL_Y1 int((GUI_OBJECTS_HEIGHT * 6) + (GUI_OBJECTS_MARGIN * 2)) #define MAGIC_ORDER_STATUS_LABEL_TEXT string("MAGIC No: " + IntegerToString(magicNo) + " - TOTAL OPEN ORDERS: ") //-- Define values for the magicOrdersStatusEdit #define MAGIC_ORDER_STATUS_EDIT_NAME "Magic Order Status Edit" #define MAGIC_ORDER_STATUS_EDIT_SUBWINDOW 0 #define MAGIC_ORDER_STATUS_EDIT_X1 int(GUI_OBJECTS_MARGIN * 2) #define MAGIC_ORDER_STATUS_EDIT_Y1 int((MAGIC_ORDER_STATUS_LABEL_Y1) + (GUI_OBJECTS_HEIGHT / 1.7)) //-- Define values for the deleteAllMagicBuyStopsBtn #define DELETE_ALL_MAGIC_BUY_STOPS_BTN_NAME "Delete All Magic Buy Stops Btn" #define DELETE_ALL_MAGIC_BUY_STOPS_BTN_SUBWINDOW 0 #define DELETE_ALL_MAGIC_BUY_STOPS_BTN_X1 int(GUI_OBJECTS_MARGIN * 2) #define DELETE_ALL_MAGIC_BUY_STOPS_BTN_Y1 int((MAGIC_ORDER_STATUS_EDIT_Y1) + (GUI_OBJECTS_HEIGHT + GUI_OBJECTS_MARGIN)) #define DELETE_ALL_MAGIC_BUY_STOPS_BTN_TEXT "DELETE ALL MAGIC BUY STOPS" //-- Define values for the deleteAllMagicSellStopsBtn #define DELETE_ALL_MAGIC_SELL_STOPS_BTN_NAME "Delete All Magic Sell Stops Btn" #define DELETE_ALL_MAGIC_SELL_STOPS_BTN_SUBWINDOW 0 #define DELETE_ALL_MAGIC_SELL_STOPS_BTN_X1 int((GUI_OBJECTS_MARGIN * 3) + DELETE_ORDERS_BTN_WIDTH) #define DELETE_ALL_MAGIC_SELL_STOPS_BTN_Y1 int((MAGIC_ORDER_STATUS_EDIT_Y1) + (GUI_OBJECTS_HEIGHT + GUI_OBJECTS_MARGIN)) #define DELETE_ALL_MAGIC_SELL_STOPS_BTN_TEXT "DELETE ALL MAGIC SELL STOPS" //-- Define values for the deleteAllMagicBuyLimitsBtn #define DELETE_ALL_MAGIC_BUY_LIMITS_BTN_NAME "Delete All Magic Buy Limits Btn" #define DELETE_ALL_MAGIC_BUY_LIMITS_BTN_SUBWINDOW 0 #define DELETE_ALL_MAGIC_BUY_LIMITS_BTN_X1 int(GUI_OBJECTS_MARGIN * 2) #define DELETE_ALL_MAGIC_BUY_LIMITS_BTN_Y1 int((DELETE_ALL_MAGIC_BUY_STOPS_BTN_Y1) + (GUI_OBJECTS_HEIGHT + GUI_OBJECTS_MARGIN)) #define DELETE_ALL_MAGIC_BUY_LIMITS_BTN_TEXT "DELETE ALL MAGIC BUY LIMITS" //-- Define values for the deleteAllMagicSellLimitsBtn #define DELETE_ALL_MAGIC_SELL_LIMITS_BTN_NAME "Delete All Magic Sell Limits Btn" #define DELETE_ALL_MAGIC_SELL_LIMITS_BTN_SUBWINDOW 0 #define DELETE_ALL_MAGIC_SELL_LIMITS_BTN_X1 int((GUI_OBJECTS_MARGIN * 3) + DELETE_ORDERS_BTN_WIDTH) #define DELETE_ALL_MAGIC_SELL_LIMITS_BTN_Y1 DELETE_ALL_MAGIC_BUY_LIMITS_BTN_Y1//int((MAGIC_ORDER_STATUS_EDIT_Y1) + (GUI_OBJECTS_HEIGHT + GUI_OBJECTS_MARGIN)) #define DELETE_ALL_MAGIC_SELL_LIMITS_BTN_TEXT "DELETE ALL MAGIC SELL LIMITS" //-- Define values for the deleteAllMagicOrdersBtn #define DELETE_ALL_MAGIC_ORDERS_BTN_NAME "Delete All Magic Orders Btn" #define DELETE_ALL_MAGIC_ORDERS_BTN_SUBWINDOW 0 #define DELETE_ALL_MAGIC_ORDERS_BTN_X1 int(GUI_OBJECTS_MARGIN * 2) #define DELETE_ALL_MAGIC_ORDERS_BTN_Y1 int((DELETE_ALL_MAGIC_BUY_LIMITS_BTN_Y1) + (GUI_OBJECTS_HEIGHT + GUI_OBJECTS_MARGIN)) #define DELETE_ALL_MAGIC_ORDERS_BTN_TEXT "DELETE ALL MAGIC PENDING ORDERS"
Добавим в наш код стандартные классы MQL5 для панелей и диалогов.
//-- Include the MQL5 standard library for panels and dialogs #include <Controls\Dialog.mqh> #include <Controls\Button.mqh> #include <Controls\Label.mqh> #include <Controls\Edit.mqh>
Теперь, когда классы панелей и диалоговых окон включены и доступны в нашем файле, мы можем приступить к созданию их объектов для расширения функциональности в нашем коде.
//-- Create objects for the included standard classes CAppDialog mainPanelWindow; //-- Create the header label components CLabel lotVolHeaderLabel; CLabel openPriceHeaderLabel; CLabel slHeaderLabel; CLabel tpHeaderLabel; //-- Create the buy stop GUI components //--BuyStopBtn CButton buyStopBtn; //--BuyStopEdits CEdit buyStopVolumeLotEdit; CEdit buyStopOpenPriceEdit; CEdit buyStopSlEdit; CEdit buyStopTpEdit; //-- Create the sell stop GUI components //--SellStopBtn CButton sellStopBtn; //--sellStopEdits CEdit sellStopVolumeLotEdit; CEdit sellStopOpenPriceEdit; CEdit sellStopSlEdit; CEdit sellStopTpEdit; //-- Create the buy limit GUI components //--BuyLimitBtn CButton buyLimitBtn; //--BuyLimitEdits CEdit buyLimitVolumeLotEdit; CEdit buyLimitOpenPriceEdit; CEdit buyLimitSlEdit; CEdit buyLimitTpEdit; //-- Create the sell limit GUI components //--sellLimitBtn CButton sellLimitBtn; //--sellLimitEdits CEdit sellLimitVolumeLotEdit; CEdit sellLimitOpenPriceEdit; CEdit sellLimitSlEdit; CEdit sellLimitTpEdit; //-- Create the order status GUI components //--magic order status CLabel magicOrderStatusLabel; CEdit magicOrdersStatusEdit; //--Magic orders delete buttons CButton deleteAllMagicBuyStopsBtn; CButton deleteAllMagicSellStopsBtn; CButton deleteAllMagicBuyLimitsBtn; CButton deleteAllMagicSellLimitsBtn; CButton deleteAllMagicOrdersBtn;
Создадим переменные, которые будут отвечать за хранение цен входа, и строку для хранения статуса всех ордеров, открытых нашим советником.
//-- Default starting entry prices for different pending orders double buyStopEntryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK) + ((spread * 20) * symbolPoint); double buyLimitEntryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - ((spread * 20) * symbolPoint); double sellStopEntryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - ((spread * 20) * symbolPoint); double sellLimitEntryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK) + ((spread * 20) * symbolPoint); //-- String values for the orders status string magicOrderStatus;
Следующий шаг - создание функции, отвечающей за генерацию и загрузку графического пользовательского интерфейса во время инициализации советника. Назовем эту функцию CreateGui().
void CreateGui() { //-- Create the orders panel mainPanelWindow.Create( 0, MAIN_PANEL_NAME, MAIN_PANEL_SUBWINDOW, MAIN_PANEL_X1, MAIN_PANEL_Y1, MAIN_PANEL_X2, MAIN_PANEL_Y2 ); /*------------------------------------------------------ * Header Labels GUI components creation **** *-----------------------------------------------------*/ //--Create the lot volume header label lotVolHeaderLabel.Create( 0, VOLUME_LOT_LABEL_NAME, VOLUME_LOT_LABEL_SUBWINDOW, VOLUME_LOT_LABEL_X1, VOLUME_LOT_LABEL_Y1, GUI_OBJECTS_WIDTH, GUI_OBJECTS_HEIGHT ); lotVolHeaderLabel.Text(VOLUME_LOT_LABEL_TEXT); lotVolHeaderLabel.Color(GUI_OBJECTS_HEADING_COLOR); lotVolHeaderLabel.FontSize(GUI_OBJECTS_HEADER_FONT_SIZE); mainPanelWindow.Add(lotVolHeaderLabel); //--Create the open price header label openPriceHeaderLabel.Create( 0, OPEN_PRICE_LABEL_NAME, OPEN_PRICE_LABEL_SUBWINDOW, OPEN_PRICE_LABEL_X1, OPEN_PRICE_LABEL_Y1, GUI_OBJECTS_WIDTH, GUI_OBJECTS_HEIGHT ); openPriceHeaderLabel.Text(OPEN_PRICE_LABEL_TEXT); openPriceHeaderLabel.Color(GUI_OBJECTS_HEADING_COLOR); openPriceHeaderLabel.FontSize(GUI_OBJECTS_HEADER_FONT_SIZE); mainPanelWindow.Add(openPriceHeaderLabel); //--Create the sl header label slHeaderLabel.Create( 0, SL_LABEL_NAME, SL_LABEL_SUBWINDOW, SL_LABEL_X1, SL_LABEL_Y1, int(GUI_OBJECTS_WIDTH / 1.4), GUI_OBJECTS_HEIGHT ); slHeaderLabel.Text(SL_LABEL_TEXT); slHeaderLabel.Color(GUI_OBJECTS_HEADING_COLOR); slHeaderLabel.FontSize(GUI_OBJECTS_HEADER_FONT_SIZE); mainPanelWindow.Add(slHeaderLabel); //--Create the tp header label tpHeaderLabel.Create( 0, TP_LABEL_NAME, TP_LABEL_SUBWINDOW, TP_LABEL_X1, TP_LABEL_Y1, int(GUI_OBJECTS_WIDTH / 1.4), GUI_OBJECTS_HEIGHT ); tpHeaderLabel.Text(TP_LABEL_TEXT); tpHeaderLabel.Color(GUI_OBJECTS_HEADING_COLOR); tpHeaderLabel.FontSize(GUI_OBJECTS_HEADER_FONT_SIZE); mainPanelWindow.Add(tpHeaderLabel); /*------------------------------------------------------ * Buy Stop Order GUI components creation **** *-----------------------------------------------------*/ //--Create the open buy stop button buyStopBtn.Create( 0, BUY_STOP_BTN_NAME, BUY_STOP_BTN_SUBWINDOW, BUY_STOP_BTN_X1, BUY_STOP_BTN_Y1, 0, 0 ); buyStopBtn.Text(BUY_STOP_BTN_TEXT); buyStopBtn.Width(GUI_OBJECTS_WIDTH); buyStopBtn.Height(GUI_OBJECTS_HEIGHT); buyStopBtn.Color(GUI_OBJECTS_BUY_BTN_COLOR); buyStopBtn.ColorBackground(GUI_OBJECTS_BUY_BTN_BG_COLOR); buyStopBtn.FontSize(GUI_OBJECTS_FONT_SIZE); mainPanelWindow.Add(buyStopBtn); //--Create the buy stop volume lot edit to get the buy stop volume/lot user input buyStopVolumeLotEdit.Create( 0, BUY_STOP_VOLUME_LOT_EDIT_NAME, BUY_STOP_VOLUME_LOT_EDIT_SUBWINDOW, BUY_STOP_VOLUME_LOT_EDIT_X1, BUY_STOP_VOLUME_LOT_EDIT_Y1, 0, 0 ); buyStopVolumeLotEdit.Text(DoubleToString(volumeLot)); buyStopVolumeLotEdit.Width(GUI_OBJECTS_WIDTH); buyStopVolumeLotEdit.Height(GUI_OBJECTS_HEIGHT); buyStopVolumeLotEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyStopVolumeLotEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyStopVolumeLotEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyStopVolumeLotEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyStopVolumeLotEdit); //--Create the buy stop price edit to get the buy stop opening price user input buyStopOpenPriceEdit.Create( 0, BUY_STOP_OPEN_PRICE_EDIT_NAME, BUY_STOP_OPEN_PRICE_EDIT_SUBWINDOW, BUY_STOP_OPEN_PRICE_EDIT_X1, BUY_STOP_OPEN_PRICE_EDIT_Y1, 0, 0 ); buyStopOpenPriceEdit.Text(DoubleToString(buyStopEntryPrice, int(symbolDigits))); buyStopOpenPriceEdit.Width(GUI_OBJECTS_WIDTH); buyStopOpenPriceEdit.Height(GUI_OBJECTS_HEIGHT); buyStopOpenPriceEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyStopOpenPriceEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyStopOpenPriceEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyStopOpenPriceEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyStopOpenPriceEdit); //--Create the buy stop sl edit to get the buy stop sl user input buyStopSlEdit.Create( 0, BUY_STOP_SL_EDIT_NAME, BUY_STOP_SL_EDIT_SUBWINDOW, BUY_STOP_SL_EDIT_X1, BUY_STOP_SL_EDIT_Y1, 0, 0 ); buyStopSlEdit.Text(IntegerToString(sl)); buyStopSlEdit.Width(int(GUI_OBJECTS_WIDTH / 1.4)); buyStopSlEdit.Height(GUI_OBJECTS_HEIGHT); buyStopSlEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyStopSlEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyStopSlEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyStopSlEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyStopSlEdit); //--Create the buy stop tp edit to get the buy stop tp user input buyStopTpEdit.Create( 0, BUY_STOP_TP_EDIT_NAME, BUY_STOP_TP_EDIT_SUBWINDOW, BUY_STOP_TP_EDIT_X1, BUY_STOP_TP_EDIT_Y1, 0, 0 ); buyStopTpEdit.Text(IntegerToString(tp)); buyStopTpEdit.Width(GUI_OBJECTS_WIDTH); buyStopTpEdit.Height(GUI_OBJECTS_HEIGHT); buyStopTpEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyStopTpEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyStopTpEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyStopTpEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyStopTpEdit); /*------------------------------------------------------ * Sell Stop Order GUI components creation **** *-----------------------------------------------------*/ //--Create the open sell stop button sellStopBtn.Create( 0, SELL_STOP_BTN_NAME, SELL_STOP_BTN_SUBWINDOW, SELL_STOP_BTN_X1, SELL_STOP_BTN_Y1, 0, 0 ); sellStopBtn.Text(SELL_STOP_BTN_TEXT); sellStopBtn.Width(GUI_OBJECTS_WIDTH); sellStopBtn.Height(GUI_OBJECTS_HEIGHT); sellStopBtn.Color(GUI_OBJECTS_SELL_BTN_COLOR); sellStopBtn.ColorBackground(GUI_OBJECTS_SELL_BTN_BG_COLOR); sellStopBtn.FontSize(GUI_OBJECTS_FONT_SIZE); mainPanelWindow.Add(sellStopBtn); //--Create the sell stop volume lot edit to get the sell stop volume/lot user input sellStopVolumeLotEdit.Create( 0, SELL_STOP_VOLUME_LOT_EDIT_NAME, SELL_STOP_VOLUME_LOT_EDIT_SUBWINDOW, SELL_STOP_VOLUME_LOT_EDIT_X1, SELL_STOP_VOLUME_LOT_EDIT_Y1, 0, 0 ); sellStopVolumeLotEdit.Text(DoubleToString(volumeLot)); sellStopVolumeLotEdit.Width(GUI_OBJECTS_WIDTH); sellStopVolumeLotEdit.Height(GUI_OBJECTS_HEIGHT); sellStopVolumeLotEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellStopVolumeLotEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellStopVolumeLotEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellStopVolumeLotEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellStopVolumeLotEdit); //--Create the sell stop price edit to get the sell stop opening price user input sellStopOpenPriceEdit.Create( 0, SELL_STOP_OPEN_PRICE_EDIT_NAME, SELL_STOP_OPEN_PRICE_EDIT_SUBWINDOW, SELL_STOP_OPEN_PRICE_EDIT_X1, SELL_STOP_OPEN_PRICE_EDIT_Y1, 0, 0 ); sellStopOpenPriceEdit.Text(DoubleToString(sellStopEntryPrice, int(symbolDigits))); sellStopOpenPriceEdit.Width(GUI_OBJECTS_WIDTH); sellStopOpenPriceEdit.Height(GUI_OBJECTS_HEIGHT); sellStopOpenPriceEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellStopOpenPriceEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellStopOpenPriceEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellStopOpenPriceEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellStopOpenPriceEdit); //--Create the sell stop sl edit to get the sell stop sl user input sellStopSlEdit.Create( 0, SELL_STOP_SL_EDIT_NAME, SELL_STOP_SL_EDIT_SUBWINDOW, SELL_STOP_SL_EDIT_X1, SELL_STOP_SL_EDIT_Y1, 0, 0 ); sellStopSlEdit.Text(IntegerToString(sl)); sellStopSlEdit.Width(int(GUI_OBJECTS_WIDTH / 1.4)); sellStopSlEdit.Height(GUI_OBJECTS_HEIGHT); sellStopSlEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellStopSlEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellStopSlEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellStopSlEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellStopSlEdit); //--Create the sell stop tp edit to get the sell stop tp user input sellStopTpEdit.Create( 0, SELL_STOP_TP_EDIT_NAME, SELL_STOP_TP_EDIT_SUBWINDOW, SELL_STOP_TP_EDIT_X1, SELL_STOP_TP_EDIT_Y1, 0, 0 ); sellStopTpEdit.Text(IntegerToString(tp)); sellStopTpEdit.Width(GUI_OBJECTS_WIDTH); sellStopTpEdit.Height(GUI_OBJECTS_HEIGHT); sellStopTpEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellStopTpEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellStopTpEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellStopTpEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellStopTpEdit); /*------------------------------------------------------ * Buy Limit Order GUI components creation **** *-----------------------------------------------------*/ //--Create the open buy limit button buyLimitBtn.Create( 0, BUY_LIMIT_BTN_NAME, BUY_LIMIT_BTN_SUBWINDOW, BUY_LIMIT_BTN_X1, BUY_LIMIT_BTN_Y1, 0, 0 ); buyLimitBtn.Text(BUY_LIMIT_BTN_TEXT); buyLimitBtn.Width(GUI_OBJECTS_WIDTH); buyLimitBtn.Height(GUI_OBJECTS_HEIGHT); buyLimitBtn.Color(GUI_OBJECTS_BUY_BTN_COLOR); buyLimitBtn.ColorBackground(GUI_OBJECTS_BUY_BTN_BG_COLOR); buyLimitBtn.FontSize(GUI_OBJECTS_FONT_SIZE); mainPanelWindow.Add(buyLimitBtn); //--Create the buy limit volume lot edit to get the buy limit volume/lot user input buyLimitVolumeLotEdit.Create( 0, BUY_LIMIT_VOLUME_LOT_EDIT_NAME, BUY_LIMIT_VOLUME_LOT_EDIT_SUBWINDOW, BUY_LIMIT_VOLUME_LOT_EDIT_X1, BUY_LIMIT_VOLUME_LOT_EDIT_Y1, 0, 0 ); buyLimitVolumeLotEdit.Text(DoubleToString(volumeLot)); buyLimitVolumeLotEdit.Width(GUI_OBJECTS_WIDTH); buyLimitVolumeLotEdit.Height(GUI_OBJECTS_HEIGHT); buyLimitVolumeLotEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyLimitVolumeLotEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyLimitVolumeLotEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyLimitVolumeLotEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyLimitVolumeLotEdit); //--Create the buy limit price edit to get the buy limit opening price user input buyLimitOpenPriceEdit.Create( 0, BUY_LIMIT_OPEN_PRICE_EDIT_NAME, BUY_LIMIT_OPEN_PRICE_EDIT_SUBWINDOW, BUY_LIMIT_OPEN_PRICE_EDIT_X1, BUY_LIMIT_OPEN_PRICE_EDIT_Y1, 0, 0 ); buyLimitOpenPriceEdit.Text(DoubleToString(buyLimitEntryPrice, int(symbolDigits))); buyLimitOpenPriceEdit.Width(GUI_OBJECTS_WIDTH); buyLimitOpenPriceEdit.Height(GUI_OBJECTS_HEIGHT); buyLimitOpenPriceEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyLimitOpenPriceEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyLimitOpenPriceEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyLimitOpenPriceEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyLimitOpenPriceEdit); //--Create the buy limit sl edit to get the buy limit sl user input buyLimitSlEdit.Create( 0, BUY_LIMIT_SL_EDIT_NAME, BUY_LIMIT_SL_EDIT_SUBWINDOW, BUY_LIMIT_SL_EDIT_X1, BUY_LIMIT_SL_EDIT_Y1, 0, 0 ); buyLimitSlEdit.Text(IntegerToString(sl)); buyLimitSlEdit.Width(int(GUI_OBJECTS_WIDTH / 1.4)); buyLimitSlEdit.Height(GUI_OBJECTS_HEIGHT); buyLimitSlEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyLimitSlEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyLimitSlEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyLimitSlEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyLimitSlEdit); //--Create the buy limit tp edit to get the buy limit tp user input buyLimitTpEdit.Create( 0, BUY_LIMIT_TP_EDIT_NAME, BUY_LIMIT_TP_EDIT_SUBWINDOW, BUY_LIMIT_TP_EDIT_X1, BUY_LIMIT_TP_EDIT_Y1, 0, 0 ); buyLimitTpEdit.Text(IntegerToString(tp)); buyLimitTpEdit.Width(GUI_OBJECTS_WIDTH); buyLimitTpEdit.Height(GUI_OBJECTS_HEIGHT); buyLimitTpEdit.Color(GUI_OBJECTS_BUY_EDIT_COLOR); buyLimitTpEdit.ColorBackground(GUI_OBJECTS_BUY_EDIT_BG_COLOR); buyLimitTpEdit.FontSize(GUI_OBJECTS_FONT_SIZE); buyLimitTpEdit.ColorBorder(GUI_OBJECTS_BUY_BTN_BG_COLOR); mainPanelWindow.Add(buyLimitTpEdit); /*------------------------------------------------------ * Sell Limit Order GUI components creation **** *-----------------------------------------------------*/ //--Create the open sell limit button sellLimitBtn.Create( 0, SELL_LIMIT_BTN_NAME, SELL_LIMIT_BTN_SUBWINDOW, SELL_LIMIT_BTN_X1, SELL_LIMIT_BTN_Y1, 0, 0 ); sellLimitBtn.Text(SELL_LIMIT_BTN_TEXT); sellLimitBtn.Width(GUI_OBJECTS_WIDTH); sellLimitBtn.Height(GUI_OBJECTS_HEIGHT); sellLimitBtn.Color(GUI_OBJECTS_SELL_BTN_COLOR); sellLimitBtn.ColorBackground(GUI_OBJECTS_SELL_BTN_BG_COLOR); sellLimitBtn.FontSize(GUI_OBJECTS_FONT_SIZE); mainPanelWindow.Add(sellLimitBtn); //--Create the sell limit volume lot edit to get the sell limit volume/lot user input sellLimitVolumeLotEdit.Create( 0, SELL_LIMIT_VOLUME_LOT_EDIT_NAME, SELL_LIMIT_VOLUME_LOT_EDIT_SUBWINDOW, SELL_LIMIT_VOLUME_LOT_EDIT_X1, SELL_LIMIT_VOLUME_LOT_EDIT_Y1, 0, 0 ); sellLimitVolumeLotEdit.Text(DoubleToString(volumeLot)); sellLimitVolumeLotEdit.Width(GUI_OBJECTS_WIDTH); sellLimitVolumeLotEdit.Height(GUI_OBJECTS_HEIGHT); sellLimitVolumeLotEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellLimitVolumeLotEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellLimitVolumeLotEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellLimitVolumeLotEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellLimitVolumeLotEdit); //--Create the sell limit price edit to get the sell limit opening price user input sellLimitOpenPriceEdit.Create( 0, SELL_LIMIT_OPEN_PRICE_EDIT_NAME, SELL_LIMIT_OPEN_PRICE_EDIT_SUBWINDOW, SELL_LIMIT_OPEN_PRICE_EDIT_X1, SELL_LIMIT_OPEN_PRICE_EDIT_Y1, 0, 0 ); sellLimitOpenPriceEdit.Text(DoubleToString(sellLimitEntryPrice, int(symbolDigits))); sellLimitOpenPriceEdit.Width(GUI_OBJECTS_WIDTH); sellLimitOpenPriceEdit.Height(GUI_OBJECTS_HEIGHT); sellLimitOpenPriceEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellLimitOpenPriceEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellLimitOpenPriceEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellLimitOpenPriceEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellLimitOpenPriceEdit); //--Create the sell limit sl edit to get the sell limit sl user input sellLimitSlEdit.Create( 0, SELL_LIMIT_SL_EDIT_NAME, SELL_LIMIT_SL_EDIT_SUBWINDOW, SELL_LIMIT_SL_EDIT_X1, SELL_LIMIT_SL_EDIT_Y1, 0, 0 ); sellLimitSlEdit.Text(IntegerToString(sl)); sellLimitSlEdit.Width(int(GUI_OBJECTS_WIDTH / 1.4)); sellLimitSlEdit.Height(GUI_OBJECTS_HEIGHT); sellLimitSlEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellLimitSlEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellLimitSlEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellLimitSlEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellLimitSlEdit); //--Create the sell limit tp edit to get the sell limit tp user input sellLimitTpEdit.Create( 0, SELL_LIMIT_TP_EDIT_NAME, SELL_LIMIT_TP_EDIT_SUBWINDOW, SELL_LIMIT_TP_EDIT_X1, SELL_LIMIT_TP_EDIT_Y1, 0, 0 ); sellLimitTpEdit.Text(IntegerToString(tp)); sellLimitTpEdit.Width(GUI_OBJECTS_WIDTH); sellLimitTpEdit.Height(GUI_OBJECTS_HEIGHT); sellLimitTpEdit.Color(GUI_OBJECTS_SELL_EDIT_COLOR); sellLimitTpEdit.ColorBackground(GUI_OBJECTS_SELL_EDIT_BG_COLOR); sellLimitTpEdit.FontSize(GUI_OBJECTS_FONT_SIZE); sellLimitTpEdit.ColorBorder(GUI_OBJECTS_SELL_BTN_BG_COLOR); mainPanelWindow.Add(sellLimitTpEdit); /*------------------------------------------------------------- * Status Labels and readonly edits GUI components creation **** *------------------------------------------------------------*/ //--Create the order magic status label magicOrderStatusLabel.Create( 0, MAGIC_ORDER_STATUS_LABEL_NAME, MAGIC_ORDER_STATUS_LABEL_SUBWINDOW, MAGIC_ORDER_STATUS_LABEL_X1, MAGIC_ORDER_STATUS_LABEL_Y1, GUI_OBJECTS_WIDTH, GUI_OBJECTS_HEIGHT ); magicOrderStatusLabel.Text(MAGIC_ORDER_STATUS_LABEL_TEXT + " - (Total Open Orders: " + (string(MagicOrdersTotal(magicNo))) + ")"); magicOrderStatusLabel.Color(STATUS_EDIT_COLOR); magicOrderStatusLabel.FontSize(STATUS_HEADER_FONT_SIZE); mainPanelWindow.Add(magicOrderStatusLabel); //--Create the magic order status edit to display the magic orders status magicOrdersStatusEdit.Create( 0, MAGIC_ORDER_STATUS_EDIT_NAME, MAGIC_ORDER_STATUS_EDIT_SUBWINDOW, MAGIC_ORDER_STATUS_EDIT_X1, MAGIC_ORDER_STATUS_EDIT_Y1, 0, 0 ); magicOrdersStatusEdit.ReadOnly(true); magicOrdersStatusEdit.Text(magicOrderStatus); magicOrdersStatusEdit.Width(STATUS_EDIT_WIDTH); magicOrdersStatusEdit.Height(GUI_OBJECTS_HEIGHT); magicOrdersStatusEdit.Color(STATUS_EDIT_COLOR); magicOrdersStatusEdit.ColorBackground(STATUS_EDIT_BG_COLOR); magicOrdersStatusEdit.FontSize(STATUS_EDIT_FONT_SIZE); magicOrdersStatusEdit.ColorBorder(STATUS_EDIT_BORDER_COLOR); mainPanelWindow.Add(magicOrdersStatusEdit); //--Create the delete all magic buy stops button deleteAllMagicBuyStopsBtn.Create( 0, DELETE_ALL_MAGIC_BUY_STOPS_BTN_NAME, DELETE_ALL_MAGIC_BUY_STOPS_BTN_SUBWINDOW, DELETE_ALL_MAGIC_BUY_STOPS_BTN_X1, DELETE_ALL_MAGIC_BUY_STOPS_BTN_Y1, 0, 0 ); deleteAllMagicBuyStopsBtn.Text(DELETE_ALL_MAGIC_BUY_STOPS_BTN_TEXT); deleteAllMagicBuyStopsBtn.Width(DELETE_ORDERS_BTN_WIDTH); deleteAllMagicBuyStopsBtn.Height(GUI_OBJECTS_HEIGHT); deleteAllMagicBuyStopsBtn.Color(DELETE_ORDERS_BTN_COLOR); deleteAllMagicBuyStopsBtn.ColorBackground(DELETE_BUY_ORDERS_BTN_BG_COLOR); deleteAllMagicBuyStopsBtn.ColorBorder(DELETE_ORDERS_BTN_BORDER_COLOR); deleteAllMagicBuyStopsBtn.FontSize(DELETE_ORDERS_BTN_FONT_SIZE); mainPanelWindow.Add(deleteAllMagicBuyStopsBtn); //--Create the delete all magic sell stops button deleteAllMagicSellStopsBtn.Create( 0, DELETE_ALL_MAGIC_SELL_STOPS_BTN_NAME, DELETE_ALL_MAGIC_SELL_STOPS_BTN_SUBWINDOW, DELETE_ALL_MAGIC_SELL_STOPS_BTN_X1, DELETE_ALL_MAGIC_SELL_STOPS_BTN_Y1, 0, 0 ); deleteAllMagicSellStopsBtn.Text(DELETE_ALL_MAGIC_SELL_STOPS_BTN_TEXT); deleteAllMagicSellStopsBtn.Width(DELETE_ORDERS_BTN_WIDTH); deleteAllMagicSellStopsBtn.Height(GUI_OBJECTS_HEIGHT); deleteAllMagicSellStopsBtn.Color(DELETE_ORDERS_BTN_COLOR); deleteAllMagicSellStopsBtn.ColorBackground(DELETE_SELL_ORDERS_BTN_BG_COLOR); deleteAllMagicSellStopsBtn.ColorBorder(DELETE_ORDERS_BTN_BORDER_COLOR); deleteAllMagicSellStopsBtn.FontSize(DELETE_ORDERS_BTN_FONT_SIZE); mainPanelWindow.Add(deleteAllMagicSellStopsBtn); //--Create the delete all magic buy limits button deleteAllMagicBuyLimitsBtn.Create( 0, DELETE_ALL_MAGIC_BUY_LIMITS_BTN_NAME, DELETE_ALL_MAGIC_BUY_LIMITS_BTN_SUBWINDOW, DELETE_ALL_MAGIC_BUY_LIMITS_BTN_X1, DELETE_ALL_MAGIC_BUY_LIMITS_BTN_Y1, 0, 0 ); deleteAllMagicBuyLimitsBtn.Text(DELETE_ALL_MAGIC_BUY_LIMITS_BTN_TEXT); deleteAllMagicBuyLimitsBtn.Width(DELETE_ORDERS_BTN_WIDTH); deleteAllMagicBuyLimitsBtn.Height(GUI_OBJECTS_HEIGHT); deleteAllMagicBuyLimitsBtn.Color(DELETE_ORDERS_BTN_COLOR); deleteAllMagicBuyLimitsBtn.ColorBackground(DELETE_BUY_ORDERS_BTN_BG_COLOR); deleteAllMagicBuyLimitsBtn.ColorBorder(DELETE_ORDERS_BTN_BORDER_COLOR); deleteAllMagicBuyLimitsBtn.FontSize(DELETE_ORDERS_BTN_FONT_SIZE); mainPanelWindow.Add(deleteAllMagicBuyLimitsBtn); //--Create the delete all magic sell limits button deleteAllMagicSellLimitsBtn.Create( 0, DELETE_ALL_MAGIC_SELL_LIMITS_BTN_NAME, DELETE_ALL_MAGIC_SELL_LIMITS_BTN_SUBWINDOW, DELETE_ALL_MAGIC_SELL_LIMITS_BTN_X1, DELETE_ALL_MAGIC_SELL_LIMITS_BTN_Y1, 0, 0 ); deleteAllMagicSellLimitsBtn.Text(DELETE_ALL_MAGIC_SELL_LIMITS_BTN_TEXT); deleteAllMagicSellLimitsBtn.Width(DELETE_ORDERS_BTN_WIDTH); deleteAllMagicSellLimitsBtn.Height(GUI_OBJECTS_HEIGHT); deleteAllMagicSellLimitsBtn.Color(DELETE_ORDERS_BTN_COLOR); deleteAllMagicSellLimitsBtn.ColorBackground(DELETE_SELL_ORDERS_BTN_BG_COLOR); deleteAllMagicSellLimitsBtn.ColorBorder(DELETE_ORDERS_BTN_BORDER_COLOR); deleteAllMagicSellLimitsBtn.FontSize(DELETE_ORDERS_BTN_FONT_SIZE); mainPanelWindow.Add(deleteAllMagicSellLimitsBtn); //--Create the delete all magic orders button deleteAllMagicOrdersBtn.Create( 0, DELETE_ALL_MAGIC_ORDERS_BTN_NAME, DELETE_ALL_MAGIC_ORDERS_BTN_SUBWINDOW, DELETE_ALL_MAGIC_ORDERS_BTN_X1, DELETE_ALL_MAGIC_ORDERS_BTN_Y1, 0, 0 ); deleteAllMagicOrdersBtn.Text(DELETE_ALL_MAGIC_ORDERS_BTN_TEXT); deleteAllMagicOrdersBtn.Width(STATUS_EDIT_WIDTH); deleteAllMagicOrdersBtn.Height(GUI_OBJECTS_HEIGHT); deleteAllMagicOrdersBtn.Color(DELETE_ORDERS_BTN_COLOR); deleteAllMagicOrdersBtn.ColorBackground(DELETE_ALL_ORDERS_BTN_BG_COLOR); deleteAllMagicOrdersBtn.ColorBorder(DELETE_ORDERS_BTN_BORDER_COLOR); deleteAllMagicOrdersBtn.FontSize(DELETE_ORDERS_BTN_FONT_SIZE); mainPanelWindow.Add(deleteAllMagicOrdersBtn); //--Call the Run() method to load the main panel window mainPanelWindow.Run(); }
Теперь нам нужно обнаружить любые нажатия кнопок или активации путем заполнения функции OnChartEvent(...). Эта функция будет служить обработчиком событий для всех взаимодействий пользователя, что сделает ее основным компонентом отзывчивости нашей панели. В этом разделе мы будем вызывать импортированные функции прототипа из библиотеки PendingOrdersManager.ex5, что позволит нам управлять отложенными ордерами в зависимости от введенных пользователем данных. Например, если пользователь нажимает кнопку, чтобы разместить новый отложенный ордер, будет запущена соответствующая библиотечная функция для выполнения операции.
Для дальнейшего улучшения пользовательского опыта работы с панелью отложенных ордеров мы также интегрируем звуковую обратную связь. Результат действия, например, успешное размещение ордера или ошибка, будет сопровождаться тем или иным звуком. Это обеспечивает обратную связь в режиме реального времени и добавляет дополнительный уровень интерактивности, делая панель более интуитивно понятной и удобной для пользователя. Сочетание визуальных и звуковых сигналов позволит пользователям легко отслеживать статус своих действий и реагировать соответствующим образом.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--Detect any clicks or events performed to the orders panel window and make it moveable mainPanelWindow.ChartEvent(id, lparam, dparam, sparam); //--Detect any click events on the chart if(id == CHARTEVENT_OBJECT_CLICK) { //--Detect when the buyStopBtn is clicked and open a new buy stop order if(sparam == buyStopBtn.Name()) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Opening a new Buy Stop Order with the details below: "); Print("Volume: ", buyStopVolumeLotEdit.Text()); Print("Open Price: ", buyStopOpenPriceEdit.Text()); Print("Sl (Pips): ", buyStopSlEdit.Text()); Print("Tp (Pips): ", buyStopTpEdit.Text()); if( OpenBuyStop( magicNo, _Symbol, StringToDouble(buyStopOpenPriceEdit.Text()), StringToDouble(buyStopVolumeLotEdit.Text()), (uint)StringToInteger(buyStopSlEdit.Text()), (uint)StringToInteger(buyStopTpEdit.Text()), "EX5 PendingOrdersManager Panel" ) ) { PlaySound("ok.wav");//-- Order placed ok } else { PlaySound("alert2.wav");//-- Order failed } } //--Detect when the sellStopBtn is clicked and open a new sell stop order if(sparam == sellStopBtn.Name()) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Opening a new Sell Stop Order with the details below: "); Print("Volume: ", sellStopVolumeLotEdit.Text()); Print("Open Price: ", sellStopOpenPriceEdit.Text()); Print("Sl (Pips): ", sellStopSlEdit.Text()); Print("Tp (Pips): ", sellStopTpEdit.Text()); if( OpenSellStop( magicNo, _Symbol, StringToDouble(sellStopOpenPriceEdit.Text()), StringToDouble(sellStopVolumeLotEdit.Text()), (uint)StringToInteger(sellStopSlEdit.Text()), (uint)StringToInteger(sellStopTpEdit.Text()), "EX5 PendingOrdersManager Panel" ) ) { PlaySound("ok.wav");//-- Order placed ok } else { PlaySound("alert2.wav");//-- Order failed } } //--Detect when the buyLimitBtn is clicked and open a new buy limit order if(sparam == buyLimitBtn.Name()) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Opening a new Buy Limit Order with the details below: "); Print("Volume: ", buyLimitVolumeLotEdit.Text()); Print("Open Price: ", buyLimitOpenPriceEdit.Text()); Print("Sl (Pips): ", buyLimitSlEdit.Text()); Print("Tp (Pips): ", buyLimitTpEdit.Text()); if( OpenBuyLimit( magicNo, _Symbol, StringToDouble(buyLimitOpenPriceEdit.Text()), StringToDouble(buyLimitVolumeLotEdit.Text()), (uint)StringToInteger(buyLimitSlEdit.Text()), (uint)StringToInteger(buyLimitTpEdit.Text()), "EX5 PendingOrdersManager Panel" ) ) { PlaySound("ok.wav");//-- Order placed ok } else { PlaySound("alert2.wav");//-- Order failed } } //--Detect when the sellLimitBtn is clicked and open a new sell limit order if(sparam == sellLimitBtn.Name()) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Opening a new Sell Limit Order with the details below: "); Print("Volume: ", sellLimitVolumeLotEdit.Text()); Print("Open Price: ", sellLimitOpenPriceEdit.Text()); Print("Sl (Pips): ", sellLimitSlEdit.Text()); Print("Tp (Pips): ", sellLimitTpEdit.Text()); if( OpenSellLimit( magicNo, _Symbol, StringToDouble(sellLimitOpenPriceEdit.Text()), StringToDouble(sellLimitVolumeLotEdit.Text()), (uint)StringToInteger(sellLimitSlEdit.Text()), (uint)StringToInteger(sellLimitTpEdit.Text()), "EX5 PendingOrdersManager Panel" ) ) { PlaySound("ok.wav");//-- Order placed ok } else { PlaySound("alert2.wav");//-- Order failed } } //--Detect when the deleteAllMagicBuyStopsBtn is clicked and delete all the specified orders if(sparam == deleteAllMagicBuyStopsBtn.Name() && MagicBuyStopOrdersTotal(magicNo) > 0) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Deleting all the buy stop orders with magic number: ", magicNo); if(DeleteAllBuyStops("", magicNo)) { PlaySound("ok.wav");//-- Orders deleted ok } else { PlaySound("alert2.wav");//-- Order deleting failed } } //--Detect when the deleteAllMagicSellStopsBtn is clicked and delete all the specified orders if(sparam == deleteAllMagicSellStopsBtn.Name() && MagicSellStopOrdersTotal(magicNo) > 0) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Deleting all the sell stop orders with magic number: ", magicNo); if(DeleteAllSellStops("", magicNo)) { PlaySound("ok.wav");//-- Orders deleted ok } else { PlaySound("alert2.wav");//-- Order deleting failed } } //--Detect when the deleteAllMagicBuyLimitsBtn is clicked and delete all the specified orders if(sparam == deleteAllMagicBuyLimitsBtn.Name() && MagicBuyLimitOrdersTotal(magicNo) > 0) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Deleting all the buy limit orders with magic number: ", magicNo); if(DeleteAllBuyLimits("", magicNo)) { PlaySound("ok.wav");//-- Orders deleted ok } else { PlaySound("alert2.wav");//-- Order deleting failed } } //--Detect when the deleteAllMagicSellLimitsBtn is clicked and delete all the specified orders if(sparam == deleteAllMagicSellLimitsBtn.Name() && MagicSellLimitOrdersTotal(magicNo) > 0) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Deleting all the sell limit orders with magic number: ", magicNo); if(DeleteAllSellLimits("", magicNo)) { PlaySound("ok.wav");//-- Orders deleted ok } else { PlaySound("alert2.wav");//-- Order deleting failed } } //--Detect when the deleteAllMagicOrdersBtn is clicked and delete all the specified orders if(sparam == deleteAllMagicOrdersBtn.Name() && MagicOrdersTotal(magicNo) > 0) { Print(__FUNCTION__, " CHARTEVEN_OBJECT_CLICK: ", sparam); Print("Deleting all the open peding orders with magic number: ", magicNo); if(DeleteAllMagicOrders(magicNo)) { PlaySound("ok.wav");//-- Orders deleted ok } else { PlaySound("alert2.wav");//-- Order deleting failed } } } }
Сразу после загрузки советник автоматически заполняет поля объема/лота, цен входа, стоп-лосса (SL) и тейк-профита (TP)предопределенными значениями на основе текущего спреда. Эти значения предоставляют пользователю отправную точку для размещения ордера, оптимизируя процесс торговли и сводя к минимуму ручной ввод данных. Кроме того, кнопки удаления ордеров, расположенные под статусами ордеров по магическому числу, изначально отключены, если не обнаружено отложенных или активных ордеров, соответствующих определенному магическому номеру советника. Как только советник обнаружит совпадающие ордера, кнопки активируются и изменят цвет, сигнализируя о том, что теперь они готовы к работе и выполнению команд удаления.
Когда советник обнаруживает, что открываются ордера, соответствующие указанному магическому числу, кнопки удаления ордеров активируются, меняя цвет, что указывает на то, что они включены и могут быть использованы.
Для реализации этой функции нам необходимо добавить следующий код в функцию OnTick(). Это позволит нам использовать импортированные функции EX5-библиотеки для постоянного контроля и обновления графического пользовательского интерфейса в реальном времени, гарантируя его синхронизацию со статусом ордеров на каждом входящем тике.
void OnTick() { //--- magicOrderStatus = " Buy Stops: " + (string(MagicBuyStopOrdersTotal(magicNo))) + ", Sell Stops: " + (string(MagicSellStopOrdersTotal(magicNo))) + ", Buy Limits: " + (string(MagicBuyLimitOrdersTotal(magicNo))) + ", Sell Limits: " + (string(MagicSellLimitOrdersTotal(magicNo))) + " "; magicOrderStatusLabel.Text(MAGIC_ORDER_STATUS_LABEL_TEXT + (string(MagicOrdersTotal(magicNo)))); magicOrdersStatusEdit.Text(magicOrderStatus); //-- Disable and change the background color of the deleteAllMagicBuyStopsBtn depending on the open orders status if(MagicBuyStopOrdersTotal(magicNo) == 0) { deleteAllMagicBuyStopsBtn.Disable(); deleteAllMagicBuyStopsBtn.ColorBackground(clrLightSlateGray); } else { deleteAllMagicBuyStopsBtn.Enable(); deleteAllMagicBuyStopsBtn.ColorBackground(DELETE_BUY_ORDERS_BTN_BG_COLOR); } //-- Disable and change the background color of the deleteAllMagicSellStopsBtn depending on the open orders status if(MagicSellStopOrdersTotal(magicNo) == 0) { deleteAllMagicSellStopsBtn.Disable(); deleteAllMagicSellStopsBtn.ColorBackground(clrLightSlateGray); } else { deleteAllMagicSellStopsBtn.Enable(); deleteAllMagicSellStopsBtn.ColorBackground(DELETE_SELL_ORDERS_BTN_BG_COLOR); } //-- Disable and change the background color of the deleteAllMagicBuyLimitsBtn depending on the open orders status if(MagicBuyLimitOrdersTotal(magicNo) == 0) { deleteAllMagicBuyLimitsBtn.Disable(); deleteAllMagicBuyLimitsBtn.ColorBackground(clrLightSlateGray); } else { deleteAllMagicBuyLimitsBtn.Enable(); deleteAllMagicBuyLimitsBtn.ColorBackground(DELETE_BUY_ORDERS_BTN_BG_COLOR); } //-- Disable and change the background color of the deleteAllMagicSellLimitsBtn depending on the open orders status if(MagicSellLimitOrdersTotal(magicNo) == 0) { deleteAllMagicSellLimitsBtn.Disable(); deleteAllMagicSellLimitsBtn.ColorBackground(clrLightSlateGray); } else { deleteAllMagicSellLimitsBtn.Enable(); deleteAllMagicSellLimitsBtn.ColorBackground(DELETE_SELL_ORDERS_BTN_BG_COLOR); } //-- Disable and change the background color of the deleteAllMagicOrdersBtn depending on the open orders status if(MagicOrdersTotal(magicNo) == 0) { deleteAllMagicOrdersBtn.Disable(); deleteAllMagicOrdersBtn.ColorBackground(clrLightSlateGray); } else { deleteAllMagicOrdersBtn.Enable(); deleteAllMagicOrdersBtn.ColorBackground(DELETE_ALL_ORDERS_BTN_BG_COLOR); } }
Наконец, мы должны убедиться, что все ресурсы будут надлежащим образом освобождены и очищены после завершения работы советника. Для этого добавим следующий код в функцию OnDeinit(...).
void OnDeinit(const int reason) { //--- //-- Delete and garbage collect the graphical user interface and other graphical objects mainPanelWindow.Destroy(); //-- Clear any chart comments Comment(""); }
Файл PendingOrdersPanel.mq5 приложен в конце статьи.
Заключение
Мы создали разноплановую EX5-библиотеку для управления отложенными ордерами, позволяющую открывать, изменять, удалять и сортировать разные типы отложенных ордеров. Эта библиотека является полезным ресурсом для любого MQL5-разработчика, которому нужен гибкий и простой в использовании инструмент для управления отложенными ордерами, позволяющий быстро получать информацию о состоянии ордеров или выполнять действия по ним с помощью простого вызова функции.
Библиотека богата функциями и поставляется с понятной документацией и реальными примерами. В следующей статье мы применим аналогичный метод для создания EX5-библиотеки для управления историей (History Management EX5 library), которая значительно упростит обработку истории сделок и ордеров в MQL5.
Спасибо за внимание! Желаю вам всяческих успехов в торговле и программировании на MQL5!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15888
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования