
Торговый инструментарий MQL5 (Часть 2): Расширение и применение EX5-библиотеки для управления позициями
Введение
В первой статье мы подробно проанализировали библиотеки кода MQL5. Мы рассмотрели различные типы библиотек, их преимущества, создание EX5-библиотек и компоненты файла исходного кода библиотеки (.mq5). Это дало нам прочную основу для изучения EX5-библиотек и процесса их создания. Затем мы создали практический пример EX5-библиотеки управления позициями, демонстрирующий, как реализовывать экспортируемые функции в MQL5-коде.
В этой статье мы расширим EX5-библиотеку для управления позициями и создадим два базовых советника. Один из этих примеров советников будет использовать графическую торговую и информационную панель, демонстрируя, как импортировать и внедрять EX5-библиотеку для управления позициями на практике. Это послужит реальным примером того, как создать и интегрировать EX5-библиотеку в ваш код MQL5. Для начала разберем процесс импортирования и использования уже разработанной и скомпилированной двоичной библиотеки .ex5.
Как импортировать и использовать EX5-библиотеку
Для импорта и использования EX5-библиотеки в вашем MQL5-коде (советники, пользовательские индикаторы, скрипты или сервисы), необходимо добавить директивы #import под директивами #property в заголовке или верхней части файла исходного кода. Чтобы включить скомпилированную бинарную библиотеку, начните с указания директивы#import, за которой следует путь к файлу, где хранится библиотека. По умолчанию MQL5 ищет библиотеки в двух местах, чтобы сэкономить время на обращение к ним напрямую в коде. Первое место — это папка MQL5/Libraries, которая является предопределенным местом по умолчанию для хранения библиотек. Если библиотека там не найдена, MQL5 выполнит поиск в папке, где находится сама MQL-программа. Если ваша EX5-библиотека хранится непосредственно в папке MQL5/Libraries/ или в той же папке, что и исходный код, просто укажите имя библиотеки, заключенное в двойные кавычки, после директивы #import, не указывая путь к папке.
После указания пути к папке библиотеки укажите библиотеки, а затем расширение .ex5. На следующей новой строке добавьте определения или описания всех экспортированных прототипов функций, которые необходимо импортировать в ваш код. Наконец, завершите сегмент кода импорта другой директивой #import для закрытия.
#import "FilePath/LibraryName.ex5" //-- Opening .EX5 Library import directive //-- Function definitions/descriptions prototypes int FunctionPrototype1(); void FunctionPrototype2(bool y); bool FunctionPrototype3(double x); #import //--- Closing .EX5 Library import directive
При объявлении директивы import необходимо указать расширение .ex5 после имени библиотеки. Если не указывать расширение, это будет означать, что вы импортируете библиотеку .DLL по умолчанию.
Вы также можете импортировать и реализовать несколько .ex5-библиотек в одном файле MQL5. Структура кода для импорта нескольких .ex5-библиотек похожа на импорт одной библиотеки. Единственное отличие - расположение закрывающих директив #import. Для импорта нескольких библиотек за закрывающей директивой #import первой библиотеки должно следовать имя следующей импортируемой .ex5-библиотеки. Это закроет первую директиву import, одновременно инициируя следующую и так далее. При закрытии последней директивы import последней библиотеки убедитесь, что она заканчивается без имени библиотеки.
#import "FilePath/LibraryName.ex5" //-- Opening .EX5 Library import directive //-- Function definitions/descriptions prototypes for the first library here int FunctionPrototype1(); void FunctionPrototype2(bool y); #import "FilePath/SecondLibraryName.ex5" //-- Function definitions/descriptions prototypes for the second library here bool FunctionPrototype(); string FunctionPrototype2(bool z); #import //--- Closing .EX5 Library import directive
При работе с несколькими библиотеками в MQL5 необходимо дать каждой уникальное имя. Неважно, хранятся ли все эти библиотеки в разных папках, наличие разных имен является обязательным условием, чтобы не возникало ошибок.
Каждая библиотека создает свою собственную изолированную среду или "пространство имен" (namepsace). Это означает, что функции внутри библиотеки связаны с именем этой библиотеки. Вы можете свободно называть функции внутри библиотеки, не беспокоясь о конфликтах, даже если они совпадают с именами встроенных функций. Однако обычно рекомендуется избегать подобных наименований для большей ясности.
Если в разных библиотеках есть функции с одинаковыми именами, система отдаст приоритет функциям на основе определенных правил. Это предотвращает путаницу при вызове функций с одинаковыми именами. После успешного импорта прототипов функций библиотеки вы можете легко интегрировать их в свой код и обрабатывать их так же, как и любые другие локальные функции, которые вы определили самостоятельно.
Далее в статье я подробно объясняю, как внедрять и использовать EX5-библиотеки на практике. Вы найдете две подробные демонстрации: в одной мы пишем код советника на основе торговой стратегии VIDyA, а в другой — с использованием графического пользовательского интерфейса (GUI). Эти советники будут интегрировать и использовать нашу специально разработанную EX5-библиотеку для управления позициями. Эти практические примеры предоставят ценную информацию о внедрении EX5-библиотек в реальные советники.
Распространенные ошибки выполнения EX5-библиотеки
Отладка EX5-библиотек может оказаться сложной задачей, поскольку наиболее распространенные ошибки, связанные с импортированными функциями прототипа, возникают во время выполнения при загрузке окончательно скомпилированного MQL5-приложения в торговый терминал. Эти ошибки обычно возникают из-за ошибок в директивах import, в частности - в путях или именах файлов библиотеки, описаниях прототипов функций, типах, именах, полных списках параметров и возвращаемых значениях во время объявлений import. Перед компилятором не стоит задача обнаруживать эти ошибки декларации импорта во время компиляции, поскольку он не может получить доступ к исходному коду импортированной библиотеки, так как она инкапсулирована и уже скомпилирована в двоичный исполняемый формат (.ex5).
Любой файл исходного кода, содержащий эти ошибки, будет успешно скомпилирован, но при попытке загрузить скомпилированное MQL5-приложение в торговый терминал возникнут ошибки выполнения. Эти ошибки отображаются либо на вкладке "Эксперты" или "Журнал" терминала MetaTrader 5. Вот наиболее распространенные ошибки:
Unresolved Import Function Call: (cannot find 'Function_Name' in 'Library_Name.ex5')
- Описание: Эта ошибка выполнения возникает при попытке загрузить приложение MQL5 на график MetaTrader 5 и отображается на вкладке "Эксперты". Ошибка вызвана неправильными определениями или описаниями прототипов функций, такими как тип, имя или параметры, предоставленными в директив import библиотеки.
- Решение: Убедитесь, что сегмент кода import библиотеки содержит правильные определения прототипов функций и перекомпилируйте ваш код.
Cannot Open File 'Library_Name.ex5': (loading of ExpertAdvisor_Name (GBPJPY,M15) failed [0])
- Описание: Эта ошибка выполнения возникает при попытке загрузить приложение MQL5 на график MetaTrader 5 и отображается на вкладке "Журнал". Ошибка возникает, когда импортированный файл EX5-библиотеки не может быть найден и загружен.
- Решение: Убедитесь, что сегмент кода import содержит правильный путь к библиотеке и перекомпилируйте код.
Хотя при работе с импортированными библиотеками в MQL5 могут возникать и другие ошибки, указанные выше ошибки выполнения являются наиболее распространенными среди начинающих разработчиков. Эти ошибки легко пропустить и они не предназначены для обнаружения компилятором во время компиляции.
Как обновлять и повторно разворачивать EX5-библиотеки
Важно соблюдать правильную последовательность при повторном развертывании EX5-библиотек после каждого обновления, чтобы гарантировать, что новые изменения будут правильно интегрированы в проекты MQL5, использующие библиотеку. Последовательность компиляции является наиболее важным шагом в обновлении и повторном развертывании библиотек в MQL5. Выполните следующие действия, чтобы гарантировать, что все новые изменения и обновления будут использованы во всех проектах, импортирующих библиотеку:
- Скомпилируйте новый EX5-файл: Начните с компиляции обновленного файла исходного кода библиотеки .mq5 для создания нового исполняемого двоичного файла .ex5.
- Обновите импортируемые прототипы функций: Во всех проектах MQL5, использующих EX5-библиотеку, обновите все определения import прототипов функций, если они изменились в очередном обновлении .ex5-библиотеки.
- Скомпилируйте проекты: Перекомпилируйте все MQL5-проекты, реализующие EX5-библиотеку.
Функция трейлинга уровня стоп-лосс
Прежде чем мы сможем реализовать нашу библиотеку для управления позициями, давайте расширим ее, добавив несколько важных функций. Начнем с добавления модуля или функции управления трейлинг-стоп-лоссом, поскольку наша библиотека не будет полной без этой важной функции. Трейлинг-стоп является важной частью любой торговой стратегии, поскольку при правильной реализации он может увеличить прибыльность системы и общий уровень успеха.
Назовем функцию трейлинг-стоп-лосса SetTrailingStopLoss(). Она будет отвечать за установку скользящего стоп-уровня для открытой позиции с использованием тикета позиции в качестве механизма фильтрации. Она возьмет номер тикета позиции и желаемый скользящий стоп-лосс в пипсах (пунктах) в качестве аргументов или параметров и попытается обновить стоп-лосс позиции на торговом сервере при выполнении определенных условий. Функцию следует вызывать непрерывно на каждом тике, чтобы изменять скользящий стоп-лосс в режиме реального времени, поскольку статус целевых позиций постоянно меняется.
Сначала функция проверяет, разрешена ли торговля и действителен ли указанный скользящий стоп-лосс в пипсах (пунктах). Затем она выберет позицию, извлечет и сохранит всю необходимую информацию о символе и рассчитает цену трейлинг-стоп-лосса. Если рассчитанная цена верна, она отправит на торговый сервер приказ на установку стоп-лосса. Если ордер успешно выполнен, функция вернет true, если нет - false.
Начнем с определения функции. Функция трейлинг-стоп-лосса будет иметь тип bool и будет содержать два параметра:
- ulong positionTicket - уникальный идентификатор позиции, которую мы изменим.
- int trailingStopLoss - желаемый уровень стоп-лосса в пипсах (пунктах) от текущей цены позиции.
Ключевое слово export указывает, что эту библиотечную функцию можно вызвать из любого файла исходного кода MQL5 или проекта, который ее импортирует.
bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss) export { //-- place the function body here }
Нам нужно проверить, разрешена ли торговля, а также то, что параметр trailingStopLoss выше нуля. Если какое-либо условие не выполняется, мы выходим из функции и возвращаем false для прекращения операции.
if(!TradingIsAllowed() || trailingStopLoss == 0) { return(false); //--- algo trading is disabled or trailing stop loss is invalid, exit function }
Далее подтверждаем и выбираем позицию, используя предоставленный positionTicket. Если выбрать позицию не удалось, выводим сообщение об ошибке и выходим из функции.
//--- Confirm and select the position using the provided positionTicket ResetLastError(); //--- Reset error cache incase of ticket selection errors if(!PositionSelectByTicket(positionTicket)) { //---Position selection failed Print("\r\n_______________________________________________________________________________________"); Print(__FUNCTION__, ": Selecting position with ticket:", positionTicket, " failed. ERROR: ", GetLastError()); return(false); //-- Exit the function }
Затем создаем несколько переменных, которые помогут нам хранить и проверять скользящий стоп-лосс. Начнем с создания переменной slPrice для хранения рассчитанной цены трейлинг-стоп-лосса, а затем сохраним свойства позиции, такие как символ, цена входа, объем, текущие цены стоп-лосса и тейк-профита, а также тип позиции.
//-- create variable to store the calculated trailing sl prices to send to the trade server double slPrice = 0.0; //--- Position ticket selected, save the position properties string positionSymbol = PositionGetString(POSITION_SYMBOL); double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); double volume = PositionGetDouble(POSITION_VOLUME); double currentPositionSlPrice = PositionGetDouble(POSITION_SL); double currentPositionTpPrice = PositionGetDouble(POSITION_TP); ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
Аналогичным образом мы продолжаем сохранять различные свойства символа, связанные с выбранной позицией. Эти свойства также будут использоваться позже для проверки и расчета трейлинг-стоп-лосса.
//-- Get some information about the positions symbol int symbolDigits = (int)SymbolInfoInteger(positionSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places int symbolStopLevel = (int)SymbolInfoInteger(positionSymbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(positionSymbol, SYMBOL_POINT); double positionPriceCurrent = PositionGetDouble(POSITION_PRICE_CURRENT); int spread = (int)SymbolInfoInteger(positionSymbol, SYMBOL_SPREAD);
Проверяем меньше ли указанное значение стоп-лосса, чем стоп-уровень символа. Если да, корректируем трейлинг-стоп-лосс так, чтобы он был равен стоп-уровню символа.
//-- Check if the trailing stop loss is less than the symbol trade stop levels if(trailingStopLoss < symbolStopLevel) { //-- Trailing stop loss is less than the allowed level for the current symbol trailingStopLoss = symbolStopLevel; //-- Set it to the symbol stop level by default }
Следующий шаг включает расчет цены скользящего стоп-лосса на основе того, является ли позиция покупкой или продажей. Для позиций на покупку цена стоп-лосса устанавливается ниже текущей цены, а для позиций на продажу — выше текущей цены. Мы также проверяем, находится ли рассчитанная цена стоп-лосса в допустимых пределах.
//-- Calculate and store the trailing stop loss price if(positionType == POSITION_TYPE_BUY) { slPrice = positionPriceCurrent - (trailingStopLoss * symbolPoint); //-- Check if the proposed slPrice for the trailing stop loss is valid if(slPrice < entryPrice || slPrice < currentPositionSlPrice) { return(false); //-- Exit the function, proposed trailing stop loss price is invalid } } else //-- SELL POSITION { slPrice = positionPriceCurrent + (trailingStopLoss * symbolPoint); //-- Check if the proposed slPrice for the trailing stop loss is valid if(slPrice > entryPrice || slPrice > currentPositionSlPrice) { return(false); //-- Exit the function, proposed trailing stop loss price is invalid } }
Перед установкой трейлинг-стоп-лосса давайте выведем данные позиции в журнале MetaTrader 5. Сюда входят символ, тип позиции, объем, цена входа, текущие цены стоп-лосса и тейк-профита, а также другая важная информация.
//-- Print position properties before setting the trailing stop loss string positionProperties = "--> " + positionSymbol + " " + EnumToString(positionType) + " Trailing Stop Loss Modification Details" + " <--\r\n"; positionProperties += "------------------------------------------------------------\r\n"; positionProperties += "Ticket: " + (string)positionTicket + "\r\n"; positionProperties += "Volume: " + StringFormat("%G", volume) + "\r\n"; positionProperties += "Price Open: " + StringFormat("%G", entryPrice) + "\r\n"; positionProperties += "Current SL: " + StringFormat("%G", currentPositionSlPrice) + " -> New Trailing SL: " + (string)slPrice + "\r\n"; positionProperties += "Current TP: " + StringFormat("%G", currentPositionTpPrice) + "\r\n"; positionProperties += "Comment: " + PositionGetString(POSITION_COMMENT) + "\r\n"; positionProperties += "Magic Number: " + (string)PositionGetInteger(POSITION_MAGIC) + "\r\n"; positionProperties += "---"; Print(positionProperties);
Сбрасываем структуры tradeRequest и tradeResult до нуля. Затем мы инициализируем параметры, необходимые для установки стоп-лосса и тейк-профита.
//-- 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_SLTP; //-- Trade operation type for setting sl and tp tradeRequest.position = positionTicket; tradeRequest.symbol = positionSymbol; tradeRequest.sl = slPrice; tradeRequest.tp = currentPositionTpPrice;
Наконец, мы сбрасываем кэш ошибок и отправляем ордер на торговый сервер до тех пор, пока он не будет успешно выполнен или пока не будет выполнена 101 повторная попытка. Если ордер успешно выполнен, мы выводим сообщение об этом, возвращаем true и выходим из функции. Если запрос ордера не выполнен, обрабатываем ошибку, возвращаем false и выходим из функции.
ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function for(int loop = 0; loop <= 100; loop++) //-- try modifying the sl and tp 101 times untill 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 set the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType)); 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__, positionSymbol, tradeResult.retcode) || IsStopped()) { PrintFormat("ERROR setting the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType)); Print("_______________________________________________________________________________________\r\n\r\n"); return(false); //-- exit function break; //-- exit for loop } } } return(false); }
Убедитесь, что сегменты кода функции SetTrailingStopLoss() идут в следующей последовательности:
bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss) export { //-- first check if the EA is allowed to trade and the trailing stop loss parameter is more than zero if(!TradingIsAllowed() || trailingStopLoss == 0) { return(false); //--- algo trading is disabled or trailing stop loss is invalid, exit function } //--- Confirm and select the position using the provided positionTicket ResetLastError(); //--- Reset error cache incase of ticket selection errors if(!PositionSelectByTicket(positionTicket)) { //---Position selection failed Print("\r\n_______________________________________________________________________________________"); Print(__FUNCTION__, ": Selecting position with ticket:", positionTicket, " failed. ERROR: ", GetLastError()); return(false); //-- Exit the function } //-- create variable to store the calculated trailing sl prices to send to the trade server double slPrice = 0.0; //--- Position ticket selected, save the position properties string positionSymbol = PositionGetString(POSITION_SYMBOL); double entryPrice = PositionGetDouble(POSITION_PRICE_OPEN); double volume = PositionGetDouble(POSITION_VOLUME); double currentPositionSlPrice = PositionGetDouble(POSITION_SL); double currentPositionTpPrice = PositionGetDouble(POSITION_TP); ENUM_POSITION_TYPE positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); //-- Get some information about the positions symbol int symbolDigits = (int)SymbolInfoInteger(positionSymbol, SYMBOL_DIGITS); //-- Number of symbol decimal places int symbolStopLevel = (int)SymbolInfoInteger(positionSymbol, SYMBOL_TRADE_STOPS_LEVEL); double symbolPoint = SymbolInfoDouble(positionSymbol, SYMBOL_POINT); double positionPriceCurrent = PositionGetDouble(POSITION_PRICE_CURRENT); int spread = (int)SymbolInfoInteger(positionSymbol, SYMBOL_SPREAD); //-- Check if the trailing stop loss is less than the symbol trade stop levels if(trailingStopLoss < symbolStopLevel) { //-- Trailing stop loss is less than the allowed level for the current symbol trailingStopLoss = symbolStopLevel; //-- Set it to the symbol stop level by default } //-- Calculate and store the trailing stop loss price if(positionType == POSITION_TYPE_BUY) { slPrice = positionPriceCurrent - (trailingStopLoss * symbolPoint); //-- Check if the proposed slPrice for the trailing stop loss is valid if(slPrice < entryPrice || slPrice < currentPositionSlPrice) { return(false); //-- Exit the function, proposed trailing stop loss price is invalid } } else //-- SELL POSITION { slPrice = positionPriceCurrent + (trailingStopLoss * symbolPoint); //-- Check if the proposed slPrice for the trailing stop loss is valid if(slPrice > entryPrice || slPrice > currentPositionSlPrice) { return(false); //-- Exit the function, proposed trailing stop loss price is invalid } } //-- Print position properties before setting the trailing stop loss string positionProperties = "--> " + positionSymbol + " " + EnumToString(positionType) + " Trailing Stop Loss Modification Details" + " <--\r\n"; positionProperties += "------------------------------------------------------------\r\n"; positionProperties += "Ticket: " + (string)positionTicket + "\r\n"; positionProperties += "Volume: " + StringFormat("%G", volume) + "\r\n"; positionProperties += "Price Open: " + StringFormat("%G", entryPrice) + "\r\n"; positionProperties += "Current SL: " + StringFormat("%G", currentPositionSlPrice) + " -> New Trailing SL: " + (string)slPrice + "\r\n"; positionProperties += "Current TP: " + StringFormat("%G", currentPositionTpPrice) + "\r\n"; positionProperties += "Comment: " + PositionGetString(POSITION_COMMENT) + "\r\n"; positionProperties += "Magic Number: " + (string)PositionGetInteger(POSITION_MAGIC) + "\r\n"; positionProperties += "---"; Print(positionProperties); //-- 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_SLTP; //-- Trade operation type for setting sl and tp tradeRequest.position = positionTicket; tradeRequest.symbol = positionSymbol; tradeRequest.sl = slPrice; tradeRequest.tp = currentPositionTpPrice; ResetLastError(); //--- reset error cache so that we get an accurate runtime error code in the ErrorAdvisor function for(int loop = 0; loop <= 100; loop++) //-- try modifying the sl and tp 101 times untill 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 set the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType)); 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__, positionSymbol, tradeResult.retcode) || IsStopped()) { PrintFormat("ERROR setting the Trailing SL for #%I64d %s %s", positionTicket, positionSymbol, EnumToString(positionType)); Print("_______________________________________________________________________________________\r\n\r\n"); return(false); //-- exit function break; //-- exit for loop } } } return(false); }
Функция закрытия всех позиций
Эта функция разработана очень гибко и будет отвечать за закрытие всех открытых позиций на основе указанных параметров. Назовем функцию CloseAllPositions(). Она будет сканировать открытые позиции, соответствующие предоставленным аргументам или параметрам символа и магического символа, и пытаться закрыть их все. Если торговля не разрешена, функция прекратит выполнение и немедленно завершит работу. Функция пройдёт по всем открытым позициям, отсортирует их на основе указанных критериев и закроет все соответствующие позиции.
После того, как она завершит попытки закрыть все позиции, она войдет в цикл, чтобы подтвердить, что все целевые позиции закрыты, обработать все ошибки и убедиться, что мы не попали в бесконечный цикл. После успешного закрытия всез позиций, функция выходит, возвращая true. В противном случае она возвращает false.
Начнем с определения функции CloseAllPositions(). Она вернет логическое значение и примет два параметра со значениями по умолчанию:
- string symbol: По умолчанию ALL_SYMBOLS.
- ulong magicNumber: По умолчанию 0.
bool CloseAllPositions(string symbol = ALL_SYMBOLS, ulong magicNumber = 0) export { //-- Functions body goes here }
Нам нужно проверить, разрешена ли торговля. Если торговля не разрешена, выходим из функции и возвращаем false.
if(!TradingIsAllowed()) { return(false); //--- algo trading is disabled, exit function }
Создадим новую булеву переменную returnThis для сохранения возвращаемого значения функции и присвоения ему значения по умолчанию.
bool returnThis = false;
Извлечем и сохраним общее количество открытых позиций и используем это значение в цикле for, который позволит нам получить доступ ко всем открытым позициям и обработать их. На каждой итерации мы будем сохранять выбранные свойства позиции и использовать эти данные для сортировки позиций на основе предоставленных символа и магического числа. Если позиция не соответствует критериям, переходим к следующей позиции. Если позиция соответствует критериям, мы закрываем позицию с помощью функции ClosePositionByTicket().
int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); //-- Filter positions by symbol and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber) ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); }
Теперь мы выполнили итерацию по всем указанным открытым позициям и отправили запросы на закрытие на торговый сервер. Перед завершением функции нам необходимо подтвердить, что все целевые позиции действительно закрыты. Для этого мы будем использовать цикл, который многократно рекурсивно вызывает функцию CloseAllPositions() до тех пор, пока не будут закрыты все позиции, соответствующие нашим критериям. В каждой итерации мы попытаемся закрыть все оставшиеся позиции, приостановим отправку ордера на короткий период времени, чтобы отсрочить выполнение и избежать перегрузки торгового сервера, а также увеличим счетчик прерываний, чтобы избежать бесконечных циклов. Мы также проверим наличие критических ошибок и других условий выхода (например, остановку скрипта или превышение максимального количества циклов). Если хотя бы одно из этих условий будет выполнено, мы вырвемся из цикла.
int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolPositionsTotal(symbol, magicNumber) > 0) { breakerBreaker++; CloseAllPositions(symbol, magicNumber); //-- We still have some open positions, do a function callback Sleep(100); //-- 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 > 101) { break; } }
Повторно проверим, что все целевые позиции закрыты, и сохраним этот статус в возвращаемой переменной перед окончательным завершением и выходом из функции.
if(SymbolPositionsTotal(symbol, magicNumber) == 0) { returnThis = true; //-- Save this status for the function return value } return(returnThis);
Confirm that all the CloseAllPositions() function code segments are complete in the sequence below:
bool CloseAllPositions(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 positions and close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); //-- Filter positions by symbol and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber) ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } //-- Confirm that we have closed all the positions being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolPositionsTotal(symbol, magicNumber) > 0) { breakerBreaker++; CloseAllPositions(symbol, magicNumber); //-- We still have some open positions, do a function callback Sleep(100); //-- 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 > 101) { break; } } //-- Final confirmations that all targeted positions have been closed if(SymbolPositionsTotal(symbol, magicNumber) == 0) { returnThis = true; //-- Save this status for the function return value } return(returnThis); }
Перегрузка функции для закрытия всех позиций
Для удобства мы перегрузим функцию CloseAllPositions() со второй версией, которая не принимает никаких параметров и закрывает все открытые позиции на счете при вызове. Эту функцию также можно будет экспортировать и использовать в EX5-библиотеке для управления позициями.
//+------------------------------------------------------------------+ //| CloseAllPositions(): Closes all positions in the account | //+------------------------------------------------------------------+ bool CloseAllPositions() export { return(CloseAllPositions(ALL_SYMBOLS, 0)); }
Сортировка функций закрытия позиций
Просматривая форумы разработчиков MQL5, вы часто будете сталкиваться с вопросами от новичков, ищущих помощи в создании алгоритмов для сортировки и управления различными операциями с позициями, такими как закрытие или изменение определенных позиций на основе таких критериев, как магическое число, прибыль или убыток и так далее. Следующая библиотека функций призвана удовлетворить эту потребность, упрощая и ускоряя эффективную реализацию этих операций.
Функции сортировки и фильтрации закрытия позиций, представленные ниже, реализуют примерно тот же подход, что и функция CloseAllPositions(), но имеют и свои отличия. Они используют стратегию рекурсивного программирования, чтобы гарантировать закрытие всех указанных позиций, и включают логи трассировки для записи любых обнаруженных ошибок в журнале советников для диагностики конечным пользователем. Дополнительным преимуществом этих функций является их высокая успешность в достижении поставленных целей, поскольку они рекурсивно сканируют на наличие устранимых ошибок и отправляют указанные торговые запросы несколько раз, чтобы гарантировать успешное выполнение ордеров.
Закрытие всех позиций на покупку
Функция CloseAllBuyPositions() отвечает за закрытие всех открытых позиций на покупку, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllBuyPositions(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 positions and close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); ulong positionType = PositionGetInteger(POSITION_TYPE); //-- Filter positions by symbol, type and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (positionType != POSITION_TYPE_BUY) || (magicNumber != 0 && positionMagicNo != magicNumber) ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } //-- Confirm that we have closed all the buy positions being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolBuyPositionsTotal(symbol, magicNumber) > 0) { breakerBreaker++; CloseAllBuyPositions(symbol, magicNumber); //-- We still have some open buy positions, do a function callback Sleep(100); //-- 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 > 101) { break; } } if(SymbolBuyPositionsTotal(symbol, magicNumber) == 0) { returnThis = true; } return(returnThis); }
Закрытие всех позиций на продажу
Функция CloseAllSellPositions() отвечает за закрытие всех открытых позиций на продажу, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllSellPositions(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 positions and close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); ulong positionType = PositionGetInteger(POSITION_TYPE); //-- Filter positions by symbol, type and magic number if( (symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (positionType != POSITION_TYPE_SELL) || (magicNumber != 0 && positionMagicNo != magicNumber) ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } //-- Confirm that we have closed all the sell positions being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(SymbolSellPositionsTotal(symbol, magicNumber) > 0) { breakerBreaker++; CloseAllSellPositions(symbol, magicNumber); //-- We still have some open sell positions, do a function callback Sleep(100); //-- 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 > 101) { break; } } if(SymbolSellPositionsTotal(symbol, magicNumber) == 0) { returnThis = true; } return(returnThis); }
Закрытие всех позиций по магическому числу
Функция CloseAllMagicPositions() отвечает за закрытие всех открытых позиций, соответствующих указанному параметру или аргументу функции магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllMagicPositions(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 positions data ulong positionTicket, positionMagicNo; string positionSymbol; //-- Scan for magic number specific positions and close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties positionTicket = PositionGetTicket(x); //-- Get ticket to select the position positionMagicNo = PositionGetInteger(POSITION_MAGIC); positionSymbol = PositionGetString(POSITION_SYMBOL); //-- Filter positions by magic number if(magicNumber == positionMagicNo) { //-- Close the position ClosePositionByTicket(positionTicket); } } //-- Confirm that we have closed all the positions being targeted int breakerBreaker = 0; //-- Variable that safeguards and makes sure we are not locked in an infinite loop while(MagicPositionsTotal(magicNumber) > 0) { breakerBreaker++; CloseAllMagicPositions(magicNumber); //-- We still have some open positions, do a function callback Sleep(100); //-- 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__, positionSymbol, GetLastError()) || IsStopped() || breakerBreaker > 101) { break; } } if(MagicPositionsTotal(magicNumber) == 0) { returnThis = true; } return(returnThis); }
Закрытие всех прибыльных позиций
Функция CloseAllProfitablePositions() закрывает все прибыльные открытые позиции, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllProfitablePositions(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 } //-- Scan for profitable positions that match the specified symbol and magic number to close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); double positionProfit = PositionGetDouble(POSITION_PROFIT); //-- Filter positions by symbol, magic number and profit if( ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) || positionProfit <= 0 ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } return(true); }
___
Закрытие всех прибыльных позиций на покупку
Функция CloseAllProfitableBuyPositions() закрывает все прибыльные открытые позиции на покупку, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllProfitableBuyPositions(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 } //-- Scan for profitable positions that match the specified symbol and magic number to close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); double positionProfit = PositionGetDouble(POSITION_PROFIT); //-- Filter positions by symbol, magic number, profit and type if( ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) || positionProfit <= 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } return(true); }
Закрытие всех прибыльных позиций на продажу
Функция CloseAllProfitableSellPositions() закрывает все прибыльные открытые позиции на продажу, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllProfitableSellPositions(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 } //-- Scan for profitable positions that match the specified symbol and magic number to close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); double positionProfit = PositionGetDouble(POSITION_PROFIT); //-- Filter positions by symbol, magic number, profit and type if( ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) || positionProfit <= 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_SELL ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } return(true); }
Закрытие всех убыточных позиций
Функция CloseAllLossPositions() закрывает все убыточные открытые позиции, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllLossPositions(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 } //-- Scan for loss positions that match the specified symbol and magic number and close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); double positionProfit = PositionGetDouble(POSITION_PROFIT); //-- Filter positions by symbol, magic number and profit if( ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) || positionProfit > 0 ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } return(true); }
Закрытие всех убыточных позиций на покупку
Функция CloseAllLossBuyPositions() закрывает все убыточные открытые позиции на покупку, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllLossBuyPositions(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 } //-- Scan for loss positions that match the specified symbol and magic number and close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); double positionProfit = PositionGetDouble(POSITION_PROFIT); //-- Filter positions by symbol, magic number, profit and type if( ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) || positionProfit > 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_BUY ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } return(true); }
Закрытие всех убыточных позиций на продажу
Функция CloseAllLossSellPositions() закрывает все убыточные открытые позиции на продажу, которые соответствуют указанным параметрам или аргументам функции имени символа и магического числа. Функция возвращает логическое значение true при успешном закрытии всех указанных позиций и false в противном случае.
bool CloseAllLossSellPositions(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 } //-- Scan for loss positions that match the specified symbol and magic number and close them int totalOpenPositions = PositionsTotal(); for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); double positionProfit = PositionGetDouble(POSITION_PROFIT); //-- Filter positions by symbol, magic number, profit and type if( ((symbol != ALL_SYMBOLS && symbol != selectedSymbol) || (magicNumber != 0 && positionMagicNo != magicNumber)) || positionProfit > 0 || PositionGetInteger(POSITION_TYPE) != POSITION_TYPE_SELL ) { continue; } //-- Close the position ClosePositionByTicket(positionTicket); } return(true); }
Функции статуса позиции
При разработке торговой системы важно отслеживать состояние счета, используя данные в реальном времени по различным позициям. Независимо от того, разрабатываете ли вы стратегию на основе сетки или консервативную стратегию ценового действия, наличие четкого и ясного обзора всех открытых позиций имеет решающее значение для успеха вашей торговой системы. Однако не существует готовых стандартных функций языка, которые предоставляли бы такую информацию. Наша EX5-библиотека призвана упростить сбор информации о позиции с помощью однострочных вызовов функций. Экспортируемые функции, представленные ниже, дадут вам необходимое преимущество для мониторинга позиций и принятия решения о том, следует ли их закрыть или увеличить, упрощая работу по вашей торговой системы.
Получение данные о позициях
Функция GetPositionsData() играет решающую роль в сборе и хранении всей необходимой информации о статусе позиции. Она сохраняет эти данные в глобальных переменных, которые легко доступны в пределах всей библиотеки. Эти переменные должны постоянно обновляться на каждом тике, гарантируя их точность и надежность.
Разместим следующие объявления глобальных переменных в верхней части нашей библиотеки под объявлениями глобальных переменных структур данных запроса и результата торговых операций.
string accountCurrency = AccountInfoString(ACCOUNT_CURRENCY); //-- Position status global variables //------------------------------------------------------------------------------------------------------------------- int accountBuyPositionsTotal = 0, accountSellPositionsTotal = 0, symbolPositionsTotal = 0, symbolBuyPositionsTotal = 0, symbolSellPositionsTotal = 0, magicPositionsTotal = 0, magicBuyPositionsTotal = 0, magicSellPositionsTotal = 0; double accountPositionsVolumeTotal = 0.0, accountBuyPositionsVolumeTotal = 0.0, accountSellPositionsVolumeTotal = 0.0, accountBuyPositionsProfit = 0.0, accountSellPositionsProfit = 0.0, symbolPositionsVolumeTotal = 0.0, symbolBuyPositionsVolumeTotal = 0.0, symbolSellPositionsVolumeTotal = 0.0, symbolPositionsProfit = 0.0, symbolBuyPositionsProfit = 0.0, symbolSellPositionsProfit = 0.0, magicPositionsVolumeTotal = 0.0, magicBuyPositionsVolumeTotal = 0.0, magicSellPositionsVolumeTotal = 0.0, magicPositionsProfit = 0.0, magicBuyPositionsProfit = 0.0, magicSellPositionsProfit = 0.0;
Обновим и сохраним данные о статусе позиции в функции GetPositionsData() ниже.
void GetPositionsData(string symbol, ulong magicNumber) { //-- Reset the acount open positions status accountBuyPositionsTotal = 0; accountSellPositionsTotal = 0; accountPositionsVolumeTotal = 0.0; accountBuyPositionsVolumeTotal = 0.0; accountSellPositionsVolumeTotal = 0.0; accountBuyPositionsProfit = 0.0; accountSellPositionsProfit = 0.0; //-- Reset the EA's magic open positions status magicPositionsTotal = 0; magicBuyPositionsTotal = 0; magicSellPositionsTotal = 0; magicPositionsVolumeTotal = 0.0; magicBuyPositionsVolumeTotal = 0.0; magicSellPositionsVolumeTotal = 0.0; magicPositionsProfit = 0.0; magicBuyPositionsProfit = 0.0; magicSellPositionsProfit = 0.0; //-- Reset the symbol open positions status symbolPositionsTotal = 0; symbolBuyPositionsTotal = 0; symbolSellPositionsTotal = 0; symbolPositionsVolumeTotal = 0.0; symbolBuyPositionsVolumeTotal = 0.0; symbolSellPositionsVolumeTotal = 0.0; symbolPositionsProfit = 0.0; symbolBuyPositionsProfit = 0.0; symbolSellPositionsProfit = 0.0; //-- Update and save the open positions status with realtime data int totalOpenPositions = PositionsTotal(); if(totalOpenPositions > 0) { //-- Scan for symbol and magic number specific positions and save their status for(int x = 0; x < totalOpenPositions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); //-- Filter positions by magic number if(magicNumber != 0 && positionMagicNo != magicNumber) { continue; } //-- Save the account positions status first accountPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { //-- Account properties ++accountBuyPositionsTotal; accountBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); accountBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT); } else //-- POSITION_TYPE_SELL { //-- Account properties ++accountSellPositionsTotal; accountSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); accountSellPositionsProfit += PositionGetDouble(POSITION_PROFIT); } //-- Filter positions openend by EA and save their status if( PositionGetInteger(POSITION_REASON) == POSITION_REASON_EXPERT && positionMagicNo == magicNumber ) { ++magicPositionsTotal; magicPositionsProfit += PositionGetDouble(POSITION_PROFIT); magicPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { //-- Magic properties ++magicBuyPositionsTotal; magicBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT); magicBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); } else //-- POSITION_TYPE_SELL { //-- Magic properties ++magicSellPositionsTotal; magicSellPositionsProfit += PositionGetDouble(POSITION_PROFIT); magicSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); } } //-- Filter positions by symbol if(symbol == ALL_SYMBOLS || selectedSymbol == symbol) { ++symbolPositionsTotal; symbolPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); symbolPositionsProfit += PositionGetDouble(POSITION_PROFIT); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { ++symbolBuyPositionsTotal; symbolBuyPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); symbolBuyPositionsProfit += PositionGetDouble(POSITION_PROFIT); } else //-- POSITION_TYPE_SELL { ++symbolSellPositionsTotal; symbolSellPositionsVolumeTotal += PositionGetDouble(POSITION_VOLUME); symbolSellPositionsProfit += PositionGetDouble(POSITION_PROFIT); } } } } }
Чтобы получить доступ к различным свойствам статуса позиции, которые мы зафиксировали и сохранили в глобальных переменных выше, нам необходимо создать простые экспортируемые функции, которые могут быть доступны из внешней базы кодов. Добавим следующие функции.
Buy Positions Total
Возвращает целое значение общего количества всех открытых позиций на покупку на счете.
int BuyPositionsTotal() export { GetPositionsData(ALL_SYMBOLS, 0); return(accountBuyPositionsTotal); }
Sell Positions Total
Возвращает целое значение общего количества всех открытых позиций на продажу на счете.
int SellPositionsTotal() export { GetPositionsData(ALL_SYMBOLS, 0); return(accountSellPositionsTotal); }
Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций на счете.
double PositionsTotalVolume() export { GetPositionsData(ALL_SYMBOLS, 0); return(accountPositionsVolumeTotal); }
Buy Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций на покупку на счете.
double BuyPositionsTotalVolume() export { GetPositionsData(ALL_SYMBOLS, 0); return(accountBuyPositionsVolumeTotal); }
Sell Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций на продажу на счете.
double SellPositionsTotalVolume() export { GetPositionsData(ALL_SYMBOLS, 0); return(accountSellPositionsVolumeTotal); }
Buy Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций на покупку на счете.
double BuyPositionsProfit() export { GetPositionsData(ALL_SYMBOLS, 0); return(accountBuyPositionsProfit); }
Sell Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций на продажу на счете.
double SellPositionsProfit() export { GetPositionsData(ALL_SYMBOLS, 0); return(accountSellPositionsProfit); }
Magic Positions Total
Возвращает целое число общего количества всех открытых позиций для указанного магического числа на счете.
int MagicPositionsTotal(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicPositionsTotal); }
Magic Buy Positions Total
Возвращает целое число общего количества всех открытых позиций на покупку для указанного магического числа на счете.
int MagicBuyPositionsTotal(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicBuyPositionsTotal); }
Magic Sell Positions Total
Возвращает целое число общего количества всех открытых позиций на продажу для указанного магического числа на счете.
int MagicSellPositionsTotal(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicSellPositionsTotal); }
Magic Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций для указанного магического числа на счете.
double MagicPositionsTotalVolume(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicPositionsVolumeTotal); }
Magic Buy Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций на покупку для указанного магического числа на счете.
double MagicBuyPositionsTotalVolume(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicBuyPositionsVolumeTotal); }
Magic Sell Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций на продажу для указанного магического числа на счете.
double MagicSellPositionsTotalVolume(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicSellPositionsVolumeTotal); }
Magic Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций для указанного магического числа на счете.
double MagicPositionsProfit(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicPositionsProfit); }
Magic Buy Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций на покупку для указанного магического числа на счете.
double MagicBuyPositionsProfit(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicBuyPositionsProfit); }
Magic Sell Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций на продажу для указанного магического числа на счете.
double MagicSellPositionsProfit(ulong magicNumber) export { GetPositionsData(ALL_SYMBOLS, magicNumber); return(magicSellPositionsProfit); }
Symbol Positions Total
Возвращает целое значение общего количества всех открытых позиций по указанному символу на счете.
int SymbolPositionsTotal(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(symbolPositionsTotal); }
Symbol Buy Positions Total
Возвращает целое число общего количества всех открытых позиций на покупку для указанного символа на счете.
int SymbolBuyPositionsTotal(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(symbolBuyPositionsTotal); }
Symbol Sell Positions Total
Возвращает целое число общего количества всех открытых позиций на продажу по указанному символу на счете.
int SymbolSellPositionsTotal(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(symbolSellPositionsTotal); }
Symbol Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций по указанному символу на счете.
double SymbolPositionsTotalVolume(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(symbolPositionsVolumeTotal); }
Symbol Buy Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций на покупку для указанного символа на счете.
double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(symbolBuyPositionsVolumeTotal); }
Symbol Sell Positions Total Volume
Возвращает double-значение общего объема/лота/количества всех открытых позиций на продажу для указанного символа на счете.
double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(symbolSellPositionsVolumeTotal); }
Symbol Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций по указанному символу на счете.
double SymbolPositionsProfit(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(NormalizeDouble(symbolPositionsProfit, 2)); }
Symbol Buy Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций на покупку по указанному символу на счете.
double SymbolBuyPositionsProfit(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(NormalizeDouble(symbolBuyPositionsProfit, 2)); }
Symbol Sell Positions Profit
Возвращает double-значение общей прибыли всех открытых позиций на продажу по указанному символу на счете.
double SymbolSellPositionsProfit(string symbol, ulong magicNumber) export { GetPositionsData(symbol, magicNumber); return(NormalizeDouble(symbolSellPositionsProfit, 2)); }
Account Positions Status
Возвращает предварительно отформатированную строку, содержащую статус позиций счета, который можно вывести в журнал или отобразить в комментариях к графику. Функция принимает один логический параметр formatForComment. Если formatForComment равен true, функция форматирует данные для отображения в окне графика. При false данные форматируются для отображения на вкладке журналов советника.
string AccountPositionsStatus(bool formatForComment) export { GetPositionsData(ALL_SYMBOLS, 0); //-- Update the position status variables before we display their data string spacer = ""; if(formatForComment) //-- Add some formating space for the chart comment string { spacer = " "; } string accountPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n"; accountPositionsStatus += spacer + "| " + (string)AccountInfoInteger(ACCOUNT_LOGIN) + " - ACCOUNT POSTIONS STATUS \r\n"; accountPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n"; accountPositionsStatus += spacer + "| Total Open: " + (string)PositionsTotal() + "\r\n"; accountPositionsStatus += spacer + "| Total Volume: " + (string)accountPositionsVolumeTotal + "\r\n"; accountPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(AccountInfoDouble(ACCOUNT_PROFIT), 2)) + accountCurrency + "\r\n"; accountPositionsStatus += spacer + "|------------------------------------------------------------------\r\n"; accountPositionsStatus += spacer + "| BUY POSITIONS: \r\n"; accountPositionsStatus += spacer + "| Total Open: " + (string)accountBuyPositionsTotal + "\r\n"; accountPositionsStatus += spacer + "| Total Volume: " + (string)accountBuyPositionsVolumeTotal + "\r\n"; accountPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(accountBuyPositionsProfit, 2)) + accountCurrency + "\r\n"; accountPositionsStatus += spacer + "|------------------------------------------------------------------\r\n"; accountPositionsStatus += spacer + "| SELL POSITIONS: \r\n"; accountPositionsStatus += spacer + "| Total Open: " + (string)accountSellPositionsTotal + "\r\n"; accountPositionsStatus += spacer + "| Total Volume: " + (string)accountSellPositionsVolumeTotal + "\r\n"; accountPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(accountSellPositionsProfit, 2)) + accountCurrency + "\r\n"; accountPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n"; accountPositionsStatus += spacer + "\r\n"; return(accountPositionsStatus); }
Magic Positions Status
Возвращает предварительно отформатированную строку, содержащую статус позиций счета по магическому числу, который можно вывести в журнал или отобразить в комментариях к графику. Функция принимает два аргумента или параметра. Неподписанный long magicNumber и логический formatForComment. Если formatForComment равен true, функция форматирует данные для отображения в окне графика. При false данные форматируются для отображения в логах советниках.
string MagicPositionsStatus(ulong magicNumber, bool formatForComment) export { GetPositionsData(ALL_SYMBOLS, magicNumber); //-- Update the position status variables before we display their data string spacer = ""; if(formatForComment) //-- Add some formating space for the chart comment string { spacer = " "; } string magicPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n"; magicPositionsStatus += spacer + "| " + (string)magicNumber + " - MAGIC POSTIONS STATUS \r\n"; magicPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n"; magicPositionsStatus += spacer + "| Total Open: " + (string)magicPositionsTotal + "\r\n"; magicPositionsStatus += spacer + "| Total Volume: " + (string)magicPositionsVolumeTotal + "\r\n"; magicPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(magicPositionsProfit, 2)) + accountCurrency + "\r\n"; magicPositionsStatus += spacer + "|------------------------------------------------------------------\r\n"; magicPositionsStatus += spacer + "| BUY POSITIONS: \r\n"; magicPositionsStatus += spacer + "| Total Open: " + (string)magicBuyPositionsTotal + "\r\n"; magicPositionsStatus += spacer + "| Total Volume: " + (string)magicBuyPositionsVolumeTotal + "\r\n"; magicPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(magicBuyPositionsProfit, 2)) + accountCurrency + "\r\n"; magicPositionsStatus += spacer + "|------------------------------------------------------------------\r\n"; magicPositionsStatus += spacer + "| SELL POSITIONS: \r\n"; magicPositionsStatus += spacer + "| Total Open: " + (string)magicSellPositionsTotal + "\r\n"; magicPositionsStatus += spacer + "| Total Volume: " + (string)magicSellPositionsVolumeTotal + "\r\n"; magicPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(magicSellPositionsProfit, 2)) + accountCurrency + "\r\n"; magicPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n"; magicPositionsStatus += spacer + "\r\n"; return(magicPositionsStatus); }
Symbol Positions Status
Возвращает предварительно отформатированную строку, содержащую статус позиций символа, который можно вывести в журнал или отобразить в комментариях к графику. Функция принимает три аргумента или параметра. Строковый symbol, неподписанный long magicNumber и логический formatForComment. Если логическое значение formatForComment равно true, функция форматирует данные для отображения в окне графика. При false данные форматируются для отображения в логах советника.
string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment) export { GetPositionsData(symbol, magicNumber); //-- Update the position status variables before we display their data string spacer = ""; if(formatForComment) //-- Add some formating space for the chart comment string { spacer = " "; } string symbolPositionsStatus = "\r\n" + spacer + "|---------------------------------------------------------------------------\r\n"; symbolPositionsStatus += spacer + "| " + symbol + " - SYMBOL POSTIONS STATUS \r\n"; symbolPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n"; symbolPositionsStatus += spacer + "| Total Open: " + (string)symbolPositionsTotal + "\r\n"; symbolPositionsStatus += spacer + "| Total Volume: " + (string)symbolPositionsVolumeTotal + "\r\n"; symbolPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(symbolPositionsProfit, 2)) + accountCurrency + "\r\n"; symbolPositionsStatus += spacer + "|------------------------------------------------------------------\r\n"; symbolPositionsStatus += spacer + "| BUY POSITIONS: \r\n"; symbolPositionsStatus += spacer + "| Total Open: " + (string)symbolBuyPositionsTotal + "\r\n"; symbolPositionsStatus += spacer + "| Total Volume: " + (string)symbolBuyPositionsVolumeTotal + "\r\n"; symbolPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(symbolBuyPositionsProfit, 2)) + accountCurrency + "\r\n"; symbolPositionsStatus += spacer + "|------------------------------------------------------------------\r\n"; symbolPositionsStatus += spacer + "| SELL POSITIONS: \r\n"; symbolPositionsStatus += spacer + "| Total Open: " + (string)symbolSellPositionsTotal + "\r\n"; symbolPositionsStatus += spacer + "| Total Volume: " + (string)symbolSellPositionsVolumeTotal + "\r\n"; symbolPositionsStatus += spacer + "| Total Profit: " + (string)(NormalizeDouble(symbolSellPositionsProfit, 2)) + accountCurrency + "\r\n"; symbolPositionsStatus += spacer + "|---------------------------------------------------------------------------\r\n"; symbolPositionsStatus += spacer + "\r\n"; return(symbolPositionsStatus); }
Как импортировать и внедрить EX5-библиотеку для управления позициями
Мы разработали комплексную EX5-библиотеку для управления позициями, содержащую все основные функции для операций с позициями, извлечения статуса и модулей отображения. Теперь пришло время задокументировать и объяснить, как эффективно импортировать и использовать эту библиотеку в любом проекте MQL5.
Чтобы упростить процесс внедрения, давайте начнем с описания всех функций или модулей в библиотеке управления позициями, а также приведем несколько примеров использования реального кода. Это даст некоторое представление о компонентах, включенных в бинарный файл PositionsManager.ex5.
Документация EX5-библиотеки для управления позициями
Описание прототипа функции | Описание | Пример использования |
---|---|---|
bool ErrorAdvisor( string callingFunc, string symbol, int tradeServerErrorCode ); | Управляет ошибками торгового сервера и времени выполнения при обработке позиций и ордеров. Возвращает true, если ошибка устранима и запрос на торговлю можно отправить повторно, и false, если ошибка критическая и отправку запроса следует прекратить. | ResetLastError(); //-- Reset and clear the last error //-------------------------------------------------------------- //-- Insert code to send the order request to the trade server //-------------------------------------------------------------- string symbol = _Symbol; //Symbol being traded int retcode = tradeResult.retcode;//Trade Request Structure (MqlTradeRequest) if(!ErrorAdvisor(__FUNCTION__, symbol, retcode) { //Critical error found //Order can not be executed. Exit function or log this error } |
bool TradingIsAllowed(); | Проверяет, предоставлено ли советнику разрешение на совершение сделок пользователем, торговым сервером и брокером. | if(!TradingIsAllowed()) { //--- algo trading is disabled, exit function return(false); } |
bool OpenBuyPosition( ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment ); | Открывает новую позицию на покупку, соответствующую указанным параметрам. | ulong magicNo = 123; string symbol = _Symbol; double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); int sl = 500; //-- pips int tp = 1000; //-- pips string comment = "Buy position"; OpenBuyPosition(magicNo, symbol, lotSize, sl, tp, comment); |
bool OpenSellPosition( ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment ); | Открывает новую позицию на продажу, соответствующую указанным параметрам. | ulong magicNo = 123; string symbol = _Symbol; double lotSize = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); int sl = 500; //-- pips int tp = 1000; //-- pips string comment = "Sell position"; OpenSellPosition(magicNo, symbol, lotSize, sl, tp, comment); |
bool SetSlTpByTicket( ulong positionTicket, int sl, int tp ); | Устанавливает стоп-лосс для позиции, соответствующей указанному тикету. | int sl = 500, int tp = 1000; //-- pips int totalOpenPostions = PositionsTotal(); for(int x = 0; x < totalOpenPostions; x++) { ulong positionTicket = PositionGetTicket(x); if(positionTicket > 0) { SetSlTpByTicket(positionTicket, sl, tp); } } |
bool ClosePositionByTicket( ulong positionTicket ); | Закрывает позицию, соответствующую указанному тикету. | //-- Example to close all open positions for(int x = 0; x < totalOpenPostions; x++) { ulong positionTicket = PositionGetTicket(x); if(positionTicket > 0) { ClosePositionByTicket(positionTicket); } } |
bool SetTrailingStopLoss( ulong positionTicket, int trailingStopLoss ); | Устанавливает трейлинг-стоп-лосс для позиции, соответствующей указанному тикету. Эта функция должна выполняться на каждом тике в функции OnTick() для обновления трейлинг-стоп-лосса в реальном времени. | //-- Execute this on every tick //-- Example to set 500 pips trailing stop loss for all positions int trailingStopLoss = 500; //-- 500 pips trailing stop loss for(int x = 0; x < totalOpenPostions; x++) { ulong positionTicket = PositionGetTicket(x); if(positionTicket > 0) { SetTrailingStopLoss(positionTicket, trailingStopLoss); } } |
bool CloseAllPositions( string symbol, ulong magicNumber ); | Универсальная функция, которая закрывает все открытые позиции, соответствующие указанным параметрам. | //Close all positions CloseAllPositions("", 0); //Only close all positions matching a magic number value of 1 CloseAllPositions("", 1); //Only close all current symbol positions CloseAllPositions(_Symbol, 0); |
bool CloseAllPositions(); | Закрывает все открытые позиции. | //Close all open positions in the account
CloseAllPositions(); |
bool CloseAllBuyPositions( string symbol, ulong magicNumber ); | Закрывает все позиции на покупку, соответствующие указанным параметрам. | //Close all buy positions for the current symbol CloseAllBuyPositions(_Symbol, 0); //Close all buy positions matching magic number 1 for all symbols CloseAllBuyPositions("", 1); //Close all buy positions in the account CloseAllBuyPositions("", 0); |
bool CloseAllSellPositions( string symbol, ulong magicNumber ); | Закрывает все позиции на продажу, соответствующие указанным параметрам. | //Close all sell positions for the current symbol CloseAllSellPositions(_Symbol, 0); //Close all sell positions matching magic number 1 for all symbols CloseAllSellPositions("", 1); //Close all sell positions in the account CloseAllSellPositions("", 0); |
bool CloseAllMagicPositions( ulong magicNumber ); | Закрывает все позиции, соответствующие указанному магическому числу. | //Close all positions matching magic number 1 CloseAllMagicPositions(1); //Close all positions in the account CloseAllMagicPositions(0); |
bool CloseAllProfitablePositions( string symbol, ulong magicNumber ); | Закрывает все прибыльные позиции, соответствующие указанным параметрам. | //Close all profitable positions for the current symbol CloseAllProfitablePositions(_Symbol, 0); //Close all profitable positions matching magic number 1 for all symbols CloseAllProfitablePositions("", 1); //Close all profitable positions in the account CloseAllProfitablePositions("", 0); |
bool CloseAllProfitableBuyPositions( string symbol, ulong magicNumber ); | Закрывает все прибыльные позиции на покупку, соответствующие указанным параметрам. | //Close all profitable buy positions for the current symbol CloseAllProfitableBuyPositions(_Symbol, 0); //Close all profitable buy positions matching magic number 1 for all symbols CloseAllProfitableBuyPositions("", 1); //Close all profitable buy positions in the account CloseAllProfitableBuyPositions("", 0); |
bool CloseAllProfitableSellPositions( string symbol, ulong magicNumber ); | Закрывает все прибыльные позиции на продажу, соответствующие указанным параметрам. | //Close all profitable sell positions for the current symbol CloseAllProfitableSellPositions(_Symbol, 0); //Close all profitable sell positions matching magic number 1 for all symbols CloseAllProfitableSellPositions("", 1); //Close all profitable sell positions in the account CloseAllProfitableSellPositions("", 0); |
bool CloseAllLossPositions( string symbol, ulong magicNumber ); | Закрывает все убыточные позиции, соответствующие указанным параметрам. | //Close all loss positions for the current symbol CloseAllLossPositions(_Symbol, 0); //Close all loss positions matching magic number 1 for all symbols CloseAllLossPositions("", 1); //Close all loss positions in the account CloseAllLossPositions("", 0); |
bool CloseAllLossBuyPositions( string symbol, ulong magicNumber ); | Закрывает все убыточные позиции на покупку, соответствующие указанным параметрам. | //Close all loss buy positions for the current symbol CloseAllLossBuyPositions(_Symbol, 0); //Close all loss buy positions matching magic number 1 for all symbols CloseAllLossBuyPositions("", 1); //Close all loss buy positions in the account CloseAllLossBuyPositions("", 0); |
bool CloseAllLossSellPositions( string symbol, ulong magicNumber ); | Закрывает все убыточные позиции на продажу, соответствующие указанным параметрам. | //Close all loss sell positions for the current symbol CloseAllLossSellPositions(_Symbol, 0); //Close all loss sell positions matching magic number 1 for all symbols CloseAllLossSellPositions("", 1); //Close all loss sell positions in the account CloseAllLossSellPositions("", 0); |
int BuyPositionsTotal(); | Возвращает количество открытых позиций на покупку. | //Get the total number of open buy positions in the account
BuyPositionsTotal(); |
int SellPositionsTotal();
| Возвращает количество открытых позиций на продажу. | //Get the total number of open sell positions in the account
SellPositionsTotal(); |
double PositionsTotalVolume();
| Возвращает общий объем всех открытых позиций. | //Get the total volume of all open positions in the account
PositionsTotalVolume(); |
double BuyPositionsTotalVolume(); | Возвращает общий объем всех открытых позиций на покупку. | //Get the total volume of all open buy positions in the account
BuyPositionsTotalVolume(); |
double SellPositionsTotalVolume(); | Возвращает общий объем всех открытых позиций на продажу. | //Get the total volume of all open sell positions in the account
SellPositionsTotalVolume(); |
double BuyPositionsProfit(); | Возвращает общую прибыль всех открытых позиций на покупку. | //Get the total profit of all open buy positions in the account
BuyPositionsProfit(); |
double SellPositionsProfit(); | Возвращает общую прибыль всех открытых позиций на продажу. | //Get the total profit of all open sell positions in the account
SellPositionsProfit(); |
int MagicPositionsTotal( ulong magicNumber ); | Возвращает количество открытых позиций, соответствующих указанному магическому числу. | //Get the total number of open positions matching magic number 1 MagicPositionsTotal(1); |
int MagicBuyPositionsTotal( ulong magicNumber ); | Возвращает количество открытых позиций на покупку, соответствующих указанному магическому числу. | //Get the total number of open buy positions matching magic number 1 MagicBuyPositionsTotal(1); |
int MagicSellPositionsTotal( ulong magicNumber ); | Возвращает количество открытых позиций на продажу, соответствующих указанному магическому числу. | //Get the total number of open sell positions matching magic number 1 MagicSellPositionsTotal(1); |
double MagicPositionsTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых позиций, соответствующих указанному магическому числу. | //Get the total volume of open positions matching magic number 1 MagicPositionsTotalVolume(1); |
double MagicBuyPositionsTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых позиций на покупку, соответствующих указанному магическому числу. | //Get the total volume of open buy positions matching magic number 1 MagicBuyPositionsTotalVolume(1); |
double MagicSellPositionsTotalVolume( ulong magicNumber ); | Возвращает общий объем всех открытых позиций на продажу, соответствующих указанному магическому числу. | //Get the total volume of open sell positions matching magic number 1 MagicSellPositionsTotalVolume(1); |
double MagicPositionsProfit( ulong magicNumber ); | Возвращает общую прибыль всех открытых позиций, соответствующих указанному магическому числу. | //Get the total profit of open positions matching magic number 1 MagicPositionsProfit(1); |
double MagicBuyPositionsProfit( ulong magicNumber ); | Возвращает общую прибыль всех открытых позиций на покупку, соответствующих указанному магическому числу. | //Get the total profit of open buy positions matching magic number 1 MagicBuyPositionsProfit(1); |
double MagicSellPositionsProfit( ulong magicNumber ); | Возвращает общую прибыль всех открытых позиций на продажу, соответствующих указанному магическому числу. | //Get total profit of sell positions matching magic number 1 MagicSellPositionsProfit(1); |
int SymbolPositionsTotal( string symbol, ulong magicNumber ); | Возвращает общее количество всех открытых позиций, соответствующих указанному символу и магическому числу. | //Get total number of positions matching symbol and magic number 1 MagicPositionsTotal(_Symbol, 1); |
int SymbolBuyPositionsTotal( string symbol, ulong magicNumber ); | Возвращает общее количество всех открытых позиций на покупку, соответствующих указанному символу и магическому числу. | //Get total number of buy positions matching symbol and magic number 1 SymbolBuyPositionsTotal(_Symbol, 1); |
int SymbolSellPositionsTotal( string symbol, ulong magicNumber ); | Возвращает общее количество всех открытых позиций на продажу, соответствующих указанному символу и магическому числу. | //Get total number of sell positions matching symbol and magic number 1 SymbolSellPositionsTotal(_Symbol, 1); |
double SymbolPositionsTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых позиций, соответствующих указанному символу и магическому числу. | //Get the volume of positions matching symbol and magic number 1 SymbolPositionsTotalVolume(_Symbol, 1); |
double SymbolBuyPositionsTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых позиций на покупку, соответствующих указанному символу и магическому числу. | //Get the volume of buy positions matching symbol and magic number 1 SymbolBuyPositionsTotalVolume(_Symbol, 1); |
double SymbolSellPositionsTotalVolume( string symbol, ulong magicNumber ); | Возвращает общий объем всех открытых позиций на продажу, соответствующих указанному символу и магическому числу. | //Get the volume of sell positions matching symbol and magic number 1 SymbolSellPositionsTotalVolume(_Symbol, 1); |
double SymbolPositionsProfit( string symbol, ulong magicNumber ); | Возвращает общую прибыль всех открытых позиций, соответствующих указанному символу и магическому числу. | //Get the profit of all positions matching symbol and magic number 1 SymbolPositionsProfit(_Symbol, 1); |
double SymbolBuyPositionsProfit( string symbol, ulong magicNumber ); | Возвращает общую прибыль всех открытых позиций на покупку, соответствующих указанному символу и магическому числу. | //Get the profit of all buy positions matching symbol and magic number 1 SymbolBuyPositionsProfit(_Symbol, 1); |
double SymbolSellPositionsProfit( string symbol, ulong magicNumber ); | Возвращает общую прибыль всех открытых позиций на продажу, соответствующих указанному символу и магическому числу. | //Get the profit of all sell positions matching symbol and magic number 1 SymbolSellPositionsProfit(_Symbol, 1); |
string AccountPositionsStatus( bool formatForComment ); | Выводит на экран статус всех открытых позиций на графике символов или на вкладке "Эксперты" в MetaTrader 5 в виде строки. | //Print the status of all open positions formatted for the chart comments AccountPositionsStatus(true); //Print the status of all open positions formatted for the Experts tab AccountPositionsStatus(false); |
string MagicPositionsStatus( ulong magicNumber, bool formatForComment ); | Выводит на экран статус всех открытых позиций, соответствующих указанному магическому числу, на графике символов или на вкладке "Эксперты" в MetaTrader 5 в виде строки. | //Print the status of all open positions matching //the magic number 1 formatted for the chart comments MagicPositionsStatus(1, true); //Print the status of all open positions matching //the magic number 1 formatted for the Experts tab MagicPositionsStatus(1, false); |
string SymbolPositionsStatus( string symbol, ulong magicNumber, bool formatForComment ); | Выводит на экран статус всех открытых позиций, соответствующих указанному символу и магическому числу, на графике символов или на вкладке "Эксперты" в MetaTrader 5 в виде строки. | //Print the status of all open positions matching //the symbol and magic number 1 formatted for the chart comments SymbolPositionsStatus(_Symbol, 1, true); //Print the status of all open positions matching //the symbol and magic number 1 formatted for the Experts tab SymbolPositionsStatus(_Symbol, 1, false); |
Интеграция библиотеки в проекты MQL5 проста. Выполните следующие два шага для импорта PositionsManager.ex5 в ваш MQL5-код:
- Шаг 1: Скопируйте исполняемый файл библиотеки (PositionsManager.ex5)
Установите файл PositionsManager.ex5 в папку MQL5/Libraries/Toolkit. Убедитесь, что вы загрузили и скопировали файл в указанное место, если его там еще нет. Файл PositionsManager.ex5 приложен в конце статьи.
- Шаг 2: Импортируйте описания прототипов функций
Добавьте директивы импорта библиотеки для управления позициями и описания прототипов ее функций в раздел заголовка вашего файла исходного кода. Используйте фрагмент кода ниже для эффективного импорта всех функций или модулей из библиотеки PositionsManager.ex5. Я также создал пустой шаблон советника (PositionsManager_Imports_Template.mq5), который включает в себя сегмент кода, указанный ниже. Вы можете выборочно комментировать или удалять любые описания функций, которые не требуются для вашего проекта. Файл PositionsManager_Imports_Template.mq5 также приложен в конце статьи.
//+-------------------------------------------------------------------------------------+ //| PositionsManager.ex5 imports template | //+-------------------------------------------------------------------------------------+ #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(); //-- Position Execution and Modification Functions bool OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment); bool OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment); bool SetSlTpByTicket(ulong positionTicket, int sl, int tp); bool ClosePositionByTicket(ulong positionTicket); bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss); bool CloseAllPositions(string symbol, ulong magicNumber); bool CloseAllPositions(); bool CloseAllBuyPositions(string symbol, ulong magicNumber); bool CloseAllSellPositions(string symbol, ulong magicNumber); bool CloseAllMagicPositions(ulong magicNumber); bool CloseAllProfitablePositions(string symbol, ulong magicNumber); bool CloseAllProfitableBuyPositions(string symbol, ulong magicNumber); bool CloseAllProfitableSellPositions(string symbol, ulong magicNumber); bool CloseAllLossPositions(string symbol, ulong magicNumber); bool CloseAllLossBuyPositions(string symbol, ulong magicNumber); bool CloseAllLossSellPositions(string symbol, ulong magicNumber); //-- Position Status Monitoring Functions int BuyPositionsTotal(); int SellPositionsTotal(); double PositionsTotalVolume(); double BuyPositionsTotalVolume(); double SellPositionsTotalVolume(); double BuyPositionsProfit(); double SellPositionsProfit(); //-- Positions Filtered By Magic Number Status Monitoring Functions int MagicPositionsTotal(ulong magicNumber); int MagicBuyPositionsTotal(ulong magicNumber); int MagicSellPositionsTotal(ulong magicNumber); double MagicPositionsTotalVolume(ulong magicNumber); double MagicBuyPositionsTotalVolume(ulong magicNumber); double MagicSellPositionsTotalVolume(ulong magicNumber); double MagicPositionsProfit(ulong magicNumber); double MagicBuyPositionsProfit(ulong magicNumber); double MagicSellPositionsProfit(ulong magicNumber); //-- Positions Filtered By Symbol and/or Magic Number Status Monitoring Functions int SymbolPositionsTotal(string symbol, ulong magicNumber); int SymbolBuyPositionsTotal(string symbol, ulong magicNumber); int SymbolSellPositionsTotal(string symbol, ulong magicNumber); double SymbolPositionsTotalVolume(string symbol, ulong magicNumber); double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber); double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber); double SymbolPositionsProfit(string symbol, ulong magicNumber); double SymbolBuyPositionsProfit(string symbol, ulong magicNumber); double SymbolSellPositionsProfit(string symbol, ulong magicNumber); //-- Log and Data Display Functions string AccountPositionsStatus(bool formatForComment); string MagicPositionsStatus(ulong magicNumber, bool formatForComment); string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment); #import //--- Closing import directive
Импортировав библиотеку, вы теперь можете без труда открывать, закрывать, изменять или извлекать данные о состоянии позиции с помощью простых вызовов функций. Чтобы проиллюстрировать это, создадим три простых советника в следующих разделах.
Разработка советника Dual VIDyA Trailing Stop на основе EX5-библиотеки для управления позициями
В этом разделе мы разработаем советник по стратегии трейлинг-стопа на основе технического индикатора Variable Index Dynamic Average (VIDyA), чтобы проиллюстрировать применение EX5-библиотеки для управления позициями в реальном торговом приложении.
Стратегия трейлинг-стопа VIDyA будет использовать пару динамических скользящих технических индикаторов с переменным индексом для генерации сигналов на покупку и продажу. Поскольку индикатор VIDyA отображается на графике в виде линии, мы будем использовать стратегию пересечения линий для подачи сигнала о новой сделке. Для реализации стратегии пересечения пары индикаторов должны иметь разные настройки. Первый индикатор VIDyA с меньшими входными значениями будет называться fast VIDyA (быстрый VIDyA), поскольку он будет реагировать и генерировать сигналы быстрее. Второй, с более высокими входными значениями, будет называться slow VIDyA (медленный VIDyA), поскольку он медленнее реагирует на изменение цен. Для входа на покупку линия fast VIDyA должна быть выше линии slow VIDyA, а для входа на продажу линия fast VIDyA должна быть ниже линии slow VIDyA.
Создадим новый советник в среде MetaEditor, создав новый файл в Мастере MQL Wizard и назвав его DualVidyaTrader.mq5. Поскольку наш советник будет использовать библиотеку PositionsManager.ex5, первым шагом является импорт и вставка описаний прототипов библиотечных функций, как описано ранее. Поместите сегмент import библиотеки под директивами #property. Поскольку библиотека содержит много функций, мы не будем импортировать или использовать их все. Импортируем только прототипы функций, перечисленные в коде ниже.
//--- Import the PositionsManager EX5 Library #import "Toolkit/PositionsManager.ex5" //-- Open the ex5 import directive //-- Prototype function descriptions of the EX5 PositionsManager library bool OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment); bool OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment); bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss); int MagicPositionsTotal(ulong magicNumber); int MagicBuyPositionsTotal(ulong magicNumber); int MagicSellPositionsTotal(ulong magicNumber); bool CloseAllProfitableBuyPositions(string symbol, ulong magicNumber); bool CloseAllProfitableSellPositions(string symbol, ulong magicNumber); string MagicPositionsStatus(ulong magicNumber, bool formatForComment); #import //-- Close the ex5 import directive
После сегмента import библиотеки PositionsManager.ex5 добавим введенные пользователем глобальные переменные, как показано далее.
input group "" input ulong magicNo = 1234; input ENUM_TIMEFRAMES timeframe = PERIOD_H1; input ENUM_APPLIED_PRICE appliedPrice = PRICE_CLOSE; // Applied VIDyA Price //-- Fast Vidya user inputs input group "-- FAST VIDyA INPUTS" input int fast_cmoPeriod = 5; // Fast Chande Momentum Period input int fast_maPeriod = 10; // Fast MA Smoothing Period input int fast_emaShift = 0; // Fast Horizontal Shift //-- Slow Vidya user inputs input group "-- SLOW VIDyA INPUTS" input int slow_cmoPeriod = 9; // Slow Chande Momentum Period input int slow_maPeriod = 12; // Slow MA Smoothing Period input int slow_emaShift = 0; // Slow Horizontal Shift input group "-- PROFIT MANAGEMENT" input bool liquidateProfitOnCrossover = false; // Liquidate Profit On VIDyA Signal input bool enableTrailingStops = true; // Use Trailing Stop Losses
Создадим больше глобальных переменных для хранения стоп-лосса, тейк-профита, скользящего стоп-лосса и значений лота или объема.
//-- Get and save the SL, trailingSL and TP values from the spread int spreadMultiForSl = 1000; int spreadMultiForTrailingSl = 300; int spreadMultiForTp = 1000; int sl = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForSl; int trailingSl = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForTrailingSl; int tp = int(SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)) * spreadMultiForTp; //-- Set the lot or volume to the symbol allowed min value double lotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
Создадим переменные технического индикатора VIDyA в глобальной области видимости, чтобы обеспечить к ним доступ из любой части кода нашего советника.
//-- Vidya indicator variables double fastVidya[], slowVidya[]; int fastVidyaHandle, slowVidyaHandle; bool buyOk, sellOk, vidyaBuy, vidyaSell; string vidyaTrend;
После раздела глобальных переменных создадим функцию инициализации советника, который будет вызываться из стандартной функции обработки событий MQL5 OnInit(), которая впервые выполняется при запуске или инициализации советника. Назовем эту функцию GetInit(). В этой функции мы выполним все инициализации данных, включая инициализацию индикатора VIDyA и обработку запуска.
int GetInit() { int returnVal = 1; //-- Helps to regulate and prevent openning multiple trades on a single signal trigger buyOk = true; sellOk = true; //-- Create the fast iVIDyA indicator handle fastVidyaHandle = iVIDyA(_Symbol, timeframe, fast_cmoPeriod, fast_maPeriod, fast_emaShift, appliedPrice); if(fastVidyaHandle < 0) { Print("Error creating fastVidyaHandle = ", INVALID_HANDLE); Print("Handle creation: Runtime error = ", GetLastError()); //-- Close the EA if the handle is not properly loaded return(-1); } ArraySetAsSeries(fastVidya, true); //-- set the vidya array to series access //-- Create the slow iVIDyA indicator handle slowVidyaHandle = iVIDyA(_Symbol, timeframe, slow_cmoPeriod, slow_maPeriod, slow_emaShift, appliedPrice); if(slowVidyaHandle < 0) { Print("Error creating vidyaHandle = ", INVALID_HANDLE); Print("Handle creation: Runtime error = ", GetLastError()); //-- Close the EA if the handle is not properly loaded return(-1); } ArraySetAsSeries(slowVidya, true); //-- set the vidya array to series access return(returnVal); }
Теперь создадим функцию деинициализации и назовем ее GetDeinit(). Эта функция будет вызываться в стандартной функции обработки событий OnDeinit() для выполнения общесистемной очистки всех ресурсов, используемых советником. Это включает в себя высвобождение индикатора VIDyA, высвобождение всех ресурсов, привязанных к массивам хэндлов индикатора, и удаление любых комментариев или объектов графика.
void GetDeinit() //-- De-initialize the robot on shutdown and clean everything up { //-- Delete the vidya handles and de-allocate the memory spaces occupied IndicatorRelease(fastVidyaHandle); ArrayFree(fastVidya); IndicatorRelease(slowVidyaHandle); ArrayFree(slowVidya); //-- Delete and clear all chart displayed messages Comment(""); }
Далее нам необходимо создать пользовательскую функцию для обнаружения и извлечения торговых сигналов, генерируемых нашей парой индикаторов VIDyA. Функция будет называться GetVidya(). Она будет выполняться и обновляться каждый раз при поступлении нового тика, чтобы гарантировать точность генерации сигнала и его актуальность.
void GetVidya() { //-- Get vidya line directions if(CopyBuffer(fastVidyaHandle, 0, 0, 100, fastVidya) <= 0 || CopyBuffer(slowVidyaHandle, 0, 0, 100, slowVidya) <= 0) { return; } //-- Reset vidya status variables vidyaBuy = false; vidyaSell = false; vidyaTrend = "FLAT"; //-- Scan for vidya crossover buy signal if(fastVidya[1] > slowVidya[1]) { //-- Save the vidya signal vidyaTrend = "BUY/LONG"; vidyaBuy = true; vidyaSell = false; } //-- Scan for vidya crossover sell signal if(fastVidya[1] < slowVidya[1]) { //-- Save the vidya signal vidyaTrend = "SELL/SHORT"; vidyaSell = true; vidyaBuy = false; } }
Теперь, когда мы создали функцию для получения и обновления сигнала VIDyA, давайте создадим еще одну пользовательскую функцию, которая будет выполняться на каждом новом тике для сканирования и открытия новых позиций на основе текущего сигнала VIDyA. Назовем ее ScanForTradeOpportunities(). В этой функции мы вызовем и выполним прототипы функций открытия и статуса позиции, импортированные из нашей библиотеки PositionsManager.ex5 в этой функции.
void ScanForTradeOpportunities() { //-- Get the VIDyA signal GetVidya(); if(MagicPositionsTotal(magicNo) == 0) { buyOk = true; sellOk = true; } //-- Check for a buy entry when a VIDyA buy signal is found if(buyOk && vidyaBuy) //-- Open a new buy position { if(OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Vidya_BUY: " + IntegerToString(MagicBuyPositionsTotal(magicNo) + 1))) { buyOk = false; sellOk = true; } //-- Market has a strong buy trend, close all profitable sell positions if(liquidateProfitOnCrossover) { CloseAllProfitableSellPositions(_Symbol, magicNo); } } //-- Check for a sell entry when a VIDyA sell signal is found if(sellOk && vidyaSell) //-- Open a new sell position { if(OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Vidya_SELL: " + IntegerToString(MagicSellPositionsTotal(magicNo) + 1))) { sellOk = false; buyOk = true; } //-- Market has a strong sell trend, close all profitable buy positions if(liquidateProfitOnCrossover) { CloseAllProfitableBuyPositions(_Symbol, magicNo); } } }
Нам также необходимо проверить и установить трейлинг-стоп-лоссы по всем открытым позициям. Это будет просто, так как наша библиотека PositionsManager.ex5 содержит прототип функции трейлинг-стоп-лосса, который поможет нам в этом. Создадим новую функцию CheckAndSetTrailingSl() для сканирования всех открытых позиций и извлечения их тикетов для использования в качестве параметров в импортируемом прототипе функции SetTrailingStopLoss().
void CheckAndSetTrailingSl() { int totalOpenPostions = PositionsTotal(); for(int x = 0; x < totalOpenPostions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); int positionType = int(PositionGetInteger(POSITION_TYPE)); //-- modify only the positions we have opened with this EA (magic number) if(selectedSymbol != _Symbol && positionMagicNo != magicNo) { continue; } //-- Only set the trailing stop loss when the market trend is in the opposing direction of the position type if((positionType == POSITION_TYPE_BUY && vidyaBuy) || (positionType == POSITION_TYPE_SELL && vidyaSell)) { continue; } //--- set the trailing stop loss SetTrailingStopLoss(positionTicket, trailingSl); //-- call the imported function from our ex5 library } }
Теперь, когда мы создали все важные модули для нашего советника, объединим их в функции обработки событий OnTick(), которая выполняется при каждом новом тике. Расположите их в указанном ниже порядке, чтобы гарантировать, что они систематически выполняют нашу торговую систему в правильной последовательности.
void OnTick() { //-- Scan and open new positions based on the vidya signal ScanForTradeOpportunities(); //-- Check and set the trailing stop if(enableTrailingStops) { CheckAndSetTrailingSl(); } //-- Display the vidya trend and positions status for the EA's magicNo Comment( "\nvidyaTrend: ", vidyaTrend, MagicPositionsStatus(magicNo, true) ); }
Наконец, не забудьте поместить функции инициализации и деинициализации в соответствующие стандартные функции обработки событий MQL5.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- if(GetInit() <= 0) { return(INIT_FAILED); } return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- GetDeinit(); }
Файл исходного кода советника DualVidyaTrader.mq5 приложен в конце статьи. Я прикрепил полный файл исходного кода, чтобы у вас были все необходимые компоненты для внедрения и настройки торговой стратегии по мере необходимости.
При компиляции и загрузке нового советника DualVidyaTrader в MetaTrader 5 вы заметите, что на вкладке Dependencies (зависимости) все прототипы библиотечных функций, импортированные из PositionsManager.ex5 перечислены вместе с полным путем к файлу, где сохранена EX5-библиотека. Это гарантирует, что все необходимые зависимости будут правильно указаны до загрузки советника на график. Если будут обнаружены какие-либо ошибки ссылок на библиотеки, подобные тем, которые обсуждались ранее в статье, они будут выведены на вкладке "Эксперты" или "Журнал" в окне "Инструменты" MetaTrader 5.
Торговая панель управления позициями на базе EX5-библиотеки
Во втором примере мы создадим простую торговую панель с графическим пользовательским интерфейсом (GUI) на базе нашей библиотеки PositionsManager.ex5.
Создадим новый советник в среде MetaEditor, создав новый файл в Мастере MQL и назвав его PositionsManagerPanel.mq5. Под сегментом директив #property импортируйте библиотеку PositionsManager.ex5. В разделе описаний функций import импортируйте только следующие прототипы функций.
//+------------------------------------------------------------------+ //| EX5 PositionsManager imports | //+------------------------------------------------------------------+ #import "Toolkit/PositionsManager.ex5" //-- Open import directive //-- Function descriptions for the imported function prototypes //--Position Execution and Modification Functions bool OpenBuyPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment); bool OpenSellPosition(ulong magicNumber, string symbol, double lotSize, int sl, int tp, string positionComment); bool SetSlTpByTicket(ulong positionTicket, int sl, int tp); bool ClosePositionByTicket(ulong positionTicket); bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss); bool CloseAllPositions(string symbol, ulong magicNumber); bool CloseAllBuyPositions(string symbol, ulong magicNumber); bool CloseAllSellPositions(string symbol, ulong magicNumber); bool CloseAllMagicPositions(ulong magicNumber); bool CloseAllProfitablePositions(string symbol, ulong magicNumber); bool CloseAllLossPositions(string symbol, ulong magicNumber); //--Position Status Monitoring Functions int BuyPositionsTotal(); int SellPositionsTotal(); double PositionsTotalVolume(); double BuyPositionsTotalVolume(); double SellPositionsTotalVolume(); double BuyPositionsProfit(); double SellPositionsProfit(); int MagicPositionsTotal(ulong magicNumber); int MagicBuyPositionsTotal(ulong magicNumber); int MagicSellPositionsTotal(ulong magicNumber); double MagicPositionsTotalVolume(ulong magicNumber); double MagicBuyPositionsTotalVolume(ulong magicNumber); double MagicSellPositionsTotalVolume(ulong magicNumber); double MagicPositionsProfit(ulong magicNumber); double MagicBuyPositionsProfit(ulong magicNumber); double MagicSellPositionsProfit(ulong magicNumber); int SymbolPositionsTotal(string symbol, ulong magicNumber); int SymbolBuyPositionsTotal(string symbol, ulong magicNumber); int SymbolSellPositionsTotal(string symbol, ulong magicNumber); double SymbolPositionsTotalVolume(string symbol, ulong magicNumber); double SymbolBuyPositionsTotalVolume(string symbol, ulong magicNumber); double SymbolSellPositionsTotalVolume(string symbol, ulong magicNumber); double SymbolPositionsProfit(string symbol, ulong magicNumber); double SymbolBuyPositionsProfit(string symbol, ulong magicNumber); double SymbolSellPositionsProfit(string symbol, ulong magicNumber); string AccountPositionsStatus(bool formatForComment); string MagicPositionsStatus(ulong magicNumber, bool formatForComment); string SymbolPositionsStatus(string symbol, ulong magicNumber, bool formatForComment); #import //--- Close import directive
PositionsManagerPanel.mq5 будет содержать только один пользовательский ввод (магическое число).
//--User input variables input ulong magicNo = 101010;
Далее создадим глобальные переменные для хранения volumeLot, sl и tp.
//-- Global variables //----------------------- //-- Get the current symbol spread and multiply it by a significant number //-- to simulate user-input SL and TP values double volumeLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); int sl = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * 50; int tp = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD) * 100;
Создадим наш первый графический объект, который будет служить фоном для нашего графического пользовательского интерфейса. Для этой цели мы будем использовать прямоугольную метку. Для этого мы создадим пользовательскую функцию под названием CreateRectangleLabel().
//+-----------------------------------------------------------------------+ //| CreateRectangleLabel(): Creates a rectangle label on the chart window | //+-----------------------------------------------------------------------+ void CreateRectangleLabel() { //--- Detect if we have an object named the same as our rectangle label if(ObjectFind(0, "mainRectangleLabel") >= 0) { //--- Delete the specified object if it is not a rectangle label if(ObjectGetInteger(0, "mainRectangleLabel", OBJPROP_TYPE) != OBJ_RECTANGLE_LABEL) { ObjectDelete(0, "mainRectangleLabel"); } } else { //-- Create the mainRectangleLabel ObjectCreate(0, "mainRectangleLabel", OBJ_RECTANGLE_LABEL, 0, 0, 0); } //--- Set up the new rectangle label properties ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_XDISTANCE, 240); ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_YDISTANCE, 2); ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_XSIZE, 460); ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_YSIZE, 520); ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_BGCOLOR, clrMintCream); ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_BACK, false); ObjectSetInteger(0, "mainRectangleLabel", OBJPROP_HIDDEN, true); }
Нам также нужны метки для отображения текста на нашей торговой панели. Создадим еще одну пользовательскую функцию CreateLabel() для решения этой задачи.
//+---------------------------------------------------------+ //| CreateLabel(): Creates a text label on the chart window | //+---------------------------------------------------------+ void CreateLabel( string labelName, int xDistance, int yDistance, int xSize, int ySize, string labelText, color textColor, string fontType, int fontSize ) { //--- Detect if we have an object with the same name as our label if(ObjectFind(0, labelName) >= 0) { //--- Delete the specified object if it is not a label if(ObjectGetInteger(0, labelName, OBJPROP_TYPE) != OBJ_LABEL) { ObjectDelete(0, labelName); } } else { //-- Create the label ObjectCreate(0, labelName, OBJ_LABEL, 0, 0, 0); } //--- Set up the new rectangle label properties ObjectSetInteger(0, labelName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, labelName, OBJPROP_XDISTANCE, xDistance); ObjectSetInteger(0, labelName, OBJPROP_YDISTANCE, yDistance); ObjectSetInteger(0, labelName, OBJPROP_XSIZE, xSize); ObjectSetInteger(0, labelName, OBJPROP_YSIZE, ySize); ObjectSetString(0, labelName, OBJPROP_TEXT, labelText); ObjectSetInteger(0, labelName, OBJPROP_COLOR, textColor); ObjectSetString(0, labelName, OBJPROP_FONT, fontType); ObjectSetInteger(0, labelName, OBJPROP_FONTSIZE, fontSize); ObjectSetInteger(0, labelName, OBJPROP_BACK, false); ObjectSetInteger(0, labelName, OBJPROP_HIDDEN, true); ObjectSetInteger(0, labelName, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, labelName, OBJPROP_SELECTED, false); }
Для выполнения различных торговых операций на нашей торговой панели необходимы кликабельные или адаптивные кнопки. Поэтому нам необходимо создать специальную функцию для управления созданием кнопок. Назовем эту функцию CreateButton().
//+------------------------------------------------------+ //| CreateButton(): Creates buttons on the chart window | //+------------------------------------------------------+ void CreateButton( string btnName, int xDistance, int yDistance, int xSize, int ySize, string btnText, string tooltip, color textColor, string fontType, int fontSize, color bgColor ) { //--- Detect if we have an object named the same as our button if(ObjectFind(0, btnName) >= 0) { //--- Delete the specified object if it is not a button if(ObjectGetInteger(0, btnName, OBJPROP_TYPE) != OBJ_BUTTON) { ObjectDelete(0, btnName); } } else { //-- Create the button ObjectCreate(0, btnName, OBJ_BUTTON, 0, 0, 0); } //--- Set up the new button properties ObjectSetInteger(0, btnName, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, btnName, OBJPROP_XDISTANCE, xDistance); ObjectSetInteger(0, btnName, OBJPROP_YDISTANCE, yDistance); ObjectSetInteger(0, btnName, OBJPROP_XSIZE, xSize); ObjectSetInteger(0, btnName, OBJPROP_YSIZE, ySize); ObjectSetString(0, btnName, OBJPROP_TEXT, btnText); ObjectSetString(0, btnName, OBJPROP_TOOLTIP, tooltip); ObjectSetInteger(0, btnName, OBJPROP_COLOR, textColor); ObjectSetString(0, btnName, OBJPROP_FONT, fontType); ObjectSetInteger(0, btnName, OBJPROP_FONTSIZE, fontSize); ObjectSetInteger(0, btnName, OBJPROP_BGCOLOR, bgColor); }
Теперь нам нужна еще одна пользовательская функция для загрузки всех различных объектов графика и графических компонентов пользовательского ввода, созданных с помощью функций, созданных выше. Назовем эту функцию LoadChartObjects().
//+--------------------------------------------------------------------+ //| LoadChartObjects(): Create and load the buttons and chart objects | //| for demonstrating how the imported library functions work | //+--------------------------------------------------------------------+ void LoadChartObjects() { //-- Create the rectangle label first CreateRectangleLabel(); //-- Create the heading label CreateLabel( "headingLabel", 250, 10, 440, 60, "PositionsManager ex5 Library Demo Trade Panel", clrMidnightBlue, "Calibri", 10 ); //-- Create the second heading label CreateLabel( "headingLabel2", 250, 30, 440, 60, ("Trading " + _Symbol + " with Magic Number: " + (string)magicNo), clrBlack, "Consolas", 11 ); //-- "BUY": Button to call the imported ex5 OpenBuyPosition() function CreateButton( "OpenBuyPositionBtn", 250, 50, 215, 35, "BUY", "OpenBuyPosition() Function", clrMintCream, "Arial Black", 10, clrDodgerBlue ); //-- "SELL": Button to call the imported ex5 OpenSellPosition() function CreateButton( "OpenSellPositionBtn", 475, 50, 215, 35, "SELL", "OpenSellPosition() Function", clrMintCream, "Arial Black", 10, clrCrimson ); //-- "SetSlTpByTicket": Button to call the imported ex5 SetSlTpByTicket() function CreateButton( "SetSlTpBtn", 250, 90, 215, 35, "SetSlTpByTicket", "SetSlTpByTicket() Function", clrMintCream, "Arial Black", 10, clrDarkSlateGray ); //-- "SetTrailingStopLoss": Button to call the imported ex5 SetTrailingStopLoss() function when clicked CreateButton( "SetTrailingStopLossBtn", 475, 90, 215, 35, "SetTrailingStopLoss", "SetTrailingStopLoss Function", clrMintCream, "Arial Black", 10, clrDarkSlateGray ); //-- "ClosePositionsByTicket": Button to call the imported ex5 ClosePositionByTicket() function CreateButton( "ClosePositionsBtn", 250, 130, 215, 35, "ClosePositionsByTicket", "ClosePositionByTicket() Function", clrMintCream, "Arial Black", 10, clrMaroon ); //-- "CloseAllSymbolPositions": Button to call the imported ex5 CloseAllSymbolPositions() function CreateButton( "CloseAllPositionsBtn", 475, 130, 215, 35, "CloseAllPositions", "CloseAllPositions() Function", clrMintCream, "Arial Black", 10, clrMaroon ); //-- "CloseAllBuySymbolPositions": Button to call the imported ex5 CloseAllBuySymbolPositions() function CreateButton( "CloseAllBuyPositionsBtn", 250, 170, 215, 35, "CloseAllBuyPositions", "CloseAllBuyPositions() Function", clrMintCream, "Arial Black", 10, clrBrown ); //-- "CloseAllSellSymbolPositions": Button to call the imported ex5 CloseAllSellSymbolPositions() function CreateButton( "CloseAllSellPositionsBtn", 475, 170, 215, 35, "CloseAllSellPositions", "CloseAllSellPositions() Function", clrMintCream, "Arial Black", 10, clrBrown ); //-- "CloseAllMagicPositions": Button to call the imported ex5 CloseAllMagicPositions() function CreateButton( "CloseAllMagicPositionsBtn", 250, 210, 440, 35, "CloseAllMagicPositions", "CloseAllMagicPositions() Function", clrMintCream, "Arial Black", 10, C'203,18,55' ); //-- "CloseAllProfitablePositions": Button to call the imported ex5 CloseAllMagicPositions() function CreateButton( "CloseAllProfitablePositionsBtn", 250, 250, 215, 35, "CloseAllProfitablePositions", "CloseAllProfitablePositions() Function", clrMintCream, "Arial Black", 10, clrSeaGreen ); //-- "CloseAllLossPositions": Button to call the imported ex5 CloseAllLossPositions() function CreateButton( "CloseAllLossPositionsBtn", 475, 250, 215, 35, "CloseAllLossPositions", "CloseAllLossPositions() Function", clrMintCream, "Arial Black", 10, C'179,45,0' ); //-- Create the bottomHeadingLabel CreateLabel( "bottomHeadingLabel", 250, 310, 440, 60, (_Symbol + " - (Magic Number: " + (string)magicNo + ") Positions Status"), clrBlack, "Calibri", 12 ); //-- Create totalOpenPositionsLabel CreateLabel( "totalOpenPositionsLabel", 250, 340, 440, 60, (" Total Open: " + (string)MagicPositionsTotal(magicNo)), clrNavy, "Consolas", 11 ); //-- Create totalPositionsVolumeLabel CreateLabel( "totalPositionsVolumeLabel", 250, 360, 440, 60, (" Total Volume: " + (string)NormalizeDouble(MagicPositionsTotalVolume(magicNo), 2)), clrNavy, "Consolas", 11 ); //-- Create the totalPositionsProfitLabel CreateLabel( "totalPositionsProfitLabel", 250, 380, 100, 60, ( " Total Profit: " + (string)(NormalizeDouble(MagicPositionsProfit(magicNo), 2)) + " " + AccountInfoString(ACCOUNT_CURRENCY) ), clrNavy, "Consolas", 11 ); //-- Create the buyPositionsHeadingLabel CreateLabel( "buyPositionsHeadingLabel", 250, 410, 440, 60, ("BUY POSITIONS:"), clrBlack, "Calibri", 12 ); //-- Create the totalBuyPositionsLabel CreateLabel( "totalBuyPositionsLabel", 250, 430, 440, 60, (" Total Open: " + (string)MagicBuyPositionsTotal(magicNo)), clrNavy, "Consolas", 11 ); //-- Create the totalBuyPositionsVolumeLabel CreateLabel( "totalBuyPositionsVolumeLabel", 250, 450, 440, 60, (" Total Volume: " + (string)NormalizeDouble(MagicBuyPositionsTotalVolume(magicNo), 2)), clrNavy, "Consolas", 11 ); //-- Create the totalBuyPositionsProfitLabel CreateLabel( "totalBuyPositionsProfitLabel", 250, 470, 440, 60, ( " Total Profit: " + (string)(NormalizeDouble(MagicBuyPositionsProfit(magicNo), 2)) + " " + AccountInfoString(ACCOUNT_CURRENCY) ), clrNavy, "Consolas", 11 ); //-- Create the sellPositionsHeadingLabel CreateLabel( "sellPositionsHeadingLabel", 475, 410, 440, 60, ("SELL POSITIONS:"), clrBlack, "Calibri", 12 ); //-- Create the totalSellPositionsLabel CreateLabel( "totalSellPositionsLabel", 475, 430, 440, 60, (" Total Open: " + (string)MagicSellPositionsTotal(magicNo)), clrNavy, "Consolas", 11 ); //-- Create the totalSellPositionsVolumeLabel CreateLabel( "totalSellPositionsVolumeLabel", 475, 450, 440, 60, (" Total Volume: " + (string)NormalizeDouble(MagicSellPositionsTotalVolume(magicNo), 2)), clrNavy, "Consolas", 11 ); //-- Create the totalSellPositionsProfitLabel CreateLabel( "totalSellPositionsProfitLabel", 475, 470, 100, 60, ( " Total Profit: " + (string)(NormalizeDouble(MagicSellPositionsProfit(magicNo), 2)) + " " + AccountInfoString(ACCOUNT_CURRENCY) ), clrNavy, "Consolas", 11 ); //--- Redraw the chart to refresh it so that it loads our new chart objects ChartRedraw(); //--- }
Следующая пользовательская функция будет отвечать за очистку и удаление всех объектов графика и данных при завершении работы или деинициализации советника. Назовем ее DeleteChartObjects(). Она будет помещена и выполнена в стандартной функции обработки событий OnDeinit().
//+------------------------------------------------------------------------------+ //| DeleteChartObjects(): Delete all the chart objects when the EA is terminated | //| on De-initialization | //+------------------------------------------------------------------------------+ void DeleteChartObjects() { //--- //--- Clean up and delete all the buttons or graphical objects ObjectDelete(0, "OpenBuyPositionBtn"); ObjectDelete(0, "OpenSellPositionBtn"); ObjectDelete(0, "SetSlTpBtn"); ObjectDelete(0, "SetTrailingStopLossBtn"); ObjectDelete(0, "ClosePositionsBtn"); ObjectDelete(0, "CloseAllPositionsBtn"); ObjectDelete(0, "CloseAllBuyPositionsBtn"); ObjectDelete(0, "CloseAllSellPositionsBtn"); ObjectDelete(0, "CloseAllMagicPositionsBtn"); ObjectDelete(0, "CloseAllProfitablePositionsBtn"); ObjectDelete(0, "CloseAllLossPositionsBtn"); ObjectDelete(0, "mainRectangleLabel"); ObjectDelete(0, "headingLabel"); ObjectDelete(0, "headingLabel2"); ObjectDelete(0, "bottomHeadingLabel"); ObjectDelete(0, "totalOpenPositionsLabel"); ObjectDelete(0, "totalPositionsVolumeLabel"); ObjectDelete(0, "totalPositionsProfitLabel"); ObjectDelete(0, "buyPositionsHeadingLabel"); ObjectDelete(0, "totalBuyPositionsLabel"); ObjectDelete(0, "totalBuyPositionsVolumeLabel"); ObjectDelete(0, "totalBuyPositionsProfitLabel"); ObjectDelete(0, "sellPositionsHeadingLabel"); ObjectDelete(0, "totalSellPositionsLabel"); ObjectDelete(0, "totalSellPositionsVolumeLabel"); ObjectDelete(0, "totalSellPositionsProfitLabel"); }
Создадим пользовательские функции, которые будут реализовывать некоторые импортированные функции библиотеки PositionsManager.ex5. Первая функция в этой группе, которую мы назовем ModifySlTp(), будет отвечать за изменение стоп-лосса (sl) и тейк-профита (tp) всех позиций, открытых этим советником, которые соответствуют введенному пользователем магическому числу. Эта функция будет выполняться каждый раз при нажатии кнопки setSLTP на графике.
//+-------------------------------------------------------------------------+ // ModifySlTp(): This function demonstrates how to use the imported ex5 | // bool SetSlTpByTicket(ulong positionTicket, int sl, int tp); | // It runs this function when the setSLTP button on the chart is clicked. | //+-------------------------------------------------------------------------+ void ModifySlTp() { //-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with int totalOpenPostions = PositionsTotal(); //--- Scan open positions for(int x = 0; x < totalOpenPostions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); //-- modify only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart if(selectedSymbol != _Symbol && positionMagicNo != magicNo) { continue; } //--- modify the sl and tp of the position SetSlTpByTicket(positionTicket, sl, tp);//-- call the imported function from our ex5 library } }
Следующая функция, SetTrailingSl(), будет отвечать за обновление трейлинг-стоп-лосса. Она будет выполняться и при нажатии на кнопку SetTrailingStopLoss на графике, и на каждом новом входящем тике в функции обработки событий OnTick().
//+-----------------------------------------------------------------------------------+ // SetTrailingSl(): This function demonstrates how to use the imported ex5 | // bool SetTrailingStopLoss(ulong positionTicket, int trailingStopLoss); | // It runs this function when the SetTrailingStopLoss button on the chart is clicked. | //+-----------------------------------------------------------------------------------+ void SetTrailingSl() { int trailingSl = sl; //-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with int totalOpenPostions = PositionsTotal(); //--- Scan open positions for(int x = 0; x < totalOpenPostions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); //-- modify only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart if(selectedSymbol != _Symbol && positionMagicNo != magicNo) { continue; } //--- set the trailing stop loss SetTrailingStopLoss(positionTicket, trailingSl); //-- call the imported function from our ex5 library } }
Функция ClosePositionWithTicket() будет отвечать за закрытие всех открытых позиций и будет выполняться при нажатии на кнопку ClosePositions на графике.
//+-----------------------------------------------------------------------------------+ // ClosePositionWithTicket(): This function demonstrates how to use the imported ex5 | // bool ClosePositionByTicket(ulong positionTicket) | // It runs this function when the ClosePositions button on the chart is clicked. | //+-----------------------------------------------------------------------------------+ void ClosePositionWithTicket() { //-- Get positions that we have openend with the chart buy and sell buttons to test the imported function with int totalOpenPostions = PositionsTotal(); //--- Scan open positions for(int x = 0; x < totalOpenPostions; x++) { //--- Get position properties ulong positionTicket = PositionGetTicket(x); //-- Get ticket to select the position string selectedSymbol = PositionGetString(POSITION_SYMBOL); ulong positionMagicNo = PositionGetInteger(POSITION_MAGIC); //-- close only the positions we have opened with this EA (magic number) using the BUY and SELL buttons on the chart if(selectedSymbol != _Symbol && positionMagicNo != magicNo) { continue; } //--- Close the position ClosePositionByTicket(positionTicket);//-- call the imported function from our ex5 library } }
Последняя функция — стандартная MQL5-функция OnChartEvent(), которая будет определять нажатие различных кнопок и выполнять соответствующие действия. Почти все импортированные функции управления позициями из библиотеки PositionsManager.ex5 будут вызываться и выполняться из этой функции.
//+------------------------------------------------------------------+ //| ChartEvent function to detect when the buttons are clicked | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- //--- Detected a CHARTEVENT_CLICK event if(id == CHARTEVENT_OBJECT_CLICK) { Print(__FUNCTION__, ": ", sparam); //--- Buy when OpenBuyPositionBtn button (BUY) is pressed or clicked if(sparam == "OpenBuyPositionBtn") { //-- Call our imported function from the Toolkit/PositionsManager ex5 library OpenBuyPosition(magicNo, _Symbol, volumeLot, sl, tp, "ex5 PositionsManager"); //--- Release and unpress the button ObjectSetInteger(0, "OpenBuyPositionBtn", OBJPROP_STATE, false); } //--- Sell when OpenSellPositionBtn button (SELL) is pressed if(sparam == "OpenSellPositionBtn") { //-- Call our imported function from the Toolkit/PositionsManager ex5 library OpenSellPosition(magicNo, _Symbol, volumeLot, sl, tp, "ex5 PositionsManager"); //OpenSellPosition(magicNo, "NON-EXISTENT-Symbol-Name"/*_Symbol*/, volumeLot, sl, tp, "ex5 PositionsManager"); //--- Release and unpress the button ObjectSetInteger(0, "OpenSellPositionBtn", OBJPROP_STATE, false); } //--- Modify specified positions SL and TP when SetSlTpBtn button (setSLTP) is pressed if(sparam == "SetSlTpBtn") { ModifySlTp();//-- Modify the SL and TP of the positions generated by the BUY and SELL buttons //--- Release and unpress the button ObjectSetInteger(0, "SetSlTpBtn", OBJPROP_STATE, false); } //--- Set the Trailing Stop Loss when SetSlTpBtn button (SetTrailingStopLossBtn) is pressed if(sparam == "SetTrailingStopLossBtn") { SetTrailingSl();//-- Set the Trailing Stop Loss for the positions generated by the BUY and SELL buttons //--- Release and unpress the button ObjectSetInteger(0, "SetTrailingStopLossBtn", OBJPROP_STATE, false); } //--- Close specified positions when SetSlTpBtn button (setSLTP) is pressed if(sparam == "ClosePositionsBtn") { ClosePositionWithTicket();//-- Close all the positions generated by the BUY and SELL buttons //--- Release and unpress the button ObjectSetInteger(0, "ClosePositionsBtn", OBJPROP_STATE, false); } //--- Close all positions for the current symbol when the CloseAllPositionsBtn button is pressed if(sparam == "CloseAllPositionsBtn") { CloseAllPositions(_Symbol, 0);//-- Close all the open symbol positions //--- Release and unpress the button ObjectSetInteger(0, "CloseAllPositionsBtn", OBJPROP_STATE, false); } //--- Close all buy positions for the current symbol when the CloseAllBuyPositionsBtn button is pressed if(sparam == "CloseAllBuyPositionsBtn") { CloseAllBuyPositions(_Symbol, magicNo);//-- Close all the open symbol buy positions //--- Release and unpress the button ObjectSetInteger(0, "CloseAllBuyPositionsBtn", OBJPROP_STATE, false); } //--- Close all sell positions for the current symbol when the CloseAllSellPositionsBtn button is pressed if(sparam == "CloseAllSellPositionsBtn") { CloseAllSellPositions(_Symbol, magicNo);//-- Close all the open symbol sell positions //--- Release and unpress the button ObjectSetInteger(0, "CloseAllSellPositionsBtn", OBJPROP_STATE, false); } //--- Close all positions with the specified magic number when the CloseAllMagicPositionsBtn button is pressed if(sparam == "CloseAllMagicPositionsBtn") { CloseAllMagicPositions(magicNo);//-- Close all the open positions with the specified magic number //--- Release and unpress the button ObjectSetInteger(0, "CloseAllMagicPositionsBtn", OBJPROP_STATE, false); } //--- Close all profitable positions with the specified symbol and magic number when the CloseAllProfitablePositionsBtn button is pressed if(sparam == "CloseAllProfitablePositionsBtn") { CloseAllProfitablePositions(_Symbol, magicNo);//-- Close all the open profitable positions with the specified symbol and magic number //--- Release and unpress the button ObjectSetInteger(0, "CloseAllProfitablePositionsBtn", OBJPROP_STATE, false); } //--- Close all loss positions with the specified symbol and magic number when the CloseAllLossPositionsBtn button is pressed if(sparam == "CloseAllLossPositionsBtn") { CloseAllLossPositions(_Symbol, magicNo);//-- Close all the open loss positions with the specified symbol and magic number //--- Release and unpress the button ObjectSetInteger(0, "CloseAllLossPositionsBtn", OBJPROP_STATE, false); } //--- Redraw the chart to refresh it ChartRedraw(); } //--- }
Перед запуском советника PositionsTradePanel.mq5 нам нужно включить все необходимые компоненты в функции обработки событий OnInit(), OnDeinit() и OnTick(). Начнем с загрузки всех графических объектов во время инициализации советника функцией LoadChartObjects() в функции OnInit().
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //create buttons to demonstrate how the different ex5 library functions work LoadChartObjects(); //--- return(INIT_SUCCEEDED); }
Вызовем и выполним следующие функции в OnTick().
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //-- Check for profitable positions and set the trailing stop loss on every new tick SetTrailingSl(); //-- Calls the ex5 library function responsible for setting Trailing stops LoadChartObjects(); //--- Update chart objects }
Добавим функцию деинициализации в обработчик событий OnDeinit() для удаления всех графических объектов при закрытии или завершении работы советника.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- //-- Clean up the chart DeleteChartObjects(); //-- Clear any chart comments Comment(""); }
Файл исходного кода для советника PositionsManagerPanel.mq5 приложен в конце статьи.
Сохраним, скомпилируем и загрузим советник PositionsManagerPanel.mq5 на любой график в MetaTrader 5. На вкладке Dependencies (зависимости) вы увидите все прототипы библиотечных функций, импортированные из PositionsManager.ex5, а также полный путь к файлу, где сохранена EX5-библиотека. После загрузки на график протестируем его, открыв несколько позиций и проверив записи на вкладке "Эксперты" в панели "Инструменты" торгового терминала. Мы должны увидеть записи от прототипов функций PositionsManager.ex5.
Заключение
Мы всесторонне рассмотрели EX5-библиотеку для MQL5. Мы увидели их создание, интеграцию и внедрение во внешние MQL5-проекты, включая способы отладки различных ошибок EX5-библиотеки, а также способы их обновления и повторного развертывания. Кроме того, мы создали мощную многофункциональную EX5-библиотеку для управления позициями, дополненную подробной документацией и практическими примерами использования. Я также продемонстрировал, как импортировать и реализовать эту библиотеку в двух различных MQL5-советниках, таким образом предоставив реальные примеры эффективного развертывания EX5-библиотеки. В следующей статье мы воспользуемся аналогичным подходом для разработки комплексной EX5-библиотеки для управления отложенными ордерами, призванной упростить задачи обработки отложенных ордеров в ваших MQL5-приложениях. Спасибо за внимание! Желаю вам всяческих успехов в торговле и программировании!
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/15224
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.





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