Как получить свойства позиции?

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

Сделаем так, чтобы во внешних параметрах скрипта была возможность выбрать в выпадающем списке, получить ли свойства для просмотра только одного (текущего) символа или же пройти поочерёдно по всем открытым позициям (если они есть) на всех символах. Просматривать информацию на этот раз будем прямо в диалоговом окне. Это тоже довольно удобный способ и возможно, кому-нибудь понравится больше.

Начало программы примерно такое же, как и в предыдущей статье (смотрите код ниже). Сначала идут свойства программы. Далее я выделил восьмую (8) строку. В ней расположена директива #define после которой, переменной NAME_SCRIPT с помощью функции MQL5InfoString() и указанной в ней константы MQL5_PROGRAM_NAME, присваивается имя программы.

Посмотрите также Справку языка и подробнее ознакомьтесь со всеми свойствами для функции MQL5InfoString(). Там они все представлены в таблице.

Далее с 10-ой по 16-ую строку идёт перечисление режимов. Если напротив каждого идентификатора написать комментарий то, именно то, что написано в комментарии будет отображаться в выпадающем списке во внешних параметрах. Всего два режима:

  • - CURRENT SYMBOL - вывести свойства позиции только на текущем символе.
  • - ALL SYMBOLS - вывести свойства позиций на всех символах.

Внешний параметр только один (ModeSymbols), который служит для выбора режима. Комментарий после строки внешнего параметра также будет отображаться и в окне внешних параметров. Это позволяет делать более осмысленные названия параметров, в тот же момент для кода будет более удобным более краткие варианты.

//---
#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 NAME_SCRIPT MQL5InfoString(MQL5_PROGRAM_NAME) // Имя скрипта
//---
// ПЕРЕЧИСЛЕНИЕ РЕЖИМОВ
enum ENUM_MODE_SYMBOLS
  {
   CSYMBOL  = 0, // CURRENT SYMBOL
   ASYMBOLS = 1  // ALL SYMBOLS
  };
//---
// ВХОДНЫЕ ПАРАМЕТРЫ
input ENUM_MODE_SYMBOLS ModeSymbols=CSYMBOL; // Mode
//---

Далее по коду следуют глобальные переменные.

//---
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ
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; // Tип позиции
//---

Глобальные переменные доступны в любом месте программы и для этого должны быть расположены вне функций (обычно в самом начале программы).

В главной функции программы будет вызываться только одна пользовательская функция PrintPropPosition(), в которой будут совершаться все необходимые операции:

//---
//+------------------------------------------------------------------+
//| ГЛАВНАЯ ФУНКЦИЯ                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
   PrintPropPosition();
  }
//---

Теперь пошагово рассмотрим построение пользовательской функции PrintPropPosition(). Сначала напишем каркас, от которого будем двигаться дальше. Он очень простой и в коде выглядит вот так:

//---
//+------------------------------------------------------------------+
//| ОТКРЫВАЕТ ДИАЛОГОВОЕ ОКНО С ДАННЫМИ СИМВОЛА                      |
//+------------------------------------------------------------------+
void PrintPropPosition()
  {
   int err=0; // Переменная для обработки ошибок
//---
// Если нужно получить свойства позиции только на текущем символе
   if(ModeSymbols==CSYMBOL)
     {

     }
//---
// Если нужно получить свойства позиций на всех символах
   if(ModeSymbols==ASYMBOLS)
     {

     }
  }
//---

Всего лишь две ветки и вначале функции также объявлена локальная переменная err для обработки ошибок. Теперь нужно для каждого варианта написать свой сценарий. Будем идти по порядку и займёмся первым, то есть, "Если нужно получить свойства позиции только на текущем символе".

Всё просто. Сначала нужно проверить есть ли позиция на текущем символе. Для этой проверки в MQL5 есть функция PositionSelect(). Ей в качестве единственного параметра передаётся имя символа. Чтобы передать имя текущего символа нужно воспользоваться или функцией Symbol() или предопределённой переменной _Symbol, которая уже содержит имя текущего символа. Функция PositionSelect() возвратит положительный результат, если позиция на этом символе есть или отрицательный результат, если позиции нет или была ошибка.

Код с подробными комментариями для первого варианта можно посмотреть ниже:

//---
// Если есть позиция, то...
if(PositionSelect(_Symbol))
  {
// ...получим её свойства
   GetPropPosition();
//---
// Откроем диалоговое окно и выведем в нём все полученные данные
   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 : "+PosTypeToString(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; // Выйдем из функции
     }
  }
//---

В коде выше выделены 59-ая и 69-ая строки с ещё двумя пользовательскими функциями GetPropPosition() и PosTypeToString(). Так как придётся получать свойства не в одном месте программы, то имеет смысл создать отдельную функцию, чтобы уменьшить объём кода и тем самым улучшить его восприятие. Код этой функции ниже. Не забывайте также посмотреть в Справке дополнительную информацию о используемых внутри функции GetPropPosition() функциях и идентификаторах языка MQL5.

//---
//+------------------------------------------------------------------+
//| ПОЛУЧАЕТ СВОЙСТВА СИМВОЛА                                        |
//+------------------------------------------------------------------+
void GetPropPosition()
  {
   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);
  }
//---

А пользовательская функция PosTypeToString() конвертирует тип позиции, который возвращается в виде целого числа, в строковой читаемый вид. Смотрим код ниже:

//---
//+------------------------------------------------------------------+
//| ПРЕОБРАЗУЕТ ТИП ПОЗИЦИИ В СТРОКУ                                 |
//+------------------------------------------------------------------+
string PosTypeToString(int lpos_type)
  {
   string str="";
//---
   if(lpos_type==0) { str="buy";  }
   if(lpos_type==1) { str="sell"; }
//---
   return(str);
  }
//---

Для первого варианта, когда нужно показать свойства позиции только на текущем символе, код готов. Его даже можно уже прямо сейчас протестировать, если Вы делали всё сразу читая статью. Откройте позицию в торговом терминале MetaTrader 5 используя штатные средства. Для этого нажмите клавишу F9, откроется окно Ордер, в котором есть все необходимые опции для настройки свойств позиции перед её открытием:

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

Диалоговое окно со свойствами позиции

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

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

Всё работает так, как было задумано и реализовано в коде.

Теперь рассмотрим код, который используется в программе, если был выбран вариант для просмотра свойств всех открытых позиций. Код с подробными комментариями представлен ниже:

//---
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))
     {
      // ...получим её свойства
      GetPropPosition();
      //---
      // Откроем диалоговое окно и выведем в нём все полученные свойства позиции
      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 : "+PosTypeToString(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 : "+IntegerToString(pos_time)+"\n"+
                        "Identifier : "+IntegerToString(pos_id)+"",
                        //---
                        "Message Box",MB_CANCELTRYCONTINUE|MB_ICONASTERISK);
      //---
      if(mb_res==IDCANCEL) // Если нажали кнопку Отмена или Закрыть
        { Print("Программа ("+NAME_SCRIPT+") была прервана пользователем!"); return; } // Выйдем из функции
      //---
       // Если нажали кнопку Повторить   
      if(mb_res==IDTRYAGAIN) { i--; } // Отмотаем счётчик назад для повтора
     }
   else // Если же позиции нет или была ошибка, сообщим об этом
     {
      err=GetLastError(); // Получим код последней зафиксированной ошибки
      //---
      if(err>0) // Если ошибка есть
        {
         // Выведем сообщение об этом
         MessageBox("Ошибка ("+IntegerToString(err)+") при выборе позиции ("+pos_symbol+") !\n\n"+
                    "Возможно, что на этом символе нет позиции. Если это не так, то попробуйте ещё раз.",
                    "Error",
                    MB_ICONWARNING);
        }
     }
  }
//---

Осталось протестировать и этот вариант. Например, откроем позиции на двух символах (AUDUSD и EURUSD). Запустив скрипт, выбрав во внешних параметрах в выпадающем списке вариант ALL SYMBOLS и нажав кнопку OK, выйдет вот такое диалоговое окно:

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

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

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

Вот и всё. В конце статьи можно скачать файл с исходным кодом, который нужно скомпилировать в редакторе MetaEditor. Если возникли вопросы, спрашивайте в комментариях ниже.

Успехов!




Скачать скрипт GetPropPosition.mq5


Комментариев нет :

Отправить комментарий