Скачать MetaTrader 5

Рецепты MQL5 - Как получить свойства позиции?

26 февраля 2013, 12:22
Anatoli Kazharski
5
4 005

Введение

В предыдущей статье Рецепты 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.

Рис. 1. Окно "Ордер" в клиентском терминале MetaTrader 5.

Настройте все свойства и нажмите Sell или Buy, а после запустите скрипт двойным щелчком или перетащив на график. Откроется окно скрипта. По умолчанию нужное значение (Текущий символ) параметра Режим уже установлено. Нажатие кнопки OK откроет диалоговое окно, в котором будут показаны все свойства позиции на текущем символе:

Рис. 2. Диалоговое окно со свойствами текущего символа.

Рис. 2. Диалоговое окно со свойствами текущего символа.

Если же позиции на текущем символе нет, то выйдет диалоговое окно с предупреждением об этом:

Рис. 3. Диалоговое окно с предупреждением.

Рис. 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. Диалоговое окно со свойствами позиции для второго варианта.

Рис. 4. Диалоговое окно со свойствами позиции для второго варианта.


Заключение

Как видно на рисунке выше, у диалогового окна три кнопки. Если нажать кнопку Повторить, счётчик цикла будет отмотан назад и свойства позиции символа которого уже отображены в текущий момент будут обновлены в диалоговом окне. Если же нажать кнопку Продолжить, программа перейдёт к следующему символу. Кнопка Отмена завершает работу программы.

Также можно заметить, что в первой строке над списком свойств позиции отображается общее количество открытых позиций (Total Positions) и текущий номер счётчика позиций (Current).

На этом всё. Ниже можно скачать файл с исходным кодом, который нужно скомпилировать в редакторе MetaEditor.

Прикрепленные файлы |
Сергей Криушин
Сергей Криушин | 27 фев 2013 в 13:14
Здравствуйте! Ищу способ вывода или ввода в код истории имя(название) советника, который открыл позицию. В старом МТ 4 это как-то отмечалось автоматически, а здесь не посчитали видимо нужным. Я тестирую на демо разные  советники, часто их меняю и в результате в памяти ничего не остается. КАК бы сделать так, чтобы они автоматически по вашему коду прописывались.

Anatoli Kazharski
Anatoli Kazharski | 27 фев 2013 в 15:23
chipo:
Здравствуйте! Ищу способ вывода или ввода в код истории имя(название) советника, который открыл позицию. В старом МТ 4 это как-то отмечалось автоматически, а здесь не посчитали видимо нужным. Я тестирую на демо разные  советники, часто их меняю и в результате в памяти ничего не остается. КАК бы сделать так, чтобы они автоматически по вашему коду прописывались.

При открытии позиции можно указать в комментарии имя советника, если это Вам нужно. Если честно не совсем понял, что и зачем Вы хотите получить. Вы работаете с историей сделок и при её анализе хотите программно/визуально определять, какие сделки и каким экспертом осуществлялись? Если да, то или комментарий или магический номер можно использовать.
Сергей Криушин
Сергей Криушин | 27 фев 2013 в 16:46
tol64:
При открытии позиции можно указать в комментарии имя советника, если это Вам нужно. Если честно не совсем понял, что и зачем Вы хотите получить. Вы работаете с историей сделок и при её анализе хотите программно/визуально определять, какие сделки и каким экспертом осуществлялись? Если да, то или комментарий или магический номер можно использовать.
При работе с 30 советниками да еще с 30 разными парами за всем уследить невозможно - хотелось бы чтобы это происходило само собой
Anatoli Kazharski
Anatoli Kazharski | 27 фев 2013 в 16:56
chipo:
При работе с 30 советниками да еще с 30 разными парами за всем уследить невозможно - хотелось бы чтобы это происходило само собой
Нет проблем. Всё можно автоматизировать и отслеживать программно опираясь на имя символа/мэджик/комментарий.
Aliaksei Dzikun
Aliaksei Dzikun | 5 июн 2014 в 19:01
сделал
Рецепты MQL5 -  Вывод информации на печать в разных режимах Рецепты MQL5 - Вывод информации на печать в разных режимах

Это первая статья из серии "Рецепты MQL5". Я начну с простых примеров, чтобы те, кто только начинает изучать программирование, могли плавно погрузиться в изучение этого языка. Я вспоминаю, как я начинал изучать разработку и программирование торговых систем, и, признаться, мне это было довольно сложно, так как это мой первый язык. Но всё оказалось не так сложно, и уже через несколько месяцев я создал довольно сложную программу.

Основы программирования на MQL5 - Время Основы программирования на MQL5 - Время

В статье рассматриваются стандартные функции MQL5 для работы со временем, приемы программирования и практически полезные функции для работы со временем, которые необходимы при создании экспертов и индикаторов. Значительное внимание уделено общей теории времяисчисления. В первую очередь статья должна быть интересна новичкам, приступившим к изучению программирования на MQL5.

Отладка программ на MQL5 Отладка программ на MQL5

Эта статья ориентирована в первую очередь на программистов, которые уже изучили язык, но еще недостаточно освоились в разработке программ. Статья раскрывает практические приемы отладки программ и является объединенным опытом, не только моим, но и многих программистов, на опыте которых я учился.

Рецепты MQL5 - Свойства позиции на пользовательской информационной панели Рецепты MQL5 - Свойства позиции на пользовательской информационной панели

На этот раз создадим простого эксперта, который во время ручной торговли будет показывать свойства позиции по текущему символу на пользовательской информационной панели, которая будет собрана из графических объектов. Данные будут обновляться на каждом тике, что уже намного удобнее, чем постоянно запускать вручную скрипт, который описывался в предыдущей статье "Рецепты MQL5 - Как получить свойства позиции?".