Работа с историей: сколько пунктов прибыли/убытка у позиции?

 

Условности: рассматривается только hedge-торговые счета.

Стоит задача по торговой истории в терминале определить, сколько пунктов прибыли/убытка у полностью закрытых позиции?

 

Пока вариант получения списка торговых операций на определённый период времени - скрипт "HistoryDealGetTicket.mq5".

Для примера были такие торговые операции:

  1. Первая позиция: вход в рынок, buy 0.03 EURUSD
  2. Вторая позиция: вход в рынок, sell 0.01 EURUSD
  3. Закрытие встречной позицией, объём 0.01 EURUSD - после этого вторая позиция была закрыта полностью, а от первой позиции осталось 0.02
  4. Выход из рынка, sell 0.02 EURUSD - первая позиция закрыта полностью

Скрипт "HistoryDealGetTicket.mq5" даёт такую распечатку:

HistoryDealGetTicket (EURUSD,M30)         0: deal #116488443 at 2017.02.07 12:55:56 Вход в рынок, buy 0.03 EURUSD (order #132873637, position ID 132873637)
HistoryDealGetTicket (EURUSD,M30)         1: deal #116488502 at 2017.02.07 12:56:22 Вход в рынок, sell 0.01 EURUSD (order #132873695, position ID 132873695)
HistoryDealGetTicket (EURUSD,M30)         2: deal #116488539 at 2017.02.07 12:56:38 Закрытие встречной позицией, buy 0.01 EURUSD (order #132873727, position ID 132873695)
HistoryDealGetTicket (EURUSD,M30)         3: deal #116488540 at 2017.02.07 12:56:38 Закрытие встречной позицией, sell 0.01 EURUSD (order #132873727, position ID 132873637)
HistoryDealGetTicket (EURUSD,M30)         4: deal #116488549 at 2017.02.07 12:56:42 Выход из рынка, sell 0.02 EURUSD (order #132873736, position ID 132873637)

...
Файлы:
 

Видится неплохой вариант в использовании HistorySelectByPosition - запрос истории сделок и ордеров, имеющих указанный идентификатор позиции.

Скрипт "HistorySelectByPosition.mql5" - это изменённый "HistoryDealGetTicket.mq5". Изменение: при помощи HistorySelectByPosition создаём список ордеров и список сделок с указанным идентификатором позиции. Дальше работа уже не отличается.

Пример работы скрипта "HistorySelectByPosition.mql5" - в качестве параметра был задан идентификатор первой позиции (из первого поста в этой ветке) - 132873637:

HistorySelectByPosition (EURUSD,M30)      0: deal #116488443 at 2017.02.07 12:55:56 Вход в рынок, buy 0.03 EURUSD (order #132873637, position ID 132873637)
HistorySelectByPosition (EURUSD,M30)      1: deal #116488540 at 2017.02.07 12:56:38 Закрытие встречной позицией, sell 0.01 EURUSD (order #132873727, position ID 132873637)
HistorySelectByPosition (EURUSD,M30)      2: deal #116488549 at 2017.02.07 12:56:42 Выход из рынка, sell 0.02 EURUSD (order #132873736, position ID 132873637)

и второй запуск - с идентификатором второй позиции - 132873695:

HistorySelectByPosition (EURUSD,M30)      0: deal #116488502 at 2017.02.07 12:56:22 Вход в рынок, sell 0.01 EURUSD (order #132873695, position ID 132873695)
HistorySelectByPosition (EURUSD,M30)      1: deal #116488539 at 2017.02.07 12:56:38 Закрытие встречной позицией, buy 0.01 EURUSD (order #132873727, position ID 132873695)

Функция  HistorySelectByPosition хорошо справляется с задачей отбора сделок по идентификатору позиции.

... 

Файлы:
 

Если без closeBy, то совсем просто. В общем же случае надо изучать реализацию closeBy в MT5 и сопоставлять ее с MT4, т.к. в четверке этот момент за многие годы был отточен до идеала.

У меня руки так и не дошли, т.к. возни много, а используется closeBy редко. Правда, разработчики чуть ли не вынуждают использовать closeBy, потому как у MT5-позиций нет TP в виде лимитника, как это практикуется в MT4.

 

Наверное стоит предусмотреть такую ситуацию, когда запрос истории сделок и ордеров с указанным идентификатором позиции может оказаться неполным. Например:

  1. ошибки в истории (история была свёрнута брокером)
  2. или позиция ещё открыта в терминале
Условие полноценной позиции:

  1. для указанного идентификатора есть, как минимум, сделка DEAL_ENTRY_IN (перечисление ENUM_DEAL_ENTRY) - то есть первоначальная сделка - вход в рынок
  2. должна быть ещё и сделка DEAL_ENTRY_OUT и/или DEAL_ENTRY_OUT_BY - то есть должен  обязательно быть выход
  3. суммарный объём ("+" DEAL_ENTRY_IN "-" DEAL_ENTRY_OUT "-" DEAL_ENTRY_OUT_BY) сделок должен быть равен нулю
 

Скрипт "HistorySelectByPosition.mql5" - Версия 1.001 - проверка целостности позиции.

Итог работы:

    position ID 132873637:
      0: deal #116488443 at 2017.02.07 12:55:56 Вход в рынок, buy 0.03 EURUSD (order #132873637, position ID 132873637)
      1: deal #116488540 at 2017.02.07 12:56:38 Закрытие встречной позицией, sell 0.01 EURUSD (order #132873727, position ID 132873637)
      2: deal #116488549 at 2017.02.07 12:56:42 Выход из рынка, sell 0.02 EURUSD (order #132873736, position ID 132873637)
    position ID 132873637 - целостность подтверждена
    position ID 132873695:
      0: deal #116488502 at 2017.02.07 12:56:22 Вход в рынок, sell 0.01 EURUSD (order #132873695, position ID 132873695)
      1: deal #116488539 at 2017.02.07 12:56:38 Закрытие встречной позицией, buy 0.01 EURUSD (order #132873727, position ID 132873695)
    position ID 132873695 - целостность подтверждена


 

Файлы:
 

Видно нужно теперь оба скрипта доработать и поместить в один класс. Например в "CHistoryPositionInfo".

Так как позиция состоит из нескольких сделок, имеет смысл в классе "CHistoryPositionInfo" объявить класс для хранения сделок - "CMyDeal". В классе "CMyDeal" будут такие поля (исходя из задачи в названии этой ветки): 

//+------------------------------------------------------------------+
//| Класс - сделка                                                   |
//+------------------------------------------------------------------+
class CMyDeal : public CObject
  {
private:
   long              m_deal_entry;        // направление сделки – вход в рынок, выход из рынка или разворот
   double            m_deal_price;        // цена сделки
   double            m_deal_volume;       // объём сделки
   long              m_deal_id;           // идентификатор позиции, в открытии, изменении или закрытии которой участвовала эта сделка
   double            m_deal_profit;       // финансовый результат сделки

public:
                     CMyDeal(void);
                    ~CMyDeal(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMyDeal::CMyDeal(void) : m_deal_entry(0),
                         m_deal_price(0.0),
                         m_deal_volume(0.0),
                         m_deal_id(0),
                         m_deal_profit(0.0)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMyDeal::~CMyDeal(void)
  {
  }
 
fxsaber:

Если без closeBy, то совсем просто. В общем же случае надо изучать реализацию closeBy в MT5 и сопоставлять ее с MT4, т.к. в четверке этот момент за многие годы был отточен до идеала.

У меня руки так и не дошли, т.к. возни много, а используется closeBy редко. Правда, разработчики чуть ли не вынуждают использовать closeBy, потому как у MT5-позиций нет TP в виде лимитника, как это практикуется в MT4.

Я очень широко использую для закрытия множества локированных ордеров. Все же получается немалая экономия на спреде. Надо будет в КБ скрипт выложить для такого закрытия..
 
Vladimir Karputov:

Видно нужно теперь оба скрипта доработать и поместить в один класс. Например в "CHistoryPositionInfo".

Так как позиция состоит из нескольких сделок, имеет смысл в классе "CHistoryPositionInfo" объявить класс для хранения сделок - "CMyDeal". В классе "CMyDeal" будут такие поля (исходя из задачи в названии этой ветки): 

//+------------------------------------------------------------------+
//| Класс - сделка                                                   |
//+------------------------------------------------------------------+
class CMyDeal : public CObject
  {
private:
   long              m_deal_entry;        // направление сделки – вход в рынок, выход из рынка или разворот
   double            m_deal_price;        // цена сделки
   double            m_deal_volume;       // объём сделки
   long              m_deal_id;           // идентификатор позиции, в открытии, изменении или закрытии которой участвовала эта сделка
   double            m_deal_profit;       // финансовый результат сделки

public:
                     CMyDeal(void);
                    ~CMyDeal(void);
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMyDeal::CMyDeal(void) : m_deal_entry(0),
                         m_deal_price(0.0),
                         m_deal_volume(0.0),
                         m_deal_id(0),
                         m_deal_profit(0.0)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMyDeal::~CMyDeal(void)
  {
  }
Пока это класс для хранения сделки. Можно хранить указатели на экземпляры CMyDeal в Hash Table, являющейся членом в CHistoryPositionInfo, вполне быстро и удобно. Вот удачная реализация, сам пользую https://www.mql5.com/ru/articles/1334
Рецепты MQL5 - Реализуем ассоциативный массив или словарь для быстрого доступа к данным
Рецепты MQL5 - Реализуем ассоциативный массив или словарь для быстрого доступа к данным
  • 2015.03.23
  • Vasiliy Sokolov
  • www.mql5.com
В данной статье описывается специальный алгоритм, позволяющий эффективно получать доступ к элементам по их уникальному ключу. В качестве ключа может быть использован любой базовый тип данных, например ключом могут быть строки или целочисленные переменные. Такой контейнер данных принято называть словарем или ассоциативным массивом. С его помощью решать многие задачи становиться гораздо проще и эффективней.
 
Alexey Volchanskiy:
Я очень широко использую для закрытия множества локированных ордеров. Все же получается немалая экономия на спреде. Надо будет в КБ скрипт выложить для такого закрытия..
Использую только полный автомат при торговле. Поэтому CloseBy ни к чему. А если руками прикрывать - да, тогда сначала лимитник (чтобы повыгоднее залиться) на общую нетто-позу, а затем общий closeBy. Но это реал. А потому не MT5.
 

Класс "HistoryPositionInfo.mqh" и проверочный скрипт "TestHistoryPositionInfo.mq5" должны лежать в одной папке.

На данный момент класс "HistoryPositionInfo.mqh" проверяет целостность и принтует все сделки относящиеся к искомой позиции - это больше для проверки работы сделано. Остаётся доделать класс для расчёта прибыли в пунктах...

Класс "HistoryPositionInfo.mqh":

//+------------------------------------------------------------------+
//|                                          HistoryPositionInfo.mqh |
//|                              Copyright © 2017, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2017, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.000"
#include <Arrays\ArrayObj.mqh>
#property description "Информация о позициях из истории сделок"
//+------------------------------------------------------------------+
//| Класс - сделка                                                   |
//+------------------------------------------------------------------+
class CMyDeal : public CObject
  {
private:
   long              m_deal_entry;        // направление сделки – вход в рынок, выход из рынка или разворот
   double            m_deal_price;        // цена сделки
   double            m_deal_volume;       // объём сделки
   double            m_deal_profit;       // финансовый результат сделки
public:
                     CMyDeal(void);
                    ~CMyDeal(void);
   //--- методы доступа к защищённым данным
   void              Entry_deal(const long value)    { m_deal_entry=value;               }
   long              Entry_deal(void) const          { return(m_deal_entry);             }

   void              Price_deal(const double value)  { m_deal_price=value;               }
   double            Price_deal(void) const          { return(m_deal_price);             }

   void              Volume_deal(const double value) { m_deal_volume=value;              }
   double            Volume_deal(void) const         { return(m_deal_volume);            }

   void              Profit_deal(const double value) { m_deal_profit=value;              }
   double            Profit_deal(void) const         { return(m_deal_profit);            }
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMyDeal::CMyDeal(void) : m_deal_entry(0),
                         m_deal_price(0.0),
                         m_deal_volume(0.0),
                         m_deal_profit(0.0)
  {
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CMyDeal::~CMyDeal(void)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CHistoryPositionInfo : public CArrayObj
  {
private:
   long              m_position_id;       // идентификатор позиции
   CArrayObj         m_arr_deals;         // объкт динамического массива указателей на объекты класса CMyDeal

public:
                     CHistoryPositionInfo();
                    ~CHistoryPositionInfo();
   //--- метод инициализации
   void              Init(const long value) { m_position_id=value;               }
   //--- метод получения прибыли в пунктах
   bool              GetProfitInPoints(const double &profit_in_points);
protected:
   //--- проверка целостности позиции
   bool              IsIntegrity(void);
   //--- сравнение двух чисел
   bool              CompareDoubles(double number1,double number2);
   //--- распечатка сделок, которые входят в позицию
   void              PrintDeals(void);
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryPositionInfo::CHistoryPositionInfo() : m_position_id(0)
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CHistoryPositionInfo::~CHistoryPositionInfo()
  {
  }
//+------------------------------------------------------------------+
//| Расчёт прибыли в пунктах                                         |
//+------------------------------------------------------------------+
bool CHistoryPositionInfo::GetProfitInPoints(const double &profit_in_points)
  {
   bool result=true;
   if(!IsIntegrity())
      return(false);
//--- тестирование: распечатаем все позиции
      PrintDeals();
//---
   return(result);
  }
//+------------------------------------------------------------------+
//| Проверка целостности позиции                                     |
//+------------------------------------------------------------------+
bool CHistoryPositionInfo::IsIntegrity(void)
  {
   bool result=true;
//--- request trade history
   if(!HistorySelectByPosition(m_position_id))
     {
      Print("Error HistorySelectByPosition");
      return(false);
     }
   uint     total=HistoryDealsTotal();
//--- for all deals
   int      count_IN    = 0;
   double   volume_IN   = 0.0;
   int      count_OUT   = 0;
   double   volume_OUT  = 0.0;
   for(uint i=0;i<total;i++)
     {
      ulong deal_ticket          = HistoryDealGetTicket(i);
      long deal_entry            = HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);
      double deal_price          = HistoryDealGetDouble(deal_ticket,DEAL_PRICE);
      double deal_volume         = HistoryDealGetDouble(deal_ticket,DEAL_VOLUME);
      double deal_profit         = HistoryDealGetDouble(deal_ticket,DEAL_PROFIT);
      //--- объявим указатель на объект класса CMyDeal и присвоим ему вновь созданный объект класса CMyDeal
      CMyDeal *my_deal=new CMyDeal;
      if(my_deal==NULL)
        {
         //--- ошибка создания
         Print(__FUNCTION__,". Object create error (\"CMyDeal\")");
         return(false);
        }
      my_deal.Entry_deal(deal_entry);
      my_deal.Price_deal(deal_price);
      my_deal.Volume_deal(deal_volume);
      my_deal.Profit_deal(deal_profit);

      Add(my_deal);
      //---
      if(deal_entry==DEAL_ENTRY_IN)
        {
         count_IN++;
         volume_IN+=deal_volume;
        }
      else if(deal_entry==DEAL_ENTRY_OUT || deal_entry==DEAL_ENTRY_OUT_BY)
        {
         count_OUT++;
         volume_OUT+=deal_volume;
        }
     }
//--- проверка целостности
   if(count_IN==1 && count_OUT>0) // первая проверка - обязательно должна быть одна IN и не менее одной OUT
     {
      if(!CompareDoubles(volume_IN-volume_OUT,0.0)) // вторая проверка - суммарный объём IN минус OUT должен быть равен нулю
        {
         Print("Вторая проверка не пройдена. IN=",DoubleToString(volume_IN,2),
               ", OUT=",DoubleToString(volume_OUT,2));
         return(false);
        }

     }
   else
     {
      Print("Первая проверка не пройдена. IN=",count_IN,", OUT=",count_OUT);
      return(false);
     }
//---
   return(result);
  }
//+------------------------------------------------------------------+
//| Сравнение двух чисел на равенство                                |
//+------------------------------------------------------------------+
bool CHistoryPositionInfo::CompareDoubles(double number1,double number2)
  {
   if(NormalizeDouble(number1-number2,8)==0) return(true);
   else return(false);
  }
//+------------------------------------------------------------------+
//| Распечатка сделок, которые входят в позицию                      |
//+------------------------------------------------------------------+
void CHistoryPositionInfo::PrintDeals(void)
  {
   for(int i=0;i<Total();i++)
     {
      //--- объявим указатель на объект класса CMyDeal и присвоим ему элемент из указанной позиции массива
      CMyDeal *my_deal=At(i);
      if(my_deal==NULL)
        {
         //--- ошибка чтения из массива
         Print(__FUNCTION__,". Get element error (\"CMyDeal\")");
         return;
        }
      Print(EnumToString((ENUM_DEAL_ENTRY)my_deal.Entry_deal()),
            ", price ",DoubleToString(my_deal.Price_deal(),Digits()),
            ", Deal ",Symbol(),
            ", volume ",DoubleToString(my_deal.Volume_deal(),2),
            ", profit ",DoubleToString(my_deal.Profit_deal(),2));
     }
  }
//+------------------------------------------------------------------+

и проверочный скрипт "TestHistoryPositionInfo.mq5":

//+------------------------------------------------------------------+
//|                                      TestHistoryPositionInfo.mq5 |
//|                              Copyright © 2017, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2017, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#property version   "1.00"
#property script_show_inputs
//---
input long position_id=0;                    // идентификатор позиции - POSITION_IDENTIFIER
#include "HistoryPositionInfo.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Print("Поиск сделок с POSITION_IDENTIFIER ",IntegerToString(position_id));
   CHistoryPositionInfo HistoryPositionInfo;
   HistoryPositionInfo.Init(position_id);
   double profit_in_points=0.0;
   if(HistoryPositionInfo.GetProfitInPoints(profit_in_points))
      Print("GetProfitInPoints=true");
   else
      Print("GetProfitInPoints=false");
  }
//+------------------------------------------------------------------+

Результаты, когда целостность позиции подтверждена:

2017.02.08 08:09:17.692 TestHistoryPositionInfo (EURUSD,M30)    Поиск сделок с POSITION_IDENTIFIER 132873695
2017.02.08 08:09:17.692 TestHistoryPositionInfo (EURUSD,M30)    DEAL_ENTRY_IN, price 1.06719, Deal EURUSD, volume 0.01, profit 0.00
2017.02.08 08:09:17.692 TestHistoryPositionInfo (EURUSD,M30)    DEAL_ENTRY_OUT_BY, price 1.06725, Deal EURUSD, volume 0.01, profit -0.06
2017.02.08 08:09:17.692 TestHistoryPositionInfo (EURUSD,M30)    GetProfitInPoints=true

и вот ситуация, когда позиция открыта и ещё не закрыта:

2017.02.08 08:10:19.052 TestHistoryPositionInfo (EURUSD,M30)    Поиск сделок с POSITION_IDENTIFIER 133021916
2017.02.08 08:10:19.052 TestHistoryPositionInfo (EURUSD,M30)    Первая проверка не пройдена. IN=1, OUT=0
2017.02.08 08:10:19.052 TestHistoryPositionInfo (EURUSD,M30)    GetProfitInPoints=false



 

 

Для определения прибыльности в пунктах нужна дополнительная информация:

тип (DEAL_TYPE_BUY или DEAL_TYPE_SELL) сделки IN - то есть банально нужно знать, это была позиция входа в Buy или в Sell.

Для этого добавим переменную в защищённую область класса и методы для работы с этой переменной

class CMyDeal : public CObject
  {
private:
   long              m_deal_entry;        // направление сделки – вход в рынок, выход из рынка или разворот
   long              m_deal_type;         // тип сделки
   double            m_deal_price;        // цена сделки
   double            m_deal_volume;       // объём сделки
   double            m_deal_profit;       // финансовый результат сделки
public:
                     CMyDeal(void);
                    ~CMyDeal(void);
   //--- методы доступа к защищённым данным
   void              Entry_deal(const long value)    { m_deal_entry=value;               }
   long              Entry_deal(void) const          { return(m_deal_entry);             }

   void              Type_deal(const long value)     { m_deal_type=value;                }
   long              Type_deal(void) const           { return(m_deal_type);              }


   void              Price_deal(const double value)  { m_deal_price=value;               }
   double            Price_deal(void) const          { return(m_deal_price);             }

Изменение в блок определения целостности (по совместительству этот же блок наполняет нашу позицию сделками)

      ulong  deal_ticket         = HistoryDealGetTicket(i);
      long   deal_entry          = HistoryDealGetInteger(deal_ticket,DEAL_ENTRY);
      long   deal_type           = HistoryDealGetInteger(deal_ticket,DEAL_TYPE);
      double deal_price          = HistoryDealGetDouble(deal_ticket,DEAL_PRICE);
      double deal_volume         = HistoryDealGetDouble(deal_ticket,DEAL_VOLUME);
      double deal_profit         = HistoryDealGetDouble(deal_ticket,DEAL_PROFIT);
      //--- объявим указатель на объект класса CMyDeal и присвоим ему вновь созданный объект класса CMyDeal
      CMyDeal *my_deal=new CMyDeal;
      if(my_deal==NULL)
        {
         //--- ошибка создания
         Print(__FUNCTION__,". Object create error (\"CMyDeal\")");
         return(false);
        }
      my_deal.Entry_deal(deal_entry);
      my_deal.Type_deal(deal_type);
      my_deal.Price_deal(deal_price);
      my_deal.Volume_deal(deal_volume);
      my_deal.Profit_deal(deal_profit);

      Add(my_deal);

Также внесём изменение в GetProfitInPoints():

//---
   double   price_IN = 0.0;
   double   price_OUT= 0.0;
   long     type_IN=-1;
   for(int i=0;i<Total();i++)
     {
      //--- объявим указатель на объект класса CMyDeal и присвоим ему элемент из указанной позиции массива
      CMyDeal *my_deal=At(i);
      if(my_deal==NULL)
        {
         //--- ошибка чтения из массива
         Print(__FUNCTION__,". Get element error (\"CMyDeal\")");
         return(false);
        }
      if(my_deal.Entry_deal()==DEAL_ENTRY_IN)
        {
         price_IN=my_deal.Price_deal();
         type_IN=my_deal.Type_deal();
        }
      price_OUT=my_deal.Price_deal();
     }
   if(type_IN==DEAL_TYPE_BUY)
      profit_in_points=price_OUT-price_IN;
   else if(type_IN==DEAL_TYPE_SELL)
      profit_in_points=price_IN-price_OUT;
   else
      return(false);

//---
   return(result);
  }

а также в блок вывода вспомогательной информации PrintDeals:

      Print(EnumToString((ENUM_DEAL_ENTRY)my_deal.Entry_deal()),
            ", ",EnumToString((ENUM_DEAL_TYPE)my_deal.Type_deal()),
            ", price ",DoubleToString(my_deal.Price_deal(),Digits()),
            ", Deal ",Symbol(),
            ", volume ",DoubleToString(my_deal.Volume_deal(),2),
            ", profit ",DoubleToString(my_deal.Profit_deal(),2));


В итоге получаем, для наших двух проверочных позиции такой вывод информации:


Поиск сделок с POSITION_IDENTIFIER 132873695
DEAL_ENTRY_IN, DEAL_TYPE_SELL, price 1.06719, Deal EURUSD, volume 0.01, profit 0.00
DEAL_ENTRY_OUT_BY, DEAL_TYPE_BUY, price 1.06725, Deal EURUSD, volume 0.01, profit -0.06
Профит в пунктах равен -0.00006000

Поиск сделок с POSITION_IDENTIFIER 132873637
DEAL_ENTRY_IN, DEAL_TYPE_BUY, price 1.06725, Deal EURUSD, volume 0.03, profit 0.00
DEAL_ENTRY_OUT_BY, DEAL_TYPE_SELL, price 1.06719, Deal EURUSD, volume 0.01, profit 0.00
DEAL_ENTRY_OUT, DEAL_TYPE_SELL, price 1.06720, Deal EURUSD, volume 0.02, profit -0.10
Профит в пунктах равен -0.00005000

...