//+------------------------------------------------------------------+
//|                                             EventsCollection.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Orders\Order.mqh"
#include "..\Objects\Events\EventBalanceOperation.mqh"
#include "..\Objects\Events\EventOrderPlaced.mqh"
#include "..\Objects\Events\EventOrderRemoved.mqh"
#include "..\Objects\Events\EventPositionOpen.mqh"
#include "..\Objects\Events\EventPositionClose.mqh"
#include "..\Objects\Events\EventModify.mqh"
//+------------------------------------------------------------------+
//| Коллекция торговых событий счёта                                 |
//+------------------------------------------------------------------+
class CEventsCollection : public CBaseObj
  {
private:
   CListObj          m_list_trade_events;             // Список событий
   bool              m_is_hedge;                      // Флаг хедж-счёта
   int               m_trade_event_code;              // Код торгового события
   ENUM_TRADE_EVENT  m_trade_event;                   // Торговое событие на счёте
   CEvent            m_event_instance;                // Объект-событие для поиска по свойству
   ulong             m_position_id;                   // Идентификатор позиции (MQL4)
   ENUM_ORDER_TYPE   m_type_first;                    // Тип открывающего ордера (MQL4)
   
//--- Создаёт торговое событие в зависимости от (1) статуса и (2) типа изменения ордера
   void              CreateNewEvent(COrder* order,CArrayObj* list_history,CArrayObj* list_market,CArrayObj* list_control);
   void              CreateNewEvent(COrderControl* order);
//--- Создаёт событие для (1) хеджевого счёта, (2) неттингового счёта
   void              NewDealEventHedge(COrder* deal,CArrayObj* list_history,CArrayObj* list_market);
   void              NewDealEventNetto(COrder* deal,CArrayObj* list_history,CArrayObj* list_market);
//--- Выбирает из списка и возвращает список (1) рыночных отложенных ордеров, (2) открытых позиций
   CArrayObj*        GetListMarketPendings(CArrayObj* list);
   CArrayObj*        GetListPositions(CArrayObj* list);
//--- Выбирает из списка и возвращает список исторических (1) закрытых позиций,
//--- (2) удалённых отложенных ордеров, (3) сделок, (4) всех закрывающих ордеров 
   CArrayObj*        GetListHistoryPositions(CArrayObj* list);
   CArrayObj*        GetListHistoryPendings(CArrayObj* list);
   CArrayObj*        GetListDeals(CArrayObj* list);
   CArrayObj*        GetListCloseByOrders(CArrayObj* list);
//--- Возвращает список (1) всех ордеров позиции по её идентификатору, (2) всех сделок позиции по её идентификатору
//--- (3) всех сделок на вход в рынок по идентификатору позиции, (4) всех сделок на выход из рынка по идентификатору позиции,
//--- (5) всех сделок на разворот позиции по идентификатору позиции
   CArrayObj*        GetListAllOrdersByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsInByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsOutByPosID(CArrayObj* list,const ulong position_id);
   CArrayObj*        GetListAllDealsInOutByPosID(CArrayObj* list,const ulong position_id);
//--- Возвращает суммарный объём всех сделок (1) IN, (2) OUT позиции по её идентификатору
   double            SummaryVolumeDealsInByPosID(CArrayObj* list,const ulong position_id);
   double            SummaryVolumeDealsOutByPosID(CArrayObj* list,const ulong position_id);
//--- Возвращает (1) первый, (2) последний и (3) закрывающий ордер из списка всех ордеров позиции,
//--- (4) ордер по тикету, (5) рыночную позицию по идентификатору,
//--- (6) последнюю и (7) предпоследнюю сделку InOut по идентификатору позиции
   COrder*           GetFirstOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetLastOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetCloseByOrderFromList(CArrayObj* list,const ulong position_id);
   COrder*           GetHistoryOrderByTicket(CArrayObj* list,const ulong order_ticket);
   COrder*           GetPositionByID(CArrayObj* list,const ulong position_id);
//--- Возвращает (1) контрольный ордер по тикету, (2) тип открывающего ордера по тикету позиции (MQL4)
   COrderControl*    GetOrderControlByTicket(CArrayObj* list,const ulong ticket);
   ENUM_ORDER_TYPE   GetTypeFirst(CArrayObj* list,const ulong ticket);
//--- Возвращает флаг наличия объекта-события в списке событий
   bool              IsPresentEventInList(CEvent* compared_event);
//--- Обработчик события изменения существующего ордера/позиции
   void              OnChangeEvent(CArrayObj* list_changes,const int index);

public:
//--- Выбирает события из коллекции со временем в диапазоне от begin_time до end_time
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0);
//--- Возвращает полный список-коллекцию событий "как есть"
   CArrayObj        *GetList(void)                                                                       { return &this.m_list_trade_events;                                     }
//--- Возвращает список по выбранному (1) целочисленному, (2) вещественному и (3) строковому свойству, удовлетворяющему сравниваемому критерию
   CArrayObj        *GetList(ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
//--- Обновляет список событий
   void              Refresh(CArrayObj* list_history,
                             CArrayObj* list_market,
                             CArrayObj* list_changes,
                             CArrayObj* list_control,
                             const bool is_history_event,
                             const bool is_market_event,
                             const int  new_history_orders,
                             const int  new_market_pendings,
                             const int  new_market_positions,
                             const int  new_deals,
                             const double changed_volume);
//--- Возвращает (1) последнее торговое событие на счёте, (2) объект базового события по индексу, (3) количество новых событий
   ENUM_TRADE_EVENT  GetLastTradeEvent(void)                const { return this.m_trade_event;                 }
   CEventBaseObj    *GetTradeEventByIndex(const int index)        { return this.GetEvent(index,false);         }
   int               GetTradeEventsTotal(void)              const { return this.m_list_events.Total();         }
//--- Сбрасывает последнее торговое событие
   void              ResetLastTradeEvent(void)                    { this.m_trade_event=TRADE_EVENT_NO_EVENT;   }
//--- Конструктор
                     CEventsCollection(void);
  };
//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CEventsCollection::CEventsCollection(void) : m_trade_event(TRADE_EVENT_NO_EVENT),m_trade_event_code(TRADE_EVENT_FLAG_NO_EVENT)
  {
   this.m_list_trade_events.Clear();
   this.m_list_trade_events.Sort(SORT_BY_EVENT_TIME_EVENT);
   this.m_list_trade_events.Type(COLLECTION_EVENTS_ID);
   this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif;
   this.m_chart_id=::ChartID();
   this.m_is_event=false;
   ::ZeroMemory(this.m_tick);
  }
//+------------------------------------------------------------------+
//| Обновляет список событий                                         |
//+------------------------------------------------------------------+
void CEventsCollection::Refresh(CArrayObj* list_history,
                                CArrayObj* list_market,
                                CArrayObj* list_changes,
                                CArrayObj* list_control,
                                const bool is_history_event,
                                const bool is_market_event,
                                const int  new_history_orders,
                                const int  new_market_pendings,
                                const int  new_market_positions,
                                const int  new_deals,
                                const double changed_volume)
  {
//--- Если списки пустые - выход
   if(list_history==NULL || list_market==NULL)
      return;
//---
   this.m_is_event=false;
   this.m_list_events.Clear();
   this.m_list_events.Sort();
//--- Если событие в рыночном окружении
   if(is_market_event)
     {
      //--- если было изменение свойств ордера
      int total_changes=list_changes.Total();
      if(total_changes>0)
        {
         for(int i=total_changes-1;i>=0;i--)
           {
            this.OnChangeEvent(list_changes,i);
           }
        }
      //--- если увеличилось количество установленных отложенных ордеров (MQL5, MQL4)
      if(new_market_pendings>0)
        {
         //--- Получаем список только установленных отложенных ордеров
         CArrayObj* list=this.GetListMarketPendings(list_market);
         if(list!=NULL)
           {
            //--- Сортируем новый список по времени установки ордера
            list.Sort(SORT_BY_ORDER_TIME_OPEN);
            //--- Берём в цикле с конца списка количество ордеров, равное количеству новых установленных ордеров (последние N событий)
            int total=list.Total(), n=new_market_pendings;
            for(int i=total-1; i>=0 && n>0; i--,n--)
              {
               //--- Получаем ордер из списка, и если это отложенный ордер - устанавливаем торговое событие
               COrder* order=list.At(i);
               if(order!=NULL && order.Status()==ORDER_STATUS_MARKET_PENDING)
                  this.CreateNewEvent(order,list_history,list_market,list_control);
              }
           }
        }
      #ifdef __MQL4__
         //--- Если увеличилось количество позиций (MQL4)
         if(new_market_positions>0)
           {
            //--- Получаем список открытых позиций
            CArrayObj* list=this.GetListPositions(list_market);
            if(list!=NULL)
              {
               //--- Сортируем новый список по времени открытия позиции
               list.Sort(SORT_BY_ORDER_TIME_OPEN);
               //--- Берём в цикле с конца списка количество позиций, равное количеству новых открытых позиций (последние N событий)
               int total=list.Total(), n=new_market_positions;
               for(int i=total-1; i>=0 && n>0; i--,n--)
                 {
                  //--- Получаем позицию из списка, и если это позиция - ищем данные открывающего ордера и устанавливаем торговое событие
                  COrder* position=list.At(i);
                  if(position!=NULL && position.Status()==ORDER_STATUS_MARKET_POSITION)
                    {
                     //--- Находим ордер и устанавливаем (1) тип ордера, на основании которого была открыта позиция и (2) идентификатор позиции 
                     this.m_type_first=this.GetTypeFirst(list_control,position.Ticket());
                     this.m_position_id=position.Ticket();
                     this.CreateNewEvent(position,list_history,list_market,list_control);
                    }
                 }
              }
           }
         //--- Если уменьшилось количество позиций или позиция частично закрыта (MQL4)
         else if(new_market_positions<0 || (new_market_positions==0 && changed_volume<0 && new_history_orders>0 && new_market_pendings>WRONG_VALUE))
           {
            //--- Получаем список закрытых позиций
            CArrayObj* list=this.GetListHistoryPositions(list_history);
            if(list!=NULL)
              {
               //--- Сортируем новый список по времени закрытия позиции
               list.Sort(SORT_BY_ORDER_TIME_CLOSE);
               //--- Берём в цикле с конца списка количество позиций, равное количеству новых закрытых позиций (последние N событий)
               int total=list.Total(), n=new_history_orders;
               for(int i=total-1; i>=0 && n>0; i--,n--)
                 {
                  //--- Получаем позицию из списка, и если это позиция - ищем данные открывающего ордера и устанавливаем торговое событие
                  COrder* position=list.At(i);
                  if(position!=NULL && position.Status()==ORDER_STATUS_HISTORY_ORDER)
                    {
                     //--- Если есть контрольный ордер закрытой позиции
                     COrderControl* ctrl=this.GetOrderControlByTicket(list_control,position.Ticket());
                     if(ctrl!=NULL)
                       {
                        //--- Устанавливаем (1) тип ордера, на основании которого была открыта позиция, (2) идентификатор позиции и создаём событие закрытия позиции
                        this.m_type_first=(ENUM_ORDER_TYPE)ctrl.TypeOrder();
                        this.m_position_id=position.Ticket();
                        this.CreateNewEvent(position,list_history,list_market,list_control);
                       }
                    }
                 }
              }
           }
      #endif 
     }
//--- Если событие в истории счёта
   if(is_history_event)
     {
      //--- Если увеличилось количество исторических ордеров (MQL5, MQL4)
      if(new_history_orders>0 && new_market_pendings<0)
        {
         //--- Получаем список только удалённых отложенных ордеров
         CArrayObj* list=this.GetListHistoryPendings(list_history);
         if(list!=NULL)
           {
            //--- Сортируем новый список по времени удаления ордера
            list.Sort(SORT_BY_ORDER_TIME_CLOSE);
            //--- Берём в цикле с конца списка количество ордеров, равное количеству новых удалённых отложенных ордеров (последние N событий)
            int total=list.Total(), n=new_history_orders;
            for(int i=total-1; i>=0 && n>0; i--,n--)
              {
               //--- Получаем ордер из списка, и если это удалённый отложенный ордер и у него нет идентификатора позиции, 
               //--- то это удаление ордера - устанавливаем торговое событие
               COrder* order=list.At(i);
               if(order!=NULL && order.Status()==ORDER_STATUS_HISTORY_PENDING && order.PositionID()==0)
                  this.CreateNewEvent(order,list_history,list_market,list_control);
              }
           }
        }
      //--- Если увеличилось количество сделок (MQL5)
      #ifdef __MQL5__
         if(new_deals>0)
           {
            //--- Получаем список только сделок
            CArrayObj* list=this.GetListDeals(list_history);
            if(list!=NULL)
              {
               //--- Сортируем новый список по времени совершения сделки
               list.Sort(SORT_BY_ORDER_TIME_OPEN);
               //--- Берём в цикле с конца списка количество сделок, равное количеству новых сделок (последние N событий)
               int total=list.Total(), n=new_deals;
               for(int i=total-1; i>=0 && n>0; i--,n--)
                 {
                  //--- Получаем сделку из списка и устанавливаем торговое событие
                  COrder* order=list.At(i);
                  if(order!=NULL)
                     this.CreateNewEvent(order,list_history,list_market,list_control);
                 }
              }
           }
      #endif 
     }
  }
//+------------------------------------------------------------------+
//| Обработчик события изменения существующего ордера/позиции        |
//+------------------------------------------------------------------+
void CEventsCollection::OnChangeEvent(CArrayObj* list_changes,const int index)
  {
   COrderControl* order_changed=list_changes.Detach(index);
   if(order_changed!=NULL)
     {
      this.CreateNewEvent(order_changed);
      delete order_changed;
     }
  }
//+------------------------------------------------------------------+
//| Создаёт торговое событие в зависимости от типа изменения ордера  |
//+------------------------------------------------------------------+
void CEventsCollection::CreateNewEvent(COrderControl* order)
  {
   ENUM_EVENT_REASON reason=WRONG_VALUE;
   if(!::SymbolInfoTick(order.Symbol(),this.m_tick))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_CURR_PRICES),order.Symbol());
      return;
     }
   CEvent* event=NULL;
//--- Сработал отложенный StopLimit-ордер
   if(order.GetChangeType()==CHANGE_TYPE_ORDER_TYPE)
     {
      reason=EVENT_REASON_STOPLIMIT_TRIGGERED;
      this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_PLASED;
      event=new CEventOrderPlased(this.m_trade_event_code,order.Ticket());
     }
//--- Модификация
   else
     {
      //--- Модифицирована цена отложенного ордера
      if(order.GetChangeType()==CHANGE_TYPE_ORDER_PRICE)
         this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_MODIFY+TRADE_EVENT_FLAG_PRICE;
      //--- Модифицирована цена отложенного ордера и его StopLoss
      else if(order.GetChangeType()==CHANGE_TYPE_ORDER_PRICE_STOP_LOSS)
         this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_MODIFY+TRADE_EVENT_FLAG_PRICE+TRADE_EVENT_FLAG_SL;
      //--- Модифицирована цена отложенного ордера и его TakeProfit
      else if(order.GetChangeType()==CHANGE_TYPE_ORDER_PRICE_TAKE_PROFIT)
         this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_MODIFY+TRADE_EVENT_FLAG_PRICE+TRADE_EVENT_FLAG_TP;
      //--- Модифицирована цена отложенного ордера, его StopLoss и TakeProfit
      else if(order.GetChangeType()==CHANGE_TYPE_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT)
         this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_MODIFY+TRADE_EVENT_FLAG_PRICE+TRADE_EVENT_FLAG_SL+TRADE_EVENT_FLAG_TP;
      //--- Модифицирован StopLoss отложенного ордера
      else if(order.GetChangeType()==CHANGE_TYPE_ORDER_STOP_LOSS)
         this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_MODIFY+TRADE_EVENT_FLAG_SL;
      //--- Модифицирован TakeProfit отложенного ордера
      else if(order.GetChangeType()==CHANGE_TYPE_ORDER_TAKE_PROFIT)
         this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_MODIFY+TRADE_EVENT_FLAG_TP;
      //--- Модифицирован StopLoss и TakeProfit отложенного ордера
      else if(order.GetChangeType()==CHANGE_TYPE_ORDER_STOP_LOSS_TAKE_PROFIT)
         this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_MODIFY+TRADE_EVENT_FLAG_SL+TRADE_EVENT_FLAG_TP;

      //--- Модифицирован StopLoss позиции
      else if(order.GetChangeType()==CHANGE_TYPE_POSITION_STOP_LOSS)
         this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_MODIFY+TRADE_EVENT_FLAG_SL;
      //--- Модифицирован TakeProfit позиции
      else if(order.GetChangeType()==CHANGE_TYPE_POSITION_TAKE_PROFIT)
         this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_MODIFY+TRADE_EVENT_FLAG_TP;
      //--- Модифицирован StopLoss и TakeProfit позиции
      else if(order.GetChangeType()==CHANGE_TYPE_POSITION_STOP_LOSS_TAKE_PROFIT)
         this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_MODIFY+TRADE_EVENT_FLAG_SL+TRADE_EVENT_FLAG_TP;
      
      //--- Создаём событие модификации
      reason=EVENT_REASON_MODIFY;
      event=new CEventModify(this.m_trade_event_code,order.Ticket());
     }
//--- Создание события
   if(event!=NULL)
     {
      event.SetProperty(EVENT_PROP_TIME_EVENT,order.Time());                        // Время события
      event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                            // Причина события (из перечисления ENUM_EVENT_REASON)
      event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,PositionTypeByOrderType((ENUM_ORDER_TYPE)order.TypeOrderPrev())); // Тип ордера, срабатывание которого привело к событию
      event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,order.Ticket());               // Тикет ордера , срабатывание которого привело к событию
      event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order.TypeOrder());             // Тип ордера события
      event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order.Ticket());              // Тикет ордера события
      event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order.TypeOrder());          // Тип первого ордера позиции
      event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order.Ticket());           // Тикет первого ордера позиции
      event.SetProperty(EVENT_PROP_POSITION_ID,order.PositionID());                 // Идентификатор позиции
      event.SetProperty(EVENT_PROP_POSITION_BY_ID,0);                               // Идентификатор встречной позиции
      event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                  // Магический номер встречной позиции
         
      event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order.TypeOrderPrev());      // Тип ордера позиции до смены направления
      event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order.Ticket());           // Тикет ордера позиции до смены направления
      event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order.TypeOrder());         // Тип ордера текущей позиции
      event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order.Ticket());          // Тикет ордера текущей позиции
      
      event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order.PricePrev());            // Цена установки ордера до модификации
      event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order.StopLossPrev());           // Цена StopLoss до модификации
      event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order.TakeProfitPrev());         // Цена TakeProfit до модификации
      event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,this.m_tick.ask);                // Цена Ask в момент события
      event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,this.m_tick.bid);                // Цена Bid в момент события
         
      event.SetProperty(EVENT_PROP_MAGIC_ORDER,order.Magic());                      // Магический номер ордера
      event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order.TimePrev());           // Время первого ордера позиции
      event.SetProperty(EVENT_PROP_PRICE_EVENT,order.PricePrev());                  // Цена, на которой произошло событие
      event.SetProperty(EVENT_PROP_PRICE_OPEN,order.Price());                       // Цена установки ордера
      event.SetProperty(EVENT_PROP_PRICE_CLOSE,order.Price());                      // Цена закрытия ордера
      event.SetProperty(EVENT_PROP_PRICE_SL,order.StopLoss());                      // Цена StopLoss ордера
      event.SetProperty(EVENT_PROP_PRICE_TP,order.TakeProfit());                    // Цена TakeProfit ордера
      event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order.Volume());            // Запрашиваемый объём ордера
      event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,0);                        // Исполненный объём ордера
      event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order.Volume());            // Оставшийся (неисполненный) объём ордера
      event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,0);                     // Исполненный объём позиции
      event.SetProperty(EVENT_PROP_PROFIT,0);                                       // Профит
      event.SetProperty(EVENT_PROP_SYMBOL,order.Symbol());                          // Символ ордера
      event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order.Symbol());                    // Символ встречной позиции
      //--- Установка идентификатора графика управляющей программы, расшифровка кода события и установка типа события
      event.SetChartID(this.m_chart_id);
      event.SetTypeEvent();
      //--- Если объекта-события нет в списке - добавляем
      if(!this.IsPresentEventInList(event))
        {
         this.m_list_trade_events.InsertSort(event);
         //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
         this.m_trade_event=event.TradeEvent();
         this.m_is_event=true;
         event.SendEvent();
         CBaseObj::EventAdd(this.m_trade_event,order.Ticket(),order.Price(),order.Symbol());
        }
      //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
      else
        {
         ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
         delete event;
        }
     }
  }
//+------------------------------------------------------------------+
//| Создаёт торговое событие в зависимости от статуса ордера         |
//+------------------------------------------------------------------+
void CEventsCollection::CreateNewEvent(COrder* order,CArrayObj* list_history,CArrayObj* list_market,CArrayObj* list_control)
  {
   if(!::SymbolInfoTick(order.Symbol(),this.m_tick))
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_CURR_PRICES),order.Symbol());
      return;
     }
   this.m_trade_event_code=TRADE_EVENT_FLAG_NO_EVENT;
   ENUM_ORDER_STATUS status=order.Status();
//--- Установлен отложенный ордер
   if(status==ORDER_STATUS_MARKET_PENDING)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_PLASED;
      CEvent* event=new CEventOrderPlased(this.m_trade_event_code,order.Ticket());
      if(event!=NULL)
        {
         event.SetProperty(EVENT_PROP_TIME_EVENT,order.TimeOpen());                                // Время события
         event.SetProperty(EVENT_PROP_REASON_EVENT,EVENT_REASON_DONE);                             // Причина события (из перечисления ENUM_EVENT_REASON)
         event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,order.TypeByDirection());                    // Тип сделки события
         event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,order.Ticket());                           // Тикет ордера события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order.TypeOrder());                         // Тип ордера события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order.TypeOrder());                      // Тип ордера события
         event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order.Ticket());                          // Тикет ордера события
         event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order.Ticket());                       // Тикет ордера
         event.SetProperty(EVENT_PROP_POSITION_ID,order.PositionID());                             // Идентификатор позиции
         event.SetProperty(EVENT_PROP_POSITION_BY_ID,order.PositionByID());                        // Идентификатор встречной позиции
         event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                              // Магический номер встречной позиции
            
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order.TypeOrder());                      // Тип ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order.Ticket());                       // Тикет ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order.TypeOrder());                     // Тип ордера текущей позиции
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order.Ticket());                      // Тикет ордера текущей позиции
      
         event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order.PriceOpen());                        // Цена установки ордера до модификации
         event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order.StopLoss());                           // Цена StopLoss до модификации
         event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order.TakeProfit());                         // Цена TakeProfit до модификации
         event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,this.m_tick.ask);                            // Цена Ask в момент события
         event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,this.m_tick.bid);                            // Цена Bid в момент события
         
         event.SetProperty(EVENT_PROP_MAGIC_ORDER,order.Magic());                                  // Магический номер ордера
         event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order.TimeOpen());                       // Время ордера
         event.SetProperty(EVENT_PROP_PRICE_EVENT,this.m_tick.bid);                                // Цена Bid, на которой произошло событие
         event.SetProperty(EVENT_PROP_PRICE_OPEN,order.PriceOpen());                               // Цена установки ордера
         event.SetProperty(EVENT_PROP_PRICE_CLOSE,order.PriceClose());                             // Цена закрытия ордера
         event.SetProperty(EVENT_PROP_PRICE_SL,order.StopLoss());                                  // Цена StopLoss ордера
         event.SetProperty(EVENT_PROP_PRICE_TP,order.TakeProfit());                                // Цена TakeProfit ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order.Volume());                        // Запрашиваемый объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,order.Volume()-order.VolumeCurrent()); // Исполненный объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order.VolumeCurrent());                 // Оставшийся (неисполненный) объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,0);                                 // Исполненный объём позиции
         event.SetProperty(EVENT_PROP_PROFIT,order.Profit());                                      // Профит
         event.SetProperty(EVENT_PROP_SYMBOL,order.Symbol());                                      // Символ ордера
         event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order.Symbol());                                // Символ встречной позиции
         //--- Установка идентификатора графика управляющей программы, расшифровка кода события и установка типа события
         event.SetChartID(this.m_chart_id);
         event.SetTypeEvent();
         //--- Если объекта-события нет в списке - добавляем
         if(!this.IsPresentEventInList(event))
           {
            this.m_list_trade_events.InsertSort(event);
            //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
            this.m_trade_event=event.TradeEvent();
            this.m_is_event=true;
            event.SendEvent();
            CBaseObj::EventAdd(this.m_trade_event,order.Ticket(),order.PriceOpen(),order.Symbol());
           }
         //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
         else
           {
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
            delete event;
           }
        }
     }
//--- Удалён отложенный ордер
   if(status==ORDER_STATUS_HISTORY_PENDING)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_ORDER_REMOVED;
      CEvent* event=new CEventOrderRemoved(this.m_trade_event_code,order.Ticket());
      if(event!=NULL)
        {
         ENUM_EVENT_REASON reason=
           (
            order.State()==ORDER_STATE_CANCELED ? EVENT_REASON_CANCEL :
            order.State()==ORDER_STATE_EXPIRED  ? EVENT_REASON_EXPIRED : EVENT_REASON_DONE
           );
         event.SetProperty(EVENT_PROP_TIME_EVENT,order.TimeClose());                               // Время события
         event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                                        // Причина события (из перечисления ENUM_EVENT_REASON)
         event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,order.TypeByDirection());                    // Тип ордера события
         event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,order.Ticket());                           // Тикет ордера события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order.TypeOrder());                         // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order.TypeOrder());                      // Тип ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order.Ticket());                          // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order.Ticket());                       // Тикет ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_POSITION_ID,order.PositionID());                             // Идентификатор позиции
         event.SetProperty(EVENT_PROP_POSITION_BY_ID,order.PositionByID());                        // Идентификатор встречной позиции
         event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                              // Магический номер встречной позиции
            
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order.TypeOrder());                      // Тип ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order.Ticket());                       // Тикет ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order.TypeOrder());                     // Тип ордера текущей позиции
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order.Ticket());                      // Тикет ордера текущей позиции
      
         event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order.PriceOpen());                        // Цена установки ордера до модификации
         event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order.StopLoss());                           // Цена StopLoss до модификации
         event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order.TakeProfit());                         // Цена TakeProfit до модификации
         event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,this.m_tick.ask);                            // Цена Ask в момент события
         event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,this.m_tick.bid);                            // Цена Bid в момент события
         
         event.SetProperty(EVENT_PROP_MAGIC_ORDER,order.Magic());                                  // Магический номер ордера
         event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order.TimeOpen());                       // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_PRICE_EVENT,this.m_tick.bid);                                // Цена Bid, на которой произошло событие
         event.SetProperty(EVENT_PROP_PRICE_OPEN,order.PriceOpen());                               // Цена установки ордера
         event.SetProperty(EVENT_PROP_PRICE_CLOSE,order.PriceClose());                             // Цена закрытия ордера
         event.SetProperty(EVENT_PROP_PRICE_SL,order.StopLoss());                                  // Цена StopLoss ордера
         event.SetProperty(EVENT_PROP_PRICE_TP,order.TakeProfit());                                // Цена TakeProfit ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order.Volume());                        // Запрашиваемый объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,order.Volume()-order.VolumeCurrent()); // Исполненный объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order.VolumeCurrent());                 // Оставшийся (неисполненный) объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,0);                                 // Исполненный объём позиции
         event.SetProperty(EVENT_PROP_PROFIT,order.Profit());                                      // Профит
         event.SetProperty(EVENT_PROP_SYMBOL,order.Symbol());                                      // Символ ордера
         event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order.Symbol());                                // Символ встречной позиции
         //--- Установка идентификатора графика управляющей программы и расшифровка кода события и установка типа события
         event.SetChartID(this.m_chart_id);
         event.SetTypeEvent();
         //--- Если объекта-события нет в списке - добавляем
         if(!this.IsPresentEventInList(event))
           {
            this.m_list_trade_events.InsertSort(event);
            //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
            this.m_trade_event=event.TradeEvent();
            this.m_is_event=true;
            event.SendEvent();
            CBaseObj::EventAdd(this.m_trade_event,order.Ticket(),order.PriceOpen(),order.Symbol());
           }
         //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
         else
           {
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
            delete event;
           }
        }
     }
//--- Открыта позиция (__MQL4__)
#ifdef __MQL4__
   if(status==ORDER_STATUS_MARKET_POSITION)
     {
      //--- Установим код торгового события "позиция открыта"
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_OPENED;
      //--- Установим причину "запрос исполнен полностью""
      ENUM_EVENT_REASON reason=EVENT_REASON_DONE;
      //--- Если открывающий ордер - отложенный
      if(this.m_type_first>ORDER_TYPE_SELL && this.m_type_first<ORDER_TYPE_BALANCE)
        {
         //--- установим причину "срабатывание отложенного ордера"
         reason=EVENT_REASON_ACTIVATED_PENDING;
         //--- добавим к коду события флаг активации отложенного ордера
         this.m_trade_event_code+=TRADE_EVENT_FLAG_ORDER_ACTIVATED;
        }
      CEvent* event=new CEventPositionOpen(this.m_trade_event_code,order.Ticket());
      if(event!=NULL)
        {
         event.SetProperty(EVENT_PROP_TIME_EVENT,order.TimeOpen());                                // Время события
         event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                                        // Причина события (из перечисления ENUM_EVENT_REASON)
         event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,this.m_type_first);                          // Тип сделки события
         event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,order.Ticket());                           // Тикет сделки события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,this.m_type_first);                         // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,this.m_type_first);                      // Тип ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order.Ticket());                          // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order.Ticket());                       // Тикет ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_POSITION_ID,this.m_position_id);                             // Идентификатор позиции
         event.SetProperty(EVENT_PROP_POSITION_BY_ID,order.PositionByID());                        // Идентификатор встречной позиции
         event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                              // Магический номер встречной позиции
            
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order.TypeOrder());                      // Тип ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order.Ticket());                       // Тикет ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order.TypeOrder());                     // Тип ордера текущей позиции
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order.Ticket());                      // Тикет ордера текущей позиции
      
         event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order.PriceOpen());                        // Цена установки ордера до модификации
         event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order.StopLoss());                           // Цена StopLoss до модификации
         event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order.TakeProfit());                         // Цена TakeProfit до модификации
         event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,this.m_tick.ask);                            // Цена Ask в момент события
         event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,this.m_tick.bid);                            // Цена Bid в момент события
         
         event.SetProperty(EVENT_PROP_MAGIC_ORDER,order.Magic());                                  // Магический номер ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order.TimeOpen());                       // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_PRICE_EVENT,order.PriceOpen());                              // Цена, на которой произошло событие
         event.SetProperty(EVENT_PROP_PRICE_OPEN,order.PriceOpen());                               // Цена открытия ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_PRICE_CLOSE,order.PriceClose());                             // Цена закрытия ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_PRICE_SL,order.StopLoss());                                  // Цена StopLoss позиции
         event.SetProperty(EVENT_PROP_PRICE_TP,order.TakeProfit());                                // Цена TakeProfit позиции
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order.Volume());                        // Запрашиваемый объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,order.Volume()-order.VolumeCurrent()); // Исполненный объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order.VolumeCurrent());                 // Оставшийся (неисполненный) объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,order.Volume());                    // Исполненный объём позиции
         event.SetProperty(EVENT_PROP_PROFIT,order.Profit());                                      // Профит
         event.SetProperty(EVENT_PROP_SYMBOL,order.Symbol());                                      // Символ ордера
         event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order.Symbol());                                // Символ встречной позиции
         //--- Установка идентификатора графика управляющей программы и расшифровка кода события и установка типа события
         event.SetChartID(this.m_chart_id);
         event.SetTypeEvent();
         //--- Если объекта-события нет в списке - добавляем
         if(!this.IsPresentEventInList(event))
           {
            this.m_list_trade_events.InsertSort(event);
            //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
            this.m_trade_event=event.TradeEvent();
            this.m_is_event=true;
            event.SendEvent();
            CBaseObj::EventAdd(this.m_trade_event,order.Ticket(),order.PriceOpen(),order.Symbol());
           }
         //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
         else
           {
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
            delete event;
           }
        }
     }
//--- Закрыта позиция (__MQL4__)
   if(status==ORDER_STATUS_HISTORY_ORDER)
     {
      //--- Установим код торгового события "позиция закрыта"
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_CLOSED;
      //--- Установим причину "запрос исполнен полностью""
      ENUM_EVENT_REASON reason=EVENT_REASON_DONE;
      //--- Если у ордера установлен флаг закрытия по StopLoss - значит позиция закрыта по StopLoss
      if(order.IsCloseByStopLoss())
        {
         //--- установим причину "закрытие по StopLoss"
         reason=EVENT_REASON_DONE_SL;
         //--- добавим к коду события флаг закрытия по StopLoss
         this.m_trade_event_code+=TRADE_EVENT_FLAG_SL;
        }
      //--- Если у ордера установлен флаг закрытия по TakeProfit - значит позиция закрыта по TakeProfit
      if(order.IsCloseByTakeProfit())
        {
         //--- установим причину "закрытие по TakeProfit"
         reason=EVENT_REASON_DONE_TP;
         //--- добавим к коду события флаг закрытия по TakeProfit
         this.m_trade_event_code+=TRADE_EVENT_FLAG_TP;
        }
      //--- Если у ордера заполнено свойство с наследуемым ордером - значит позиция закрыта частично
      if(order.TicketTo()>0)
        {
         //--- установим причину "частичное закрытие"
         reason=EVENT_REASON_DONE_PARTIALLY;
         //--- добавим к коду события флаг частичного закрытия
         this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
        }
      //--- Проверка закрытия встречной позицией
      COrder* order_close_by=this.GetCloseByOrderFromList(list_history,order.Ticket());
      //--- Объявим переменные свойств встречного ордера и инициализируем их значениями текущей закрытой позиции 
      ENUM_ORDER_TYPE close_by_type=this.m_type_first;
      double close_by_volume=order.Volume();
      ulong  close_by_ticket=order.Ticket();
      long   close_by_magic=order.Magic();
      string close_by_symbol=order.Symbol();
      //--- Если в списке исторических ордеров есть ордер с идентификатором закрытой позиции - значит позиция закрыта встречной
      if(order_close_by!=NULL)
        {
         //--- Заполним свойства встречного закрывающего ордера данными свойств встречной позиции
         close_by_type=(ENUM_ORDER_TYPE)order_close_by.TypeOrder();
         close_by_ticket=order_close_by.Ticket();
         close_by_magic=order_close_by.Magic();
         close_by_symbol=order_close_by.Symbol();
         close_by_volume=order_close_by.Volume();
         //--- установим причину "закрытие встречной"
         reason=EVENT_REASON_DONE_BY_POS;
         //--- добавим к коду события флаг закрытия встречной
         this.m_trade_event_code+=TRADE_EVENT_FLAG_BY_POS;
         //--- Возьмём данные о (1) закрытой и (2) встречной позициях из списка контрольных ордеров
         //--- (в этом списке свойства двух встречных позиций остались какими были до закрытия)
         COrderControl* ctrl_closed=this.GetOrderControlByTicket(list_control,order.Ticket());
         COrderControl* ctrl_close_by=this.GetOrderControlByTicket(list_control,close_by_ticket);
         double vol_closed=0;
         double vol_close_by=0;
         //--- Если эти два встречных ордера получены без ошибок
         if(ctrl_closed!=NULL && ctrl_close_by!=NULL)
           {
            //--- Рассчитаем закрытые объёмы (1) закрытой и (2) встречной позиций
            vol_closed=ctrl_closed.Volume()-order.Volume();
            vol_close_by=vol_closed-close_by_volume;
            //--- Если позиция закрыта частично (прошлый объём был больше, чем текущий закрытый)
            if(ctrl_closed.Volume()>order.Volume())
              {
               //--- добавим к коду события флаг частичного закрытия
               this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
               //--- установим причину "частичное закрытие"
               reason=EVENT_REASON_DONE_PARTIALLY_BY_POS;
              }
           }
        }
      //--- Создаём событие закрытия позиции
      CEvent* event=new CEventPositionClose(this.m_trade_event_code,order.Ticket());
      if(event!=NULL && order.PositionByID()==0)
        {
         event.SetProperty(EVENT_PROP_TIME_EVENT,order.TimeClose());                               // Время события
         event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                                        // Причина события (из перечисления ENUM_EVENT_REASON)
         event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,close_by_type);                              // Тип сделки события
         event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,order.Ticket());                           // Тикет сделки события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,close_by_type);                             // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,this.m_type_first);                      // Тип ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,close_by_ticket);                         // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order.Ticket());                       // Тикет ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_POSITION_ID,this.m_position_id);                             // Идентификатор позиции
         event.SetProperty(EVENT_PROP_POSITION_BY_ID,close_by_ticket);                             // Идентификатор встречной позиции
         event.SetProperty(EVENT_PROP_MAGIC_BY_ID,close_by_magic);                                 // Магический номер встречной позиции
            
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order.TypeOrder());                      // Тип ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order.Ticket());                       // Тикет ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order.TypeOrder());                     // Тип ордера текущей позиции
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order.Ticket());                      // Тикет ордера текущей позиции
      
         event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order.PriceOpen());                        // Цена установки ордера до модификации
         event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order.StopLoss());                           // Цена StopLoss до модификации
         event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order.TakeProfit());                         // Цена TakeProfit до модификации
         event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,this.m_tick.ask);                            // Цена Ask в момент события
         event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,this.m_tick.bid);                            // Цена Bid в момент события
         
         event.SetProperty(EVENT_PROP_MAGIC_ORDER,order.Magic());                                  // Магический номер ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order.TimeOpen());                       // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_PRICE_EVENT,order.PriceOpen());                              // Цена, на которой произошло событие
         event.SetProperty(EVENT_PROP_PRICE_OPEN,order.PriceOpen());                               // Цена открытия ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_PRICE_CLOSE,order.PriceClose());                             // Цена закрытия ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_PRICE_SL,order.StopLoss());                                  // Цена StopLoss позиции
         event.SetProperty(EVENT_PROP_PRICE_TP,order.TakeProfit());                                // Цена TakeProfit позиции
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order.Volume());                        // Запрашиваемый объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,order.Volume()-order.VolumeCurrent()); // Исполненный объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order.VolumeCurrent());                 // Оставшийся (неисполненный) объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,order.Volume());                    // Исполненный объём позиции
         event.SetProperty(EVENT_PROP_PROFIT,order.Profit());                                      // Профит
         event.SetProperty(EVENT_PROP_SYMBOL,order.Symbol());                                      // Символ ордера
         event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,close_by_symbol);                               // Символ встречной позиции
         //--- Установка идентификатора графика управляющей программы и расшифровка кода события и установка типа события
         event.SetChartID(this.m_chart_id);
         event.SetTypeEvent();
         //--- Если объекта-события нет в списке - добавляем
         if(!this.IsPresentEventInList(event))
           {
            this.m_list_trade_events.InsertSort(event);
            //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
            this.m_trade_event=event.TradeEvent();
            this.m_is_event=true;
            event.SendEvent();
            CBaseObj::EventAdd(this.m_trade_event,order.Ticket(),order.PriceClose(),order.Symbol());
           }
         //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
         else
           {
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
            delete event;
           }
        }
     }
#endif 
//--- Новая сделка (__MQL5__)
   if(status==ORDER_STATUS_DEAL)
     {
      //--- Новая балансовая оберация
      if((ENUM_DEAL_TYPE)order.TypeOrder()>DEAL_TYPE_SELL)
        {
         this.m_trade_event_code=TRADE_EVENT_FLAG_ACCOUNT_BALANCE;
         CEvent* event=new CEventBalanceOperation(this.m_trade_event_code,order.Ticket());
         if(event!=NULL)
           {
            ENUM_EVENT_REASON reason=
              (
               (ENUM_DEAL_TYPE)order.TypeOrder()==DEAL_TYPE_BALANCE ? (order.Profit()>0 ? EVENT_REASON_BALANCE_REFILL : EVENT_REASON_BALANCE_WITHDRAWAL) :
               (ENUM_EVENT_REASON)(order.TypeOrder()+REASON_EVENT_SHIFT)
              );
            event.SetProperty(EVENT_PROP_TIME_EVENT,order.TimeOpen());                    // Время события
            event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                            // Причина события (из перечисления ENUM_EVENT_REASON)
            event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,order.TypeOrder());              // Тип сделки события
            event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,order.Ticket());               // Тикет сделки события
            event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order.TypeOrder());             // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order.TypeOrder());          // Тип ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order.Ticket());              // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order.Ticket());           // Тикет ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_POSITION_ID,order.PositionID());                 // Идентификатор позиции
            event.SetProperty(EVENT_PROP_POSITION_BY_ID,order.PositionByID());            // Идентификатор встречной позиции
            event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                  // Магический номер встречной позиции
            
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order.TypeOrder());          // Тип ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order.Ticket());           // Тикет ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order.TypeOrder());         // Тип ордера текущей позиции
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order.Ticket());          // Тикет ордера текущей позиции
      
            event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order.PriceOpen());            // Цена установки ордера до модификации
            event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order.StopLoss());               // Цена StopLoss до модификации
            event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order.TakeProfit());             // Цена TakeProfit до модификации
            event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,this.m_tick.ask);                // Цена Ask в момент события
            event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,this.m_tick.bid);                // Цена Bid в момент события
         
            event.SetProperty(EVENT_PROP_MAGIC_ORDER,order.Magic());                      // Магический номер ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order.TimeOpen());           // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_PRICE_EVENT,order.PriceOpen());                  // Цена, на которой произошло событие
            event.SetProperty(EVENT_PROP_PRICE_OPEN,order.PriceOpen());                   // Цена открытия ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_PRICE_CLOSE,order.PriceOpen());                  // Цена закрытия ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_PRICE_SL,0);                                     // Цена StopLoss сделки
            event.SetProperty(EVENT_PROP_PRICE_TP,0);                                     // Цена TakeProfit сделки
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order.Volume());            // Запрашиваемый объём сделки
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,order.Volume());           // Исполненный объём сделки
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,0);                         // Оставшийся (неисполненный) объём сделки
            event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,order.Volume());        // Исполненный объём позиции
            event.SetProperty(EVENT_PROP_PROFIT,order.Profit());                          // Профит
            event.SetProperty(EVENT_PROP_SYMBOL,order.Symbol());                          // Символ ордера
            event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order.Symbol());                    // Символ встречной позиции
            //--- Установка идентификатора графика управляющей программы и расшифровка кода события и установка типа события
            event.SetChartID(this.m_chart_id);
            event.SetTypeEvent();
            //--- Если объекта-события нет в списке - добавляем
            if(!this.IsPresentEventInList(event))
              {
               //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
               this.m_list_trade_events.InsertSort(event);
               this.m_trade_event=event.TradeEvent();
               this.m_is_event=true;
               event.SendEvent();
               CBaseObj::EventAdd(this.m_trade_event,order.Ticket(),order.Profit(),order.Symbol());
              }
            //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
            else
              {
               ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
               delete event;
              }
           }
        }
      //--- Если это не балансовая операция
      else
        {
         if(this.m_is_hedge)
            this.NewDealEventHedge(order,list_history,list_market);
         else
            this.NewDealEventNetto(order,list_history,list_market);
        }
     }
  }
//+------------------------------------------------------------------+
//| Создаёт событие для хеджевого счёта                              |
//+------------------------------------------------------------------+
void CEventsCollection::NewDealEventHedge(COrder* deal,CArrayObj* list_history,CArrayObj* list_market)
  {
#ifdef __MQL5__
   double ask=::SymbolInfoDouble(deal.Symbol(),SYMBOL_ASK);
   double bid=::SymbolInfoDouble(deal.Symbol(),SYMBOL_BID);
//--- Вход в рынок
   if(deal.GetProperty(ORDER_PROP_DEAL_ENTRY)==DEAL_ENTRY_IN)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_OPENED;
      int reason=EVENT_REASON_DONE;
      //--- Ищем все сделки позиции в направлении её открытия и считаем их общий объём
      double volume_in=this.SummaryVolumeDealsInByPosID(list_history,deal.PositionID());
      //--- Возьмём ордер сделки и последний ордер позиции из списка всех ордеров позиции
      ulong order_ticket=deal.GetProperty(ORDER_PROP_DEAL_ORDER_TICKET);
      COrder* order_first=this.GetHistoryOrderByTicket(list_history,order_ticket);
      COrder* order_last=this.GetLastOrderFromList(list_history,deal.PositionID());
      //--- Получим открытую позицию по тикету
      COrder* position=this.GetPositionByID(list_market,deal.PositionID());
      double vol_position=(position!=NULL ? position.Volume() : 0);
      //--- Если последнего ордера нет, то первый и последний ордер позиции - один и тот же
      if(order_last==NULL)
         order_last=order_first;
      if(order_first!=NULL)
        {
         //--- Если не весь объём ордера открыт - значит частичное исполнение
         if(this.SummaryVolumeDealsInByPosID(list_history,deal.PositionID())<order_first.Volume())
           {
            this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
            reason=EVENT_REASON_DONE_PARTIALLY;
           }
         //--- Если открывающий ордер - отложенный, значит - активирован отложенный ордер
         if(order_first.TypeOrder()>ORDER_TYPE_SELL && order_first.TypeOrder()<ORDER_TYPE_CLOSE_BY)
           {
            this.m_trade_event_code+=TRADE_EVENT_FLAG_ORDER_ACTIVATED;
            //--- Если ордер исполнен частично, ставим в причину события частичное исполнение ордера
            reason=
              (this.SummaryVolumeDealsInByPosID(list_history,deal.PositionID())<order_first.Volume() ? 
               EVENT_REASON_ACTIVATED_PENDING_PARTIALLY : 
               EVENT_REASON_ACTIVATED_PENDING
              );
           }
         CEvent* event=new CEventPositionOpen(this.m_trade_event_code,deal.PositionID());
         if(event!=NULL)
           {
            event.SetProperty(EVENT_PROP_TIME_EVENT,deal.TimeOpen());                           // Время события (Время открытия позиции)
            event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                                  // Причина события (из перечисления ENUM_EVENT_REASON)
            event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,deal.TypeOrder());                     // Тип сделки события
            event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,deal.Ticket());                      // Тикет сделки события
            event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order_first.TypeOrder());          // Тип ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order_first.Ticket());           // Тикет ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order_last.TypeOrder());              // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order_last.Ticket());               // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_POSITION_ID,deal.PositionID());                        // Идентификатор позиции
            event.SetProperty(EVENT_PROP_POSITION_BY_ID,order_last.PositionByID());             // Идентификатор встречной позиции
            //---
            event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                        // Магический номер встречной позиции
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order_first.TypeOrder());          // Тип ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order_first.Ticket());           // Тикет ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order_first.TypeOrder());         // Тип ордера текущей позиции
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order_first.Ticket());          // Тикет ордера текущей позиции
            event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,deal.Symbol());                           // Символ встречной позиции
            //---
            event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order_first.PriceOpen());            // Цена установки ордера до модификации
            event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order_first.StopLoss());               // Цена StopLoss до модификации
            event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order_first.TakeProfit());             // Цена TakeProfit до модификации
            event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,ask);                                  // Цена Ask в момент события
            event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,bid);                                  // Цена Bid в момент события
            //---
            event.SetProperty(EVENT_PROP_MAGIC_ORDER,deal.Magic());                             // Магический номер ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order_first.TimeOpen());           // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_PRICE_EVENT,deal.PriceOpen());                         // Цена, на которой произошло событие (Цена открытия позиции)
            event.SetProperty(EVENT_PROP_PRICE_OPEN,order_first.PriceOpen());                   // Цена открытия ордера (Цена установки открывающего ордера позиции)
            event.SetProperty(EVENT_PROP_PRICE_CLOSE,order_last.PriceClose());                  // Цена закрытия ордера (Цена закрытия последнего ордера позиции)
            event.SetProperty(EVENT_PROP_PRICE_SL,order_first.StopLoss());                      // Цена StopLoss (Цена StopLoss ордера позиции)
            event.SetProperty(EVENT_PROP_PRICE_TP,order_first.TakeProfit());                    // Цена TakeProfit (Цена TakeProfit ордера позиции)
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order_first.Volume());                                 // Запрашиваемый объём ордера
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,(order_first.Volume()-order_first.VolumeCurrent()));  // Исполненный объём ордера
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order_first.VolumeCurrent());                          // Оставшийся (неисполненный) объём ордера
            event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,vol_position);                                     // Исполненный объём позиции
            event.SetProperty(EVENT_PROP_PROFIT,deal.ProfitFull());                             // Профит
            event.SetProperty(EVENT_PROP_SYMBOL,deal.Symbol());                                 // Символ ордера
            //--- Установка идентификатора графика управляющей программы и расшифровка кода события и установка типа события
            event.SetChartID(this.m_chart_id);
            event.SetTypeEvent();
            //--- Если объекта-события нет в списке - добавляем
            if(!this.IsPresentEventInList(event))
              {
               this.m_list_trade_events.InsertSort(event);
               //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
               this.m_trade_event=event.TradeEvent();
               this.m_is_event=true;
               event.SendEvent();
               CBaseObj::EventAdd(this.m_trade_event,deal.Ticket(),deal.PriceOpen(),deal.Symbol());
              }
            //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
            else
              {
               ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
               delete event;
              }
           }
        }
     }
//--- Выход из рынка
   else if(deal.GetProperty(ORDER_PROP_DEAL_ENTRY)==DEAL_ENTRY_OUT)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_CLOSED;
      int reason=EVENT_REASON_DONE;
      //--- Возьмём первый и последний ордера позиции из списка всех ордеров позиции
      COrder* order_first=this.GetFirstOrderFromList(list_history,deal.PositionID());
      COrder* order_last=this.GetLastOrderFromList(list_history,deal.PositionID());
      //--- Получим открытую позицию по тикету
      COrder* position=this.GetPositionByID(list_market,deal.PositionID());
      double vol_position=(position!=NULL ? position.Volume() : 0);
      if(order_first!=NULL && order_last!=NULL)
        {
         //--- Ищем все сделки позиции в направлении её открытия и закрытия, и считаем их общий объём
         double volume_in=this.SummaryVolumeDealsInByPosID(list_history,deal.PositionID());
         double volume_out=this.SummaryVolumeDealsOutByPosID(list_history,deal.PositionID());
         //--- Рассчитываем текущий объём закрытой позиции
         int dgl=(int)DigitsLots(deal.Symbol());
         double volume_current=::NormalizeDouble(volume_in-volume_out,dgl);
         //--- Если не весь объём позиции закрыт - значит частичное исполнение
         if(volume_current>0)
           {
            this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
           }
         //--- Если закрывающий ордер исполнен частично, ставим в причину события частичное исполнение закрывающего ордера
         if(order_last.VolumeCurrent()>0)
           {
            reason=EVENT_REASON_DONE_PARTIALLY;
           }
         //--- Если у закрывающего ордера позиции выставлен флаг закрытия по StopLoss - значит закрытие по StopLoss
         //--- Если StopLoss-ордер исполнен частично, ставим в причину события частичное исполнение ордера StopLoss
         if(order_last.IsCloseByStopLoss())
           {
            this.m_trade_event_code+=TRADE_EVENT_FLAG_SL;
            reason=(order_last.VolumeCurrent()>0 ? EVENT_REASON_DONE_SL_PARTIALLY : EVENT_REASON_DONE_SL);
           }
         //--- Если у закрывающего ордера позиции выставлен флаг закрытия по TakeProfit - значит закрытие по TakeProfit
         //--- Если TakeProfit-ордер исполнен частично, ставим в причину события частичное исполнение ордера TakeProfit
         else if(order_last.IsCloseByTakeProfit())
           {
            this.m_trade_event_code+=TRADE_EVENT_FLAG_TP;
            reason=(order_last.VolumeCurrent()>0 ? EVENT_REASON_DONE_TP_PARTIALLY : EVENT_REASON_DONE_TP);
           }
         //---
         CEvent* event=new CEventPositionClose(this.m_trade_event_code,deal.PositionID());
         if(event!=NULL)
           {
            event.SetProperty(EVENT_PROP_TIME_EVENT,deal.TimeOpen());                           // Время события (Время закрытия позиции)
            event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                                  // Причина события (из перечисления ENUM_EVENT_REASON)
            event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,deal.TypeOrder());                     // Тип сделки события
            event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,deal.Ticket());                      // Тикет сделки события
            event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order_first.TypeOrder());          // Тип ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order_last.TypeOrder());              // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order_first.Ticket());           // Тикет ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order_last.Ticket());               // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_POSITION_ID,deal.PositionID());                        // Идентификатор позиции
            event.SetProperty(EVENT_PROP_POSITION_BY_ID,order_last.PositionByID());             // Идентификатор встречной позиции
            //---
            event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                        // Магический номер встречной позиции
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order_first.TypeOrder());          // Тип ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order_first.Ticket());           // Тикет ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order_first.TypeOrder());         // Тип ордера текущей позиции
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order_first.Ticket());          // Тикет ордера текущей позиции
            event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order_last.Symbol());                     // Символ встречной позиции
            //---
            event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order_first.PriceOpen());            // Цена установки ордера до модификации
            event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order_first.StopLoss());               // Цена StopLoss до модификации
            event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order_first.TakeProfit());             // Цена TakeProfit до модификации
            event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,ask);                                  // Цена Ask в момент события
            event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,bid);                                  // Цена Bid в момент события
            //---
            event.SetProperty(EVENT_PROP_MAGIC_ORDER,deal.Magic());                             // Магический номер ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order_first.TimeOpen());           // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_PRICE_EVENT,deal.PriceOpen());                         // Цена, на которой произошло событие (Цена закрытия позиции)
            event.SetProperty(EVENT_PROP_PRICE_OPEN,order_first.PriceOpen());                   // Цена открытия ордера (Цена установки открывающего ордера позиции)
            event.SetProperty(EVENT_PROP_PRICE_CLOSE,order_last.PriceClose());                  // Цена закрытия ордера  (Цена закрытия последнего ордера позиции)
            event.SetProperty(EVENT_PROP_PRICE_SL,order_first.StopLoss());                      // Цена StopLoss (Цена StopLoss ордера позиции)
            event.SetProperty(EVENT_PROP_PRICE_TP,order_first.TakeProfit());                    // Цена TakeProfit (Цена TakeProfit ордера позиции)
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order_last.Volume());                               // Запрашиваемый объём ордера
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,order_last.Volume()-order_last.VolumeCurrent());   // Исполненный объём ордера
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,order_last.VolumeCurrent());                        // Оставшийся (текущий) объём ордера
            event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,vol_position);                                  // Оставшийся (текущий) объём позиции
            //---
            event.SetProperty(EVENT_PROP_PROFIT,deal.ProfitFull());                             // Профит
            event.SetProperty(EVENT_PROP_SYMBOL,deal.Symbol());                                 // Символ ордера
            //--- Установка идентификатора графика управляющей программы и расшифровка кода события и установка типа события
            event.SetChartID(this.m_chart_id);
            event.SetTypeEvent();
            //--- Если объекта-события нет в списке - добавляем
            if(!this.IsPresentEventInList(event))
              {
               this.m_list_trade_events.InsertSort(event);
               //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
               this.m_trade_event=event.TradeEvent();
               this.m_is_event=true;
               event.SendEvent();
               CBaseObj::EventAdd(this.m_trade_event,order_first.Ticket(),deal.PriceOpen(),deal.Symbol());
              }
            //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
            else
              {
               ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
               delete event;
              }
           }
        }
     }
//--- Встречная позиция
   else if(deal.GetProperty(ORDER_PROP_DEAL_ENTRY)==DEAL_ENTRY_OUT_BY)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_CLOSED;
      int reason=EVENT_REASON_DONE_BY_POS;
      //--- Возьмём первый и закрывающий ордера позиции из списка всех ордеров позиции
      COrder* order_first=this.GetFirstOrderFromList(list_history,deal.PositionID());
      COrder* order_close=this.GetCloseByOrderFromList(list_history,deal.PositionID());
      //--- Получим открытую позицию по идентификатору
      COrder* position=this.GetPositionByID(list_market,order_first.PositionID());
      double vol_position=(position!=NULL ? position.Volume() : 0);
      if(order_first!=NULL && order_close!=NULL)
        {
         //--- Добавляем флаг закрытия встречной
         this.m_trade_event_code+=TRADE_EVENT_FLAG_BY_POS;
         //--- Возьмём первый ордер закрывающей позиции
         CArrayObj* list_close_by=this.GetListAllOrdersByPosID(list_history,order_close.PositionByID());
         COrder* order_close_by=list_close_by.At(0);
         if(order_close_by==NULL)
            return;
         //--- Ищем все сделки закрытой позиции в направлении её открытия и закрытия, и считаем их общий объём
         double volume_in=this.SummaryVolumeDealsInByPosID(list_history,deal.PositionID());
         double volume_out=this.SummaryVolumeDealsOutByPosID(list_history,deal.PositionID());//+order_close.Volume();
         //--- Рассчитываем текущий объём закрытой позиции
         int dgl=(int)DigitsLots(deal.Symbol());
         double volume_current=::NormalizeDouble(volume_in-volume_out,dgl);
         //--- Ищем все сделки встречной позиции в направлении её открытия и закрытия, и считаем их общий объём
         double volume_opp_in=this.SummaryVolumeDealsInByPosID(list_history,order_close.PositionByID());
         double volume_opp_out=this.SummaryVolumeDealsOutByPosID(list_history,order_close.PositionByID());
         //--- Рассчитываем текущий объём встречной позиции
         double volume_opp_current=::NormalizeDouble(volume_opp_in-volume_opp_out,dgl);
         //--- Если не весь объём закрытой позиции закрыт - значит частичное закрытие
         if(volume_current>0 || order_close.VolumeCurrent()>0)
           {
            //--- Добавляем флаг частичного закрытия
            this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
            //--- Если встречная позиция закрыта частично - значит частичное закрытие частью объёма встречной позиции
            reason=(volume_opp_current>0 ? EVENT_REASON_DONE_PARTIALLY_BY_POS_PARTIALLY : EVENT_REASON_DONE_PARTIALLY_BY_POS);
           }
         //--- Если закрыт весь объём позиции и есть частичное исполнение встречной - значит закрытие частью объёма встречной позиции
         else
           {
            if(volume_opp_current>0)
              {
               reason=EVENT_REASON_DONE_BY_POS_PARTIALLY;
              }
           }
         CEvent* event=new CEventPositionClose(this.m_trade_event_code,deal.PositionID());
         if(event!=NULL)
           {
            event.SetProperty(EVENT_PROP_TIME_EVENT,deal.TimeOpen());                           // Время события
            event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                                  // Причина события (из перечисления ENUM_EVENT_REASON)
            event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,deal.TypeOrder());                     // Тип сделки события
            event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,deal.Ticket());                      // Тикет сделки события
            event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,order_close.TypeOrder());             // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,order_close.Ticket());              // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
            event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order_first.TimeOpen());           // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,order_first.TypeOrder());          // Тип ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,order_first.Ticket());           // Тикет ордера, на основании которого открыта сделка позиции (первый ордер позиции)
            event.SetProperty(EVENT_PROP_POSITION_ID,deal.PositionID());                        // Идентификатор позиции
            event.SetProperty(EVENT_PROP_POSITION_BY_ID,order_close.PositionByID());            // Идентификатор встречной позиции
            //---
            event.SetProperty(EVENT_PROP_MAGIC_BY_ID,order_close_by.Magic());                   // Магический номер встречной позиции
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,order_first.TypeOrder());          // Тип ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,order_first.Ticket());           // Тикет ордера позиции до смены направления
            event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,order_first.TypeOrder());         // Тип ордера текущей позиции
            event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,order_first.Ticket());          // Тикет ордера текущей позиции
            event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,order_close_by.Symbol());                 // Символ встречной позиции
            //---
            event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order_first.PriceOpen());            // Цена установки ордера до модификации
            event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order_first.StopLoss());               // Цена StopLoss до модификации
            event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order_first.TakeProfit());             // Цена TakeProfit до модификации
            event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,ask);                                  // Цена Ask в момент события
            event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,bid);                                  // Цена Bid в момент события
            //---
            event.SetProperty(EVENT_PROP_MAGIC_ORDER,deal.Magic());                             // Магический номер ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_PRICE_EVENT,deal.PriceOpen());                         // Цена, на которой произошло событие
            event.SetProperty(EVENT_PROP_PRICE_OPEN,order_first.PriceOpen());                   // Цена открытия ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_PRICE_CLOSE,deal.PriceClose());                        // Цена закрытия ордера/сделки/позиции
            event.SetProperty(EVENT_PROP_PRICE_SL,order_first.StopLoss());                      // Цена StopLoss (Цена StopLoss ордера позиции)
            event.SetProperty(EVENT_PROP_PRICE_TP,order_first.TakeProfit());                    // Цена TakeProfit (Цена TakeProfit ордера позиции)
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,::NormalizeDouble(volume_in,dgl));// Первоначальный объём
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,deal.Volume());                  // Закрытый объём
            event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,volume_current);                  // Оставшийся (текущий) объём
            event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,vol_position);                // Оставшийся (текущий) объём
            event.SetProperty(EVENT_PROP_PROFIT,deal.ProfitFull());                             // Профит
            event.SetProperty(EVENT_PROP_SYMBOL,deal.Symbol());                                 // Символ ордера
            //--- Установка идентификатора графика управляющей программы и расшифровка кода события и установка типа события
            event.SetChartID(this.m_chart_id);
            event.SetTypeEvent();
            //--- Если объекта-события нет в списке - добавляем
            if(!this.IsPresentEventInList(event))
              {
               this.m_list_trade_events.InsertSort(event);
               //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
               this.m_trade_event=event.TradeEvent();
               this.m_is_event=true;
               event.SendEvent();
               CBaseObj::EventAdd(this.m_trade_event,order_first.Ticket(),deal.PriceOpen(),deal.Symbol());
              }
            //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
            else
              {
               ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
               delete event;
              }
           }
        }
     }
#endif 
  }
//+------------------------------------------------------------------+
//| Создаёт событие для неттингового счёта                           |
//+------------------------------------------------------------------+
void CEventsCollection::NewDealEventNetto(COrder *deal,CArrayObj *list_history,CArrayObj *list_market)
  {
#ifdef __MQL5__
   double ask=::SymbolInfoDouble(deal.Symbol(),SYMBOL_ASK);
   double bid=::SymbolInfoDouble(deal.Symbol(),SYMBOL_BID);
//--- Подготовка данных по истории позиции
//--- Списки всех сделок и изменений направления позиции
   CArrayObj* list_deals=this.GetListAllDealsByPosID(list_history,deal.PositionID());
   CArrayObj* list_changes=this.GetListAllDealsInOutByPosID(list_history,deal.PositionID());
   if(list_deals==NULL || list_changes==NULL)
      return;
   list_deals.Sort(SORT_BY_ORDER_TIME_OPEN);
   list_changes.Sort(SORT_BY_ORDER_TIME_OPEN);
   if(!list_changes.InsertSort(list_deals.At(0)))
      return;
   
//--- Ордера первой и последней сделок позиции
   CArrayObj* list_tmp=this.GetListAllOrdersByPosID(list_history,deal.PositionID());
   COrder* order_first_deal=list_tmp.At(0);
   list_tmp=CSelect::ByOrderProperty(list_tmp,ORDER_PROP_TICKET,deal.GetProperty(ORDER_PROP_DEAL_ORDER_TICKET),EQUAL);
   COrder* order_last_deal=list_tmp.At(list_tmp.Total()-1);
   if(order_first_deal==NULL || order_last_deal==NULL)
      return;
//--- Тип и тикеты ордеров первой и последней сделок позиции
   ENUM_ORDER_TYPE type_order_first_deal=(ENUM_ORDER_TYPE)order_first_deal.TypeOrder();
   ENUM_ORDER_TYPE type_order_last_deal=(ENUM_ORDER_TYPE)order_last_deal.TypeOrder();
   ulong ticket_order_first_deal=order_first_deal.Ticket();
   ulong ticket_order_last_deal=order_last_deal.Ticket();
   
//--- Текущая и прошлая позиции
   COrder* position_current=list_changes.At(list_changes.Total()-1);
   COrder* position_previous=(list_changes.Total()>1 ? list_changes.At(list_changes.Total()-2) : position_current);
   if(position_current==NULL || position_previous==NULL)
      return;
   ENUM_ORDER_TYPE type_position_current=(ENUM_ORDER_TYPE)position_current.TypeOrder();
   ulong ticket_position_current=position_current.GetProperty(ORDER_PROP_DEAL_ORDER_TICKET);
   ENUM_ORDER_TYPE type_position_previous=(ENUM_ORDER_TYPE)position_previous.TypeOrder();
   ulong ticket_position_previous=position_previous.GetProperty(ORDER_PROP_DEAL_ORDER_TICKET);

//--- Получим открытую позицию по тикету и запишем её объём
   COrder* position=this.GetPositionByID(list_market,deal.PositionID());
   double vol_position=(position!=NULL ? position.Volume() : 0);
//--- Исполненный объём ордера
   double vol_order_done=order_last_deal.Volume()-order_last_deal.VolumeCurrent();
//--- Оставшийся (неисполненный) объём ордера
   double vol_order_current=order_last_deal.VolumeCurrent();

//--- Вход в рынок
   if(deal.GetProperty(ORDER_PROP_DEAL_ENTRY)==DEAL_ENTRY_IN)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_OPENED;
      int num_deals=list_deals.Total();
      int reason=(num_deals>1 ? EVENT_REASON_VOLUME_ADD : EVENT_REASON_DONE);
      //--- Если это не первая сделка в позиции, добавляем флаг изменения позиции
      if(num_deals>1)
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_POSITION_CHANGED;
        }
      //--- Если не весь объём ордера открыт - значит частичное исполнение
      if(order_last_deal.VolumeCurrent()>0)
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
         //--- Если это не первая сделка позиции - значит добавление объёма частичным исполнением, иначе - частичное открытие
         reason=(num_deals>1 ? EVENT_REASON_VOLUME_ADD_PARTIALLY : EVENT_REASON_DONE_PARTIALLY);
        }
      //--- Если открывающий ордер - отложенный, значит - активирован отложенный ордер
      if(order_last_deal.TypeOrder()>ORDER_TYPE_SELL && order_last_deal.TypeOrder()<ORDER_TYPE_CLOSE_BY)
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_ORDER_ACTIVATED;
         //--- Если это не первая сделка позиции
         if(num_deals>1)
           {
            //--- Если ордер исполнен частично, ставим в причину события добавление объёма к позиции частичным исполнением отложенного ордера
            //--- иначе - добавление объёма к позиции исполнением отложенного ордера
            reason=
              (order_last_deal.VolumeCurrent()>0 ? 
               EVENT_REASON_VOLUME_ADD_BY_PENDING_PARTIALLY  : 
               EVENT_REASON_VOLUME_ADD_BY_PENDING
              );
           }
         //--- Если это новая позиция
         else
           {
            //--- Если ордер исполнен частично, ставим в причину события частичноем исполнение отложенного ордера,
            //--- иначе - открытие позиции активацией отложенного ордера
            reason=
              (order_last_deal.VolumeCurrent()>0 ? 
               EVENT_REASON_ACTIVATED_PENDING_PARTIALLY  : 
               EVENT_REASON_ACTIVATED_PENDING
              );
           }
        }
      CEvent* event=new CEventPositionOpen(this.m_trade_event_code,deal.PositionID());
      if(event!=NULL)
        {
         //--- Параметры сделки события
         event.SetProperty(EVENT_PROP_TIME_EVENT,deal.TimeOpen());                        // Время события (Время открытия позиции)
         event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                               // Причина события (из перечисления ENUM_EVENT_REASON)
         event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,deal.TypeOrder());                  // Тип сделки события
         event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,deal.Ticket());                   // Тикет сделки события
         event.SetProperty(EVENT_PROP_MAGIC_ORDER,deal.Magic());                          // Магический номер ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_PRICE_EVENT,deal.PriceOpen());                      // Цена, на которой произошло событие (Цена открытия позиции)
         event.SetProperty(EVENT_PROP_PROFIT,deal.ProfitFull());                          // Профит
         event.SetProperty(EVENT_PROP_SYMBOL,deal.Symbol());                              // Символ ордера
         event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,deal.Symbol());                        // Символ встречной позиции
         event.SetProperty(EVENT_PROP_POSITION_ID,deal.PositionID());                     // Идентификатор позиции
         
         //--- Параметры ордера события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,type_order_last_deal);             // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,ticket_order_last_deal);         // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_POSITION_BY_ID,order_last_deal.PositionByID());     // Идентификатор встречной позиции
         event.SetProperty(EVENT_PROP_PRICE_CLOSE,order_last_deal.PriceClose());          // Цена закрытия ордера (Цена закрытия последнего ордера позиции)
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order_last_deal.Volume());     // Запрашиваемый объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,vol_order_done);              // Исполненный объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,vol_order_current);            // Оставшийся (неисполненный) объём ордера
         event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                     // Магический номер встречной позиции
            
         //--- Параметры позиции
         event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,type_order_first_deal);         // Тип ордера, на основании которого открыта первая сделка позиции
         event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,ticket_order_first_deal);     // Тикет ордера, на основании которого открыта первая сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order_first_deal.TimeOpen());   // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_PRICE_OPEN,order_first_deal.PriceOpen());           // Цена открытия первого ордера позиции
         event.SetProperty(EVENT_PROP_PRICE_SL,order_first_deal.StopLoss());              // Цена StopLoss (Цена StopLoss ордера позиции)
         event.SetProperty(EVENT_PROP_PRICE_TP,order_first_deal.TakeProfit());            // Цена TakeProfit (Цена TakeProfit ордера позиции)
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,type_position_previous);        // Тип позиции до смены направления
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,ticket_position_previous);    // Тикет ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,type_position_current);        // Тип ордера текущей позиции
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,ticket_position_current);    // Тикет ордера текущей позиции
         event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,vol_position);             // Исполненный объём позиции

         event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order_first_deal.PriceOpen());    // Цена установки ордера до модификации
         event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order_first_deal.StopLoss());       // Цена StopLoss до модификации
         event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order_first_deal.TakeProfit());     // Цена TakeProfit до модификации
         event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,ask);                               // Цена Ask в момент события
         event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,bid);                               // Цена Bid в момент события
         
         //--- Установка идентификатора графика управляющей программы и расшифровка кода события, установка типа события
         event.SetChartID(this.m_chart_id);
         event.SetTypeEvent();
         //--- Если объекта-события нет в списке - добавляем
         if(!this.IsPresentEventInList(event))
           {
            this.m_list_trade_events.InsertSort(event);
            //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
            this.m_trade_event=event.TradeEvent();
            this.m_is_event=true;
            event.SendEvent();
            CBaseObj::EventAdd(this.m_trade_event,deal.Ticket(),deal.PriceOpen(),deal.Symbol());
           }
         //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
         else
           {
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
            delete event;
           }
        }
     }
//--- Разворот позиции
   else if(deal.GetProperty(ORDER_PROP_DEAL_ENTRY)==DEAL_ENTRY_INOUT)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_OPENED+TRADE_EVENT_FLAG_POSITION_CHANGED+TRADE_EVENT_FLAG_POSITION_REVERSE;
      int reason=EVENT_REASON_REVERSE;
      //--- Если не весь объём ордера открыт - значит частичное исполнение
      if(order_last_deal.VolumeCurrent()>0)
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
         reason=EVENT_REASON_REVERSE_PARTIALLY;
        }
      //--- Если открывающий ордер - отложенный, значит - активирован отложенный ордер
      if(order_last_deal.TypeOrder()>ORDER_TYPE_SELL && order_last_deal.TypeOrder()<ORDER_TYPE_CLOSE_BY)
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_ORDER_ACTIVATED;
         //--- Если ордер исполнен частично, ставим в причину события разворот позиции частичным исполнением отложенного ордера
         reason=
           (order_last_deal.VolumeCurrent()>0 ? 
            EVENT_REASON_REVERSE_BY_PENDING_PARTIALLY  : 
            EVENT_REASON_REVERSE_BY_PENDING
           );
        }
      CEvent* event=new CEventPositionOpen(this.m_trade_event_code,deal.PositionID());
      if(event!=NULL)
        {
         //--- Параметры сделки события
         event.SetProperty(EVENT_PROP_TIME_EVENT,deal.TimeOpen());                        // Время события (Время открытия позиции)
         event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                               // Причина события (из перечисления ENUM_EVENT_REASON)
         event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,deal.TypeOrder());                  // Тип сделки события
         event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,deal.Ticket());                   // Тикет сделки события
         event.SetProperty(EVENT_PROP_MAGIC_ORDER,deal.Magic());                          // Магический номер ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_PRICE_EVENT,deal.PriceOpen());                      // Цена, на которой произошло событие (Цена открытия позиции)
         event.SetProperty(EVENT_PROP_PROFIT,deal.ProfitFull());                          // Профит
         event.SetProperty(EVENT_PROP_SYMBOL,deal.Symbol());                              // Символ ордера
         event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,deal.Symbol());                        // Символ встречной позиции
         event.SetProperty(EVENT_PROP_POSITION_ID,deal.PositionID());                     // Идентификатор позиции
            
         //--- Параметры ордера события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,type_order_last_deal);             // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,ticket_order_last_deal);         // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_POSITION_BY_ID,order_last_deal.PositionByID());     // Идентификатор встречной позиции
         event.SetProperty(EVENT_PROP_PRICE_CLOSE,order_last_deal.PriceClose());          // Цена закрытия ордера (Цена закрытия последнего ордера позиции)
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order_last_deal.Volume());     // Запрашиваемый объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,vol_order_done);              // Исполненный объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,vol_order_current);            // Оставшийся (неисполненный) объём ордера
         event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                     // Магический номер встречной позиции
            
         //--- Параметры позиции
         event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,type_order_first_deal);         // Тип ордера, на основании которого открыта первая сделка позиции
         event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,ticket_order_first_deal);     // Тикет ордера, на основании которого открыта первая сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order_first_deal.TimeOpen());   // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_PRICE_OPEN,order_first_deal.PriceOpen());           // Цена открытия первого ордера позиции
         event.SetProperty(EVENT_PROP_PRICE_SL,order_first_deal.StopLoss());              // Цена StopLoss (Цена StopLoss ордера позиции)
         event.SetProperty(EVENT_PROP_PRICE_TP,order_first_deal.TakeProfit());            // Цена TakeProfit (Цена TakeProfit ордера позиции)
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,type_position_previous);        // Тип ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,ticket_position_previous);    // Тикет ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,type_position_current);        // Тип ордера текущей позиции
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,ticket_position_current);    // Тикет ордера текущей позиции
         event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,vol_position);             // Исполненный объём позиции

         event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order_first_deal.PriceOpen());    // Цена установки ордера до модификации
         event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order_first_deal.StopLoss());       // Цена StopLoss до модификации
         event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order_first_deal.TakeProfit());     // Цена TakeProfit до модификации
         event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,ask);                               // Цена Ask в момент события
         event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,bid);                               // Цена Bid в момент события
         
         //--- Установка идентификатора графика управляющей программы и расшифровка кода события, установка типа события
         event.SetChartID(this.m_chart_id);
         event.SetTypeEvent();
         //--- Если объекта-события нет в списке - добавляем
         if(!this.IsPresentEventInList(event))
           {
            this.m_list_trade_events.InsertSort(event);
            //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
            this.m_trade_event=event.TradeEvent();
            this.m_is_event=true;
            event.SendEvent();
            CBaseObj::EventAdd(this.m_trade_event,deal.Ticket(),deal.PriceOpen(),deal.Symbol());
           }
         //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
         else
           {
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
            delete event;
           }
        }
     }
//--- Выход из рынка
   else if(deal.GetProperty(ORDER_PROP_DEAL_ENTRY)==DEAL_ENTRY_OUT)
     {
      this.m_trade_event_code=TRADE_EVENT_FLAG_POSITION_CLOSED;
      int reason=EVENT_REASON_DONE;
      //--- Если позиция с идентификатором ещё в рынке - значит частичное исполнение
      if(this.GetPositionByID(list_market,deal.PositionID())!=NULL)
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_PARTIAL;
        }
      //--- Если закрывающий ордер исполнен частично, ставим в причину события частичное исполнение закрывающего ордера
      if(order_last_deal.VolumeCurrent()>0)
        {
         reason=EVENT_REASON_DONE_PARTIALLY;
        }
      //--- Если у закрывающего ордера позиции выставлен флаг закрытия по StopLoss - значит закрытие по StopLoss
      //--- Если StopLoss-ордер исполнен частично, ставим в причину события частичное исполнение ордера StopLoss
      if(order_last_deal.IsCloseByStopLoss())
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_SL;
         reason=(order_last_deal.VolumeCurrent()>0 ? EVENT_REASON_DONE_SL_PARTIALLY : EVENT_REASON_DONE_SL);
        }
      //--- Если у закрывающего ордера позиции выставлен флаг закрытия по TakeProfit - значит закрытие по TakeProfit
      //--- Если TakeProfit-ордер исполнен частично, ставим в причину события частичное исполнение ордера TakeProfit
      else if(order_last_deal.IsCloseByTakeProfit())
        {
         this.m_trade_event_code+=TRADE_EVENT_FLAG_TP;
         reason=(order_last_deal.VolumeCurrent()>0 ? EVENT_REASON_DONE_TP_PARTIALLY : EVENT_REASON_DONE_TP);
        }
      //---
      CEvent* event=new CEventPositionClose(this.m_trade_event_code,deal.PositionID());
      if(event!=NULL)
        {
         //--- Параметры сделки события
         event.SetProperty(EVENT_PROP_TIME_EVENT,deal.TimeOpen());                        // Время события (Время открытия позиции)
         event.SetProperty(EVENT_PROP_REASON_EVENT,reason);                               // Причина события (из перечисления ENUM_EVENT_REASON)
         event.SetProperty(EVENT_PROP_TYPE_DEAL_EVENT,deal.TypeOrder());                  // Тип сделки события
         event.SetProperty(EVENT_PROP_TICKET_DEAL_EVENT,deal.Ticket());                   // Тикет сделки события
         event.SetProperty(EVENT_PROP_MAGIC_ORDER,deal.Magic());                          // Магический номер ордера/сделки/позиции
         event.SetProperty(EVENT_PROP_PRICE_EVENT,deal.PriceOpen());                      // Цена, на которой произошло событие (Цена открытия позиции)
         event.SetProperty(EVENT_PROP_PROFIT,deal.ProfitFull());                          // Профит
         event.SetProperty(EVENT_PROP_SYMBOL,deal.Symbol());                              // Символ ордера
         event.SetProperty(EVENT_PROP_SYMBOL_BY_ID,deal.Symbol());                        // Символ встречной позиции
         event.SetProperty(EVENT_PROP_POSITION_ID,deal.PositionID());                     // Идентификатор позиции
         
         //--- Параметры ордера события
         event.SetProperty(EVENT_PROP_TYPE_ORDER_EVENT,type_order_last_deal);             // Тип ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_TICKET_ORDER_EVENT,ticket_order_last_deal);         // Тикет ордера, на основании которого открыта сделка события (последний ордер позиции)
         event.SetProperty(EVENT_PROP_POSITION_BY_ID,order_last_deal.PositionByID());     // Идентификатор встречной позиции
         event.SetProperty(EVENT_PROP_PRICE_CLOSE,order_last_deal.PriceClose());          // Цена закрытия ордера (Цена закрытия последнего ордера позиции)
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_INITIAL,order_last_deal.Volume());     // Запрашиваемый объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_EXECUTED,vol_order_done);              // Исполненный объём ордера
         event.SetProperty(EVENT_PROP_VOLUME_ORDER_CURRENT,vol_order_current);            // Оставшийся (неисполненный) объём ордера
         event.SetProperty(EVENT_PROP_MAGIC_BY_ID,0);                                     // Магический номер встречной позиции
            
         //--- Параметры позиции
         event.SetProperty(EVENT_PROP_TYPE_ORDER_POSITION,type_order_first_deal);         // Тип ордера, на основании которого открыта первая сделка позиции
         event.SetProperty(EVENT_PROP_TICKET_ORDER_POSITION,ticket_order_first_deal);     // Тикет ордера, на основании которого открыта первая сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_TIME_ORDER_POSITION,order_first_deal.TimeOpen());   // Время ордера, на основании которого открыта сделка позиции (первый ордер позиции)
         event.SetProperty(EVENT_PROP_PRICE_OPEN,order_first_deal.PriceOpen());           // Цена открытия первого ордера позиции
         event.SetProperty(EVENT_PROP_PRICE_SL,order_first_deal.StopLoss());              // Цена StopLoss (Цена StopLoss ордера позиции)
         event.SetProperty(EVENT_PROP_PRICE_TP,order_first_deal.TakeProfit());            // Цена TakeProfit (Цена TakeProfit ордера позиции)
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_BEFORE,type_position_previous);        // Тип ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_BEFORE,ticket_position_previous);    // Тикет ордера позиции до смены направления
         event.SetProperty(EVENT_PROP_TYPE_ORD_POS_CURRENT,type_position_current);        // Тип ордера текущей позиции
         event.SetProperty(EVENT_PROP_TICKET_ORD_POS_CURRENT,ticket_position_current);    // Тикет ордера текущей позиции
         event.SetProperty(EVENT_PROP_VOLUME_POSITION_EXECUTED,vol_position);             // Исполненный объём позиции

         event.SetProperty(EVENT_PROP_PRICE_OPEN_BEFORE,order_first_deal.PriceOpen());    // Цена установки ордера до модификации
         event.SetProperty(EVENT_PROP_PRICE_SL_BEFORE,order_first_deal.StopLoss());       // Цена StopLoss до модификации
         event.SetProperty(EVENT_PROP_PRICE_TP_BEFORE,order_first_deal.TakeProfit());     // Цена TakeProfit до модификации
         event.SetProperty(EVENT_PROP_PRICE_EVENT_ASK,ask);                               // Цена Ask в момент события
         event.SetProperty(EVENT_PROP_PRICE_EVENT_BID,bid);                               // Цена Bid в момент события
         
         //--- Установка идентификатора графика управляющей программы и расшифровка кода события, установка типа события
         event.SetChartID(this.m_chart_id);
         event.SetTypeEvent();
         //--- Если объекта-события нет в списке - добавляем
         if(!this.IsPresentEventInList(event))
           {
            this.m_list_trade_events.InsertSort(event);
            //--- Отправляем сообщение о событии и устанавливаем значение последнего торгового события
            this.m_trade_event=event.TradeEvent();
            this.m_is_event=true;
            event.SendEvent();
            CBaseObj::EventAdd(this.m_trade_event,deal.Ticket(),deal.PriceOpen(),deal.Symbol());
           }
         //--- Если это событие уже есть в списке - удаляем новый объект-событие и выводим отладочное сообщение
         else
           {
            ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_EVENT_ALREADY_IN_LIST));
            delete event;
           }
        }
     }
#endif 
  }  
//+------------------------------------------------------------------+
//| Выбирает события из коллекции со временем                        |
//| в диапазоне от begin_time, до end_time                           |
//+------------------------------------------------------------------+
CArrayObj *CEventsCollection::GetListByTime(const datetime begin_time=0,const datetime end_time=0)
  {
   CArrayObj *list=new CArrayObj();
   if(list==NULL)
     {
      ::Print(DFUN+CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST));
      return NULL;
     }
   datetime begin=begin_time,end=(end_time==0 ? END_TIME : end_time);
   if(begin_time>end_time) begin=0;
   list.FreeMode(false);
   ListStorage.Add(list);
   //---
   this.m_event_instance.SetProperty(EVENT_PROP_TIME_EVENT,begin);
   int index_begin=this.m_list_trade_events.SearchGreatOrEqual(&m_event_instance);
   if(index_begin==WRONG_VALUE)
      return list;
   this.m_event_instance.SetProperty(EVENT_PROP_TIME_EVENT,end);
   int index_end=this.m_list_trade_events.SearchLessOrEqual(&m_event_instance);
   if(index_end==WRONG_VALUE)
      return list;
   for(int i=index_begin; i<=index_end; i++)
      list.Add(this.m_list_trade_events.At(i));
   return list;
  }
//+------------------------------------------------------------------+
//| Выбирает из списка только рыночные отложенные ордера             |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListMarketPendings(CArrayObj* list)
  {
   if(list.Type()!=COLLECTION_MARKET_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_MARKET_LIST));
      return NULL;
     }
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_PENDING,EQUAL);
   return list_orders;
  }
//+------------------------------------------------------------------+
//| Выбирает из списка только рыночные позиции                       |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListPositions(CArrayObj *list)
  {
   if(list.Type()!=COLLECTION_MARKET_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_MARKET_LIST));
      return NULL;
     }
   CArrayObj* list_positions=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   return list_positions;
  }
//+------------------------------------------------------------------+
//| Выбирает из списка только закрытые позиции                       |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListHistoryPositions(CArrayObj *list)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_HISTORY_ORDER,EQUAL);
   return list_orders;
  }
//+------------------------------------------------------------------+
//| Выбирает из списка только удалённые отложенные ордера            |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListHistoryPendings(CArrayObj* list)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_HISTORY_PENDING,EQUAL);
   return list_orders;
  }
//+------------------------------------------------------------------+
//| Выбирает из списка только сделки                                 |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListDeals(CArrayObj* list)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_deals=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_DEAL,EQUAL);
   return list_deals;
  }
//+------------------------------------------------------------------+
//|  Возвращает список всех закрывающих ордеров CloseBy из списка    |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListCloseByOrders(CArrayObj *list)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
#ifdef __MQL5__
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,ORDER_TYPE_CLOSE_BY,EQUAL);
#else 
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_POSITION_BY_ID,0,NO_EQUAL);
#endif 
   return list_orders;
  }
//+------------------------------------------------------------------+
//|  Возвращает список всех ордеров позиции по её идентификатору     |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListAllOrdersByPosID(CArrayObj* list,const ulong position_id)
  {
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_POSITION_ID,position_id,EQUAL);
   list_orders=CSelect::ByOrderProperty(list_orders,ORDER_PROP_STATUS,ORDER_STATUS_DEAL,NO_EQUAL);
   return list_orders;
  }
//+------------------------------------------------------------------+
//| Возвращает список всех сделок позиции по её идентификатору       |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListAllDealsByPosID(CArrayObj *list,const ulong position_id)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_deals=CSelect::ByOrderProperty(list,ORDER_PROP_POSITION_ID,position_id,EQUAL);
   list_deals=CSelect::ByOrderProperty(list_deals,ORDER_PROP_STATUS,ORDER_STATUS_DEAL,EQUAL);
   return list_deals;
  }
//+------------------------------------------------------------------+
//| Возвращает список всех сделок на вход в рынок (IN)               |
//| по идентификатору позиции                                        |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListAllDealsInByPosID(CArrayObj *list,const ulong position_id)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_deals=this.GetListAllDealsByPosID(list,position_id);
   list_deals=CSelect::ByOrderProperty(list_deals,ORDER_PROP_DEAL_ENTRY,DEAL_ENTRY_IN,EQUAL);
   return list_deals;
  }
//+------------------------------------------------------------------+
//| Возвращает список всех сделок на выход из рынка (OUT)            |
//| по идентификатору позиции                                        |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListAllDealsOutByPosID(CArrayObj *list,const ulong position_id)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_deals=this.GetListAllDealsByPosID(list,position_id);
   list_deals=CSelect::ByOrderProperty(list_deals,ORDER_PROP_DEAL_ENTRY,DEAL_ENTRY_OUT,EQUAL);
   return list_deals;
  }
//+------------------------------------------------------------------+
//| Возвращает список всех сделок на разворот (IN_OUT)               |
//| по идентификатору позиции                                        |
//+------------------------------------------------------------------+
CArrayObj* CEventsCollection::GetListAllDealsInOutByPosID(CArrayObj *list,const ulong position_id)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_deals=this.GetListAllDealsByPosID(list,position_id);
   list_deals=CSelect::ByOrderProperty(list_deals,ORDER_PROP_DEAL_ENTRY,DEAL_ENTRY_INOUT,EQUAL);
   return list_deals;
  }
//+------------------------------------------------------------------+
//| Возвращает суммарный объём всех сделок IN позиции                |
//| по её идентификатору                                             |
//+------------------------------------------------------------------+
double CEventsCollection::SummaryVolumeDealsInByPosID(CArrayObj *list,const ulong position_id)
  {
   double vol=0.0;
   CArrayObj* list_in=this.GetListAllDealsInByPosID(list,position_id);
   if(list_in==NULL)
      return 0;
   for(int i=0;i<list_in.Total();i++)
     {
      COrder* deal=list_in.At(i);
      if(deal==NULL)
         continue;
      vol+=deal.Volume();
     }
   return vol;
  }
//+------------------------------------------------------------------+
//| Возвращает суммарный объём всех сделок OUT позиции по её         |
//| идентификатору (учитывается участие во встречных закрытиях)      |
//+------------------------------------------------------------------+
double CEventsCollection::SummaryVolumeDealsOutByPosID(CArrayObj *list,const ulong position_id)
  {
   double vol=0.0;
   CArrayObj* list_out=this.GetListAllDealsOutByPosID(list,position_id);
   if(list_out!=NULL)
     {
      for(int i=0;i<list_out.Total();i++)
        {
         COrder* deal=list_out.At(i);
         if(deal==NULL)
            continue;
         vol+=deal.Volume();
        }
     }
   CArrayObj* list_by=this.GetListCloseByOrders(list);
   if(list_by!=NULL)
     {
      for(int i=0;i<list_by.Total();i++)
        {
         COrder* order=list_by.At(i);
         if(order==NULL)
            continue;
         if(order.PositionID()==position_id || order.PositionByID()==position_id)
           {
            vol+=order.Volume();
           }
        }
     }
   return vol;
  }
//+------------------------------------------------------------------+
//| Возвращает первый ордер из списка всех ордеров позиции           |
//+------------------------------------------------------------------+
COrder* CEventsCollection::GetFirstOrderFromList(CArrayObj* list,const ulong position_id)
  {
   CArrayObj* list_orders=this.GetListAllOrdersByPosID(list,position_id);
   if(list_orders==NULL || list_orders.Total()==0) return NULL;
   list_orders.Sort(SORT_BY_ORDER_TIME_OPEN);
   COrder* order=list_orders.At(0);
   return(order!=NULL ? order : NULL);
  }
//+------------------------------------------------------------------+
//| Возвращает последний ордер из списка всех ордеров позиции        |
//+------------------------------------------------------------------+
COrder* CEventsCollection::GetLastOrderFromList(CArrayObj* list,const ulong position_id)
  {
   CArrayObj* list_orders=this.GetListAllOrdersByPosID(list,position_id);
   if(list_orders==NULL || list_orders.Total()==0) return NULL;
   list_orders.Sort(SORT_BY_ORDER_TIME_OPEN);
   COrder* order=list_orders.At(list_orders.Total()-1);
   return(order!=NULL ? order : NULL);
  }
//+------------------------------------------------------------------+
//| Возвращает последний закрывающий ордер                           |
//| из списка всех ордеров позиции                                   |
//+------------------------------------------------------------------+
COrder* CEventsCollection::GetCloseByOrderFromList(CArrayObj *list,const ulong position_id)
  {
#ifdef __MQL5__
   CArrayObj* list_orders=this.GetListAllOrdersByPosID(list,position_id);
   list_orders=CSelect::ByOrderProperty(list_orders,ORDER_PROP_TYPE,ORDER_TYPE_CLOSE_BY,EQUAL);
   if(list_orders==NULL || list_orders.Total()==0) return NULL;
   list_orders.Sort(SORT_BY_ORDER_TIME_OPEN);
#else 
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_POSITION_BY_ID,position_id,EQUAL);
   if(list_orders==NULL || list_orders.Total()==0) return NULL;
   list_orders.Sort(SORT_BY_ORDER_TIME_CLOSE);
#endif 
   COrder* order=list_orders.At(list_orders.Total()-1);
   return(order!=NULL ? order : NULL);
  }
//+------------------------------------------------------------------+
//| Возвращает ордер по тикету                                       |
//+------------------------------------------------------------------+
COrder* CEventsCollection::GetHistoryOrderByTicket(CArrayObj *list,const ulong order_ticket)
  {
   if(list.Type()!=COLLECTION_HISTORY_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_HISTORY_LIST));
      return NULL;
     }
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_DEAL,NO_EQUAL);
   list_orders=CSelect::ByOrderProperty(list_orders,ORDER_PROP_TICKET,order_ticket,EQUAL);
   if(list_orders==NULL || list_orders.Total()==0) return NULL;
   COrder* order=list_orders.At(0);
   return(order!=NULL ? order : NULL);
  }
//+------------------------------------------------------------------+
//| Возвращает позицию по идентификатору                             |
//+------------------------------------------------------------------+
COrder* CEventsCollection::GetPositionByID(CArrayObj *list,const ulong position_id)
  {
   if(list.Type()!=COLLECTION_MARKET_ID)
     {
      Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NOT_MARKET_LIST));
      return NULL;
     }
   CArrayObj* list_orders=CSelect::ByOrderProperty(list,ORDER_PROP_STATUS,ORDER_STATUS_MARKET_POSITION,EQUAL);
   list_orders=CSelect::ByOrderProperty(list_orders,ORDER_PROP_POSITION_ID,position_id,EQUAL);
   if(list_orders==NULL || list_orders.Total()==0) return NULL;
   COrder* order=list_orders.At(0);
   return(order!=NULL ? order : NULL);
  }
//+------------------------------------------------------------------+
//| Возвращает контрольный ордер по тикету позиции (MQL4)            |
//+------------------------------------------------------------------+
COrderControl* CEventsCollection::GetOrderControlByTicket(CArrayObj *list,const ulong ticket)
  {
   if(list==NULL)
      return NULL;
   int total=list.Total();
   for(int i=0;i<total;i++)
     {
      COrderControl* ctrl=list.At(i);
      if(ctrl==NULL)
         continue;
      if(ctrl.Ticket()==ticket)
         return ctrl;
     }
   return NULL;
  }
//+------------------------------------------------------------------+
//| Возвращает тип открывающего ордера по тикету позиции (MQL4)      |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE CEventsCollection::GetTypeFirst(CArrayObj* list,const ulong ticket)
  {
   if(list==NULL)
      return WRONG_VALUE;
   COrderControl* ctrl=this.GetOrderControlByTicket(list,ticket);
   if(ctrl==NULL)
      return WRONG_VALUE;
   return (ENUM_ORDER_TYPE)ctrl.TypeOrder();
  }
//+------------------------------------------------------------------+
//| Возвращает флаг наличия объекта-события в списке событий         |
//+------------------------------------------------------------------+
bool CEventsCollection::IsPresentEventInList(CEvent *compared_event)
  {
   int total=this.m_list_trade_events.Total();
   if(total==0)
      return false;
   for(int i=total-1;i>=0;i--)
     {
      CEvent* event=this.m_list_trade_events.At(i);
      if(event==NULL)
         continue;
      if(event.IsEqual(compared_event))
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+
