
Рецепты MQL5 - Как получить свойства позиции?
Введение
В предыдущей статье Рецепты MQL5 - Вывод информации в печать в разных режимах было показано, как можно быстро сделать скрипт и вывести необходимую информацию тремя разными способами. Теперь создадим скрипт, который получает все свойства позиции и показывает их пользователю.
Сделаем так, чтобы во внешних параметрах скрипта была реализована следующая возможность выбора: получить свойства только одного (текущего) символа или же пройти поочерёдно по всем открытым позициям (если они есть) на всех символах. Просматривать информацию на этот раз будем прямо в диалоговом окне. Это тоже довольно удобный способ и, возможно, кому-нибудь он понравится больше.
Процесс разработки скрипта
Начало программы примерно такое же, как и в предыдущей статье (смотрите код ниже). Сначала идут свойства программы. Далее следует строка с директивой #define, после которой переменной SCRIPT_NAME с помощью функции MQLInfoString() и указанной в ней константы MQL_PROGRAM_NAME, присваивается имя программы. В Справочнике MQL5 вы можете подробнее ознакомиться со всеми возможными значениями для функции MQLInfoString().
Далее идет перечисление режимов. Если напротив каждого идентификатора написать комментарий, то его текст будет отображаться в выпадающем списке во внешних параметрах. Всего два режима:
- Текущий символ - вывести свойства позиции только текущего символа.
- Все символы - вывести свойства позиций всех символов.
Внешний параметр только один (mode), который служит для выбора режима. Комментарий после строки внешнего параметра также будет отображаться и в окне внешних параметров. Это позволяет делать более осмысленные названия параметров, в тот же момент для кода будет более удобным более краткие варианты имён переменных.
#property copyright "Copyright 2012, http://tol64.blogspot.com" #property link "http://tol64.blogspot.com" #property description "email: hello.tol64@gmail.com" #property version "1.0" #property script_show_inputs //--- #define SCRIPT_NAME MQLInfoString(MQL_PROGRAM_NAME) // Имя скрипта //--- // ПЕРЕЧИСЛЕНИЕ РЕЖИМОВ enum ENUM_SYMBOLS_MODE { CURRENT_SYMBOL =0, // Текущий символ ALL_SYMBOLS =1 // Все символы }; //--- // ВХОДНЫЕ ПАРАМЕТРЫ input ENUM_SYMBOLS_MODE mode=CURRENT_SYMBOL; // Режим
Далее по коду следуют глобальные переменные. Глобальные переменные доступны в любом месте программы и для этого должны быть расположены вне функций (обычно - в самом начале программы).
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ long pos_magic=0; // Магический номер string pos_symbol=""; // Символ string pos_comment=""; // Комментарий double pos_swap=0.0; // Своп double pos_commission=0.0; // Комиссия double pos_price=0.0; // Текущая цена позиции double pos_cprice=0.0; // Текущая цена позиции double pos_profit=0.0; // Прибыль/убыток позиции double pos_volume=0.0; // Объём позиции double pos_sl=0.0; // Stop Loss позиции double pos_tp=0.0; // Take Profit позиции datetime pos_time=NULL; // Время открытия позиции long pos_id=0; // Идентификатор позиции ENUM_POSITION_TYPE pos_type=NULL; // Тип позиции //---
В главной функции программы будет вызываться только одна пользовательская функция PrintPositionProperties(), в которой будут совершаться все необходимые операции:
//+------------------------------------------------------------------+ //| ГЛАВНАЯ ФУНКЦИЯ | //+------------------------------------------------------------------+ void OnStart() { PrintPositionProperties(); }
Теперь пошагово рассмотрим построение пользовательской функции PrintPositionProperties(). Сначала напишем каркас, от которого будем двигаться дальше. Он очень простой и в коде выглядит вот так:
//+------------------------------------------------------------------+ //| ОТКРЫВАЕТ ДИАЛОГОВОЕ ОКНО С ДАННЫМИ СИМВОЛА | //+------------------------------------------------------------------+ void PrintPositionProperties() { int err=0; // Переменная для обработки ошибок //--- // Если нужно получить свойства позиции только на текущем символе if(mode==CURRENT_SYMBOL) { } //--- // Если нужно получить свойства позиций на всех символах if(mode==ALL_SYMBOLS) { } }
Всего лишь две ветки, в начале функции также объявлена локальная переменная err для обработки ошибок. Теперь нужно для каждого варианта написать свой сценарий. Будем идти по порядку и займёмся первым, т.е. "Если нужно получить свойства позиции только на текущем символе".
Всё просто. Сначала нужно проверить, есть ли позиция на текущем символе. Для этой проверки в MQL5 есть функция PositionSelect(). Ей в качестве единственного параметра передаётся имя символа. Чтобы передать имя текущего символа? нужно воспользоваться или функцией Symbol() или предопределённой переменной _Symbol, которая уже содержит имя текущего символа. Функция PositionSelect() возвратит положительный результат, если позиция на этом символе есть, или отрицательный результат, если позиции нет или была ошибка.
Код с подробными комментариями для первого варианта можно посмотреть ниже:
//--- // Если есть позиция, то... if(PositionSelect(_Symbol)) { // ...получим её свойства GetPositionProperties(); //--- // Откроем диалоговое окно и выведем в нём все полученные данные MessageBox("Symbol : "+pos_symbol+"\n"+ "Comment : "+pos_comment+"\n"+ "Magic Number : "+IntegerToString(pos_magic)+"\n"+ "Price Open : "+DoubleToString(pos_price,_Digits)+"\n"+ "Current Price : "+DoubleToString(pos_cprice,_Digits)+"\n"+ "Stop Loss : "+DoubleToString(pos_sl,_Digits)+"\n"+ "Take Profit : "+DoubleToString(pos_tp,_Digits)+"\n"+ "Type : "+PositionTypeToString(pos_type)+"\n"+ "Volume : "+DoubleToString(pos_volume,2)+"\n"+ "Commission : "+DoubleToString(pos_commission,2)+"\n"+ "Swap : "+DoubleToString(pos_swap,2)+"\n"+ "Profit : "+DoubleToString(pos_profit,2)+"\n"+ "Time : "+TimeToString(pos_time)+"\n"+ "Identifier : "+IntegerToString(pos_id)+"", //--- "Message Box",MB_ICONASTERISK); //--- return; } // Если же позиции нет или была ошибка, сообщим об этом else { err=GetLastError(); // Получим код последней зафиксированной ошибки //--- if(err>0) // Если ошибка есть { // Выведем сообщение об этом MessageBox("Ошибка ("+IntegerToString(err)+") при выборе позиции ("+_Symbol+") !\n\n"+ "Возможно, что на этом символе нет позиции. Если это не так, попробуйте ещё раз.", "Error", MB_ICONWARNING); //--- return; // Выйдем из функции } } //---
В коде выше можно увидеть ещё две пользовательские функции GetPositionProperties() и PositionTypeToString(). Так как придется получать свойства не в одном месте программы, то имеет смысл создать отдельную функцию, чтобы уменьшить объем кода и, тем самым, улучшить его восприятие. Код этой функции ниже. Не забывайте также посмотреть в Справке дополнительную информацию об используемых внутри GetPositionProperties() функциях и идентификаторах языка MQL5.
//+------------------------------------------------------------------+ //| ПОЛУЧАЕТ СВОЙСТВА СИМВОЛА | //+------------------------------------------------------------------+ void GetPositionProperties() { pos_symbol =PositionGetString(POSITION_SYMBOL); pos_comment =PositionGetString(POSITION_COMMENT); pos_magic =PositionGetInteger(POSITION_MAGIC); pos_price =PositionGetDouble(POSITION_PRICE_OPEN); pos_cprice =PositionGetDouble(POSITION_PRICE_CURRENT); pos_sl =PositionGetDouble(POSITION_SL); pos_tp =PositionGetDouble(POSITION_TP); pos_type =(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); pos_volume =PositionGetDouble(POSITION_VOLUME); pos_commission =PositionGetDouble(POSITION_COMMISSION); pos_swap =PositionGetDouble(POSITION_SWAP); pos_profit =PositionGetDouble(POSITION_PROFIT); pos_time =(datetime)PositionGetInteger(POSITION_TIME); pos_id =PositionGetInteger(POSITION_IDENTIFIER); }
А пользовательская функция PositionTypeToString() конвертирует тип позиции, который возвращается в виде целого числа, в строковой читаемый вид. Смотрим код ниже:
//+------------------------------------------------------------------+ //| ПРЕОБРАЗУЕТ ТИП ПОЗИЦИИ В СТРОКУ | //+------------------------------------------------------------------+ string PositionTypeToString(int position_type) { string str=""; //--- if(position_type==0) { str="buy"; } if(position_type==1) { str="sell"; } //--- return(str); }
Для первого варианта, когда нужно показать свойства позиции только на текущем символе, код готов. Его даже можно уже прямо сейчас протестировать, если вы делали все сразу, читая статью. Откройте позицию в торговом терминале MetaTrader 5, используя штатные средства. Для этого нажмите клавишу F9: откроется окно Ордер, в котором есть все необходимые опции для настройки свойств позиции перед её открытием:
Рис. 1. Окно "Ордер" в клиентском терминале MetaTrader 5.
Настройте все свойства и нажмите Sell или Buy, а после запустите скрипт двойным щелчком или перетащив на график. Откроется окно скрипта. По умолчанию нужное значение (Текущий символ) параметра Режим уже установлено. Нажатие кнопки OK откроет диалоговое окно, в котором будут показаны все свойства позиции на текущем символе:
Рис. 2. Диалоговое окно со свойствами текущего символа.
Если же позиции на текущем символе нет, то выйдет диалоговое окно с предупреждением об этом:
Рис. 3. Диалоговое окно с предупреждением.
Всё работает так, как было задумано и реализовано в коде.
Теперь рассмотрим код, который используется в программе, если был выбран вариант для просмотра свойств всех открытых позиций. Код с подробными комментариями представлен ниже:
//--- int digits=0; // Количество десятичных знаков символа после запятой int mb_res=-1; // Переменная с результатом выбора в диалоговом окне int pos_total=PositionsTotal(); // Количество открытых позиций в терминале //--- // Последовательно в цикле просмотрим свойства всех позиций for(int i=0; i<pos_total; i++) { ResetLastError(); // Обнулим последнюю ошибку //--- pos_symbol=PositionGetSymbol(i); // Получим имя символа digits=(int)SymbolInfoInteger(pos_symbol,SYMBOL_DIGITS); // Получим количество знаков в цене //--- // Если позиция по этому символу есть, то... if(PositionSelect(pos_symbol)) { // ...получим её свойства GetPositionProperties(); //--- // Откроем диалоговое окно и выведем в нём все полученные свойства позиции mb_res=MessageBox("Total Positions/Current: "+IntegerToString(pos_total)+"/"+IntegerToString(i+1)+"\n"+ "---------------------------------\n"+ "Symbol: " +pos_symbol+"\n"+ "Comment: " +pos_comment+"\n"+ "Magic Number: " +IntegerToString(pos_magic)+"\n"+ "Price Open: " +DoubleToString(pos_price,digits)+"\n"+ "Current Price: " +DoubleToString(pos_cprice,digits)+"\n"+ "Stop Loss: " +DoubleToString(pos_sl,digits)+"\n"+ "Take Profit: " +DoubleToString(pos_tp,digits)+"\n"+ "Type: " +PositionTypeToString(pos_type)+"\n"+ "Volume: " +DoubleToString(pos_volume,2)+"\n"+ "Commission: " +DoubleToString(pos_commission,2)+"\n"+ "Swap: " +DoubleToString(pos_swap,2)+"\n"+ "Profit: " +DoubleToString(pos_profit,2)+"\n"+ "Time: " +TimeToString(pos_time)+"\n"+ "Identifier: " +IntegerToString(pos_id)+"", //--- "Message Box",MB_CANCELTRYCONTINUE|MB_ICONASTERISK); //--- if(mb_res==IDCANCEL) // Если нажали кнопку Отмена или Закрыть { Print("Программа ("+SCRIPT_NAME+") была прервана пользователем!"); return; } // Выйдем из функции //--- // Если нажали кнопку Повторить if(mb_res==IDTRYAGAIN) { i--; } // Отмотаем счётчик назад для повтора } else // Если же позиции нет или была ошибка, сообщим об этом { err=GetLastError(); // Получим код последней зафиксированной ошибки //--- if(err>0) // Если ошибка есть { // Выведем сообщение об этом MessageBox("Ошибка ("+IntegerToString(err)+") при выборе позиции ("+pos_symbol+") !\n\n"+ "Возможно, на этом символе нет позиции. Если это не так, попробуйте ещё раз.", "Error", MB_ICONWARNING); } } } //---
Осталось протестировать и этот вариант. Например, откроем позиции на двух символах (AUDUSD и EURUSD). Запустив скрипт, выбрав во внешних параметрах в выпадающем списке вариант Все символы и нажав кнопку OK, откроется вот такое диалоговое окно:
Рис. 4. Диалоговое окно со свойствами позиции для второго варианта.
Заключение
Как видно на рисунке выше, у диалогового окна три кнопки. Если нажать кнопку Повторить, счётчик цикла будет отмотан назад и свойства позиции символа которого уже отображены в текущий момент будут обновлены в диалоговом окне. Если же нажать кнопку Продолжить, программа перейдёт к следующему символу. Кнопка Отмена завершает работу программы.
Также можно заметить, что в первой строке над списком свойств позиции отображается общее количество открытых позиций (Total Positions) и текущий номер счётчика позиций (Current).
На этом всё. Ниже можно скачать файл с исходным кодом, который нужно скомпилировать в редакторе MetaEditor.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Здравствуйте! Ищу способ вывода или ввода в код истории имя(название) советника, который открыл позицию. В старом МТ 4 это как-то отмечалось автоматически, а здесь не посчитали видимо нужным. Я тестирую на демо разные советники, часто их меняю и в результате в памяти ничего не остается. КАК бы сделать так, чтобы они автоматически по вашему коду прописывались.
При открытии позиции можно указать в комментарии имя советника, если это Вам нужно. Если честно не совсем понял, что и зачем Вы хотите получить. Вы работаете с историей сделок и при её анализе хотите программно/визуально определять, какие сделки и каким экспертом осуществлялись? Если да, то или комментарий или магический номер можно использовать.
При работе с 30 советниками да еще с 30 разными парами за всем уследить невозможно - хотелось бы чтобы это происходило само собой