//+------------------------------------------------------------------+
//|                                            SymbolsCollection.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 <Arrays\ArrayString.mqh>
#include "ListObj.mqh"
#include "..\Services\Select.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "..\Objects\Symbols\SymbolFX.mqh"
#include "..\Objects\Symbols\SymbolFXMajor.mqh"
#include "..\Objects\Symbols\SymbolFXMinor.mqh"
#include "..\Objects\Symbols\SymbolFXExotic.mqh"
#include "..\Objects\Symbols\SymbolFXRub.mqh"
#include "..\Objects\Symbols\SymbolMetall.mqh"
#include "..\Objects\Symbols\SymbolIndex.mqh"
#include "..\Objects\Symbols\SymbolIndicative.mqh"
#include "..\Objects\Symbols\SymbolCrypto.mqh"
#include "..\Objects\Symbols\SymbolCommodity.mqh"
#include "..\Objects\Symbols\SymbolExchange.mqh"
#include "..\Objects\Symbols\SymbolFutures.mqh"
#include "..\Objects\Symbols\SymbolCFD.mqh"
#include "..\Objects\Symbols\SymbolStocks.mqh"
#include "..\Objects\Symbols\SymbolBonds.mqh"
#include "..\Objects\Symbols\SymbolOption.mqh"
#include "..\Objects\Symbols\SymbolCollateral.mqh"
#include "..\Objects\Symbols\SymbolCustom.mqh"
#include "..\Objects\Symbols\SymbolCommon.mqh"
//+------------------------------------------------------------------+
//| Коллекция символов                                               |
//+------------------------------------------------------------------+
class CSymbolsCollection : public CBaseObj
  {
private:
   CListObj          m_list_all_symbols;                          // Список всех объектов-символов
   CArrayString      m_list_names;                                // Контрольный список имён символов
   ENUM_SYMBOLS_MODE m_mode_list;                                 // Режим работы со списками символов
   int               m_last_event;                                // Последнее событие
   string            m_array_symbols[];                           // Массив используемых символов, передаваемых из программы
   int               m_delta_symbol;                              // Разница в количестве символов по сравнению с прошлой проверкой
   int               m_total_symbols;                             // Количество символов в окне "Обзор рынка"
   int               m_total_symbol_prev;                         // Количество символов в окне "Обзор рынка" на прошлой проверке
//--- Сохраняет имена используемых символов из "Обзора рынка"
   void              CopySymbolsNames(void);
//--- Возвращает флаг наличия объекта-символа по его имени (1) в списке всех символов, (2) в окне "Обзор рынка", (3) в контрольном списке
   bool              IsPresentSymbolInList(const string symbol_name);
   bool              IsPresentSymbolInMW(const string symbol_name);
   bool              IsPresentSymbolInControlList(const string symbol_name);
//--- Создаёт объект-символ и помещает его в список
   bool              CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index);
//--- Возвращает (1) тип используемого списка символов (Обзор рынка/Сервер),
//--- (2) количество видимых символов, (3) индекс символа в окне "Обзор рынка"
   ENUM_SYMBOLS_MODE TypeSymbolsList(const string &symbol_used_array[]);
   int               SymbolsTotalVisible(void)                    const;
   int               SymbolIndexInMW(const string name)           const;
   
//--- Определяет по имени и возвращает принадлежность символа к группе
   ENUM_SYMBOL_STATUS SymbolStatus(const string symbol_name)      const;
//--- Возвращает принадлежность символа к категории по пользовательским критериям
   ENUM_SYMBOL_STATUS StatusByCustomPredefined(const string symbol_name)  const;
//--- Возвращает принадлежность символа к категориям по расчёту залоговых средств
   ENUM_SYMBOL_STATUS StatusByCalcMode(const string symbol_name)  const;
//--- Возвращает принадлежность символа к предопределённым (1) мажорам, (2) минорам, (3) экзотикам, (4) рублёвым,
//--- (5) индикативам, (6) металлам, (7) товарам, (8) индексам, (9) криптовалюте, (10) опционам
   bool              IsPredefinedFXMajor(const string name)       const;
   bool              IsPredefinedFXMinor(const string name)       const;
   bool              IsPredefinedFXExotic(const string name)      const;
   bool              IsPredefinedFXRUB(const string name)         const;
   bool              IsPredefinedIndicative(const string name)    const;
   bool              IsPredefinedMetall(const string name)        const;
   bool              IsPredefinedCommodity(const string name)     const;
   bool              IsPredefinedIndex(const string name)         const;
   bool              IsPredefinedCrypto(const string name)        const;
   bool              IsPredefinedOption(const string name)        const;

public:
//--- Возвращает себя
   CSymbolsCollection *GetObject(void)                                                                      { return &this;   }
//--- Возвращает полный список-коллекцию "как есть"
   CArrayObj        *GetList(void)                                                                          { return &this.m_list_all_symbols;                                      }
//--- Возвращает список по выбранному (1) целочисленному, (2) вещественному и (3) строковому свойству, удовлетворяющему сравниваемому критерию
   CArrayObj        *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)    { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL)   { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); }
   CArrayObj        *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL)   { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); }
//--- Возвращает из списка по имени (1) объект-символ, (2) индекс объекта-символа
   CSymbol          *GetSymbolObjByName(const string name);
   int               GetIndexObjByName(const string name);
//--- Возвращает количество новых символов в окне "Обзор рынка"
   int               NewSymbols(void)    const                                                              { return this.m_delta_symbol;                                           }
//--- Возвращает (1) режим работы со списками символов, (2) флаг события и (3) событие одного из символов коллекции
   ENUM_SYMBOLS_MODE ModeSymbolsList(void)                        const                                     { return this.m_mode_list;                                              }
   bool              IsEvent(void)                                const                                     { return this.m_is_event;                                               }
   int               GetLastEventsCode(void)                      const                                     { return this.m_event_code;                                             }
   int               GetLastEvent(void)                           const                                     { return this.m_last_event;                                             }
//--- Возвращает количество символов в коллекции
   int               GetSymbolsCollectionTotal(void)              const                                     { return this.m_list_all_symbols.Total();                               }

//--- Конструктор
                     CSymbolsCollection();
   
//--- (1) Устанавливает список используемых символов, (2) создание списка символов (Обзор рынка или полный список)
   bool              SetUsedSymbols(const string &symbol_used_array[]);
   bool              CreateSymbolsList(const bool flag);
//--- Обновляет (1) все, (2) котировочные данные символов коллекции
   virtual void      Refresh(void);
   void              RefreshRates(void);
//--- Работа с событиями (1) списка символов коллекции, (2) окна обзора рынка
   void              RefreshAndEventsControl(void);
   void              MarketWatchEventsControl(const bool send_events=true);
//--- Возвращает описание (1) события окна "Обзор рынка", (2) режима работы с символами
   string            EventMWDescription(const ENUM_MW_EVENT event);
   string            ModeSymbolsListDescription(void);
  };
//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CSymbolsCollection::CSymbolsCollection(void) : m_total_symbol_prev(0),
                                               m_delta_symbol(0),
                                               m_mode_list(SYMBOLS_MODE_CURRENT)
  {
   this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW);
   this.m_list_all_symbols.Clear();
   this.m_list_all_symbols.Type(COLLECTION_SYMBOLS_ID);
   this.m_list_names.Clear();
  }
//+------------------------------------------------------------------+
//| Обновляет все данные символов коллекции                          |
//+------------------------------------------------------------------+
void CSymbolsCollection::Refresh(void)
  {
   int total=this.m_list_all_symbols.Total();
   if(total==0)
      return;
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      symbol.Refresh();
     }
  }
//+------------------------------------------------------------------+
//| Обновляет котировочные данные символов коллекции                 |
//+------------------------------------------------------------------+
void CSymbolsCollection::RefreshRates(void)
  {
   int total=this.m_list_all_symbols.Total();
   if(total==0)
      return;
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      symbol.RefreshRates();
     }
  }
//+------------------------------------------------------------------+
//| Работа с событиями окна обзора рынка                             |
//+------------------------------------------------------------------+
void CSymbolsCollection::MarketWatchEventsControl(const bool send_events=true)
  {
   ::ResetLastError();
//--- Если текущие цены не получены - уходим
   if(!::SymbolInfoTick(::Symbol(),this.m_tick))
     {
      this.m_global_error=::GetLastError();
      return;
     }
   uchar array[];
   int sum=0;
   this.m_hash_sum=0;
//--- Расчёт хэш-суммы всех видимых символов в окне "Обзор рынка"
   this.m_total_symbols=this.SymbolsTotalVisible();
   //--- В цикле по всем символам окна "Обзор рынка"
   int total_symbols=::SymbolsTotal(true);
   for(int i=0;i<total_symbols;i++)
     {
      //--- получаем имя символа по индексу
      string name=::SymbolName(i,true);
      //--- если невидимый - пропускаем
      if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE))
         continue;
      //--- записываем в uchar-массив коды символов (букв) названия символа
      ::StringToCharArray(name,array);
      //--- в цикле по получившемуся массиву складываем значения всех ячеек массива, тем самым создавая код символа
      for(int j=::ArraySize(array)-1;j>WRONG_VALUE;j--)
         sum+=array[j];
      //--- добавляем к хэш-сумме код символа и индекс цикла, указывающий на индекс символа в списке обзора рынка
      m_hash_sum+=i+sum;
     }
//--- Если запрет отправки событий - создаём список-коллекцию и выходим с сохранением текущей хэш-суммы как прошлой
   if(!send_events)
     {
      //--- Очищаем список
      this.m_list_all_symbols.Clear();
      //--- Создаём список-коллекцию
      this.CreateSymbolsList(true);
      //--- Создаём слепок окна обзора рынка
      this.CopySymbolsNames();
      //--- сохраняем текущую хэш-сумму как прошлую
      this.m_hash_sum_prev=this.m_hash_sum;
      //--- сохраняем текущее количество видимых символов как прошлое
      this.m_total_symbol_prev=this.m_total_symbols;
      return;
     }
   
//--- Если хэш-сумма символов в окне "Обзор рынка" изменилась
   if(this.m_hash_sum!=this.m_hash_sum_prev)
     {
      //--- Определяем событие окна "Обзор рынка"
      this.m_delta_symbol=this.m_total_symbols-this.m_total_symbol_prev;
      ushort event_id=
        (ushort(
         this.m_total_symbols>this.m_total_symbol_prev ? MARKET_WATCH_EVENT_SYMBOL_ADD :
         this.m_total_symbols<this.m_total_symbol_prev ? MARKET_WATCH_EVENT_SYMBOL_DEL :
         MARKET_WATCH_EVENT_SYMBOL_SORT)
        );
      //--- Добавление символа в окно "Обзор рынка"
      if(event_id==MARKET_WATCH_EVENT_SYMBOL_ADD)
        {
         string name="";
         //--- В цикле по всем символам окна "Обзор рынка"
         int total=::SymbolsTotal(true), index=WRONG_VALUE;
         for(int i=0;i<total;i++)
           {
            //--- получаем имя символа и проверяем его "видимость", если невидимый - пропускаем
            name=::SymbolName(i,true);
            if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE))
               continue;
            //--- Если символа ещё нет в списке символов коллекции
            if(!this.IsPresentSymbolInList(name))
              {
               //--- очищаем список-коллекцию
               this.m_list_all_symbols.Clear();
               //--- пересоздаём список-коллекцию
               this.CreateSymbolsList(true);
               //--- создаём слепок коллекции символов
               this.CopySymbolsNames();
               //--- получаем индекс нового символа в окне "Обзор рынка"
               index=this.GetIndexObjByName(name);
               //--- Если событие "Добавление нового символа" успешно добавлено в список событий 
               if(this.EventAdd(event_id,this.TickTime(),index,name))
                 {
                  //--- отправляем событие на график:
                  //--- long-значение = время события в милисекундах, double-значение = индекс символа, string-значение = имя добавленного символа
                  ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,name);
                 }
              }
           }
         //--- Сохраняем новое количество видимых символов в окне обзора рынка
         this.m_total_symbols=this.SymbolsTotalVisible();
        }
      //--- Удаление символа из окна "Обзор рынка"
      else if(event_id==MARKET_WATCH_EVENT_SYMBOL_DEL)
        {
         //--- очищаем список-коллекцию 
         this.m_list_all_symbols.Clear();
         //--- пересоздаём список-коллекцию
         this.CreateSymbolsList(true);
         //--- В цикле по слепку окна обзора рынка
         int total=this.m_list_names.Total();
         for(int i=0; i<total;i++)
           {
            //--- получаем имя символа 
            string name=this.m_list_names.At(i);
            if(name==NULL)
               continue;
            //--- если симвоа с таким именем не существует в списке символов коллекции
            if(!this.IsPresentSymbolInList(name))
              {
               //--- Если событие "Удаление символа" успешно добавлено в список событий
               if(this.EventAdd(event_id,this.TickTime(),WRONG_VALUE,name))
                 {
                  //--- отправляем событие на график:
                  //--- long-значение = время события в милисекундах, double-значение = -1 для отсутствующего символа, string-значение = имя удалённого символа
                  ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),WRONG_VALUE,name);
                 }
              }
           }
         //--- Пересоздаём слепок обзора рынка
         this.CopySymbolsNames();
         //--- Сохраняем новое количество видимых символов в окне обзора рынка
         this.m_total_symbols=this.SymbolsTotalVisible();
        }
      //--- Сортировка символов в окне "Обзор рынка"
      else if(event_id==MARKET_WATCH_EVENT_SYMBOL_SORT)
        {
         //--- очищаем список-коллекцию 
         this.m_list_all_symbols.Clear();
         //--- устанавливаем сортировку списка коллекции как сортировку по индексу
         this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW);
         //--- пересоздаём список-коллекцию
         this.CreateSymbolsList(true);
         //--- получаем индекс текущего символа в окне "Обзор рынка"
         int index=this.GetIndexObjByName(Symbol());
         //--- отправляем событие на график:
         //--- long-значение = время события в милисекундах, double-значение = индекс текущего символа, string-значение = имя текущего символа
         ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,::Symbol());
        }
      //--- сохраняем текущее количество видимых символов как прошлое
      this.m_total_symbol_prev=this.m_total_symbols;
      //--- сохраняем текущую хэш-сумму как прошлую
      this.m_hash_sum_prev=this.m_hash_sum;
     }
  }
//+------------------------------------------------------------------+
//| Работа с событиями списка символов коллекции                     |
//+------------------------------------------------------------------+
void CSymbolsCollection::RefreshAndEventsControl(void)
  {
   this.m_is_event=false;
   this.m_list_events.Clear();
   this.m_list_events.Sort();
   //--- Полное обновление всех символов коллекции
   int total=this.m_list_all_symbols.Total();
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      symbol.Refresh();
      if(!symbol.IsEvent())
         continue;
      CArrayObj *list=symbol.GetListEvents();
      if(list==NULL)
         continue;
      this.m_is_event=true;
      this.m_event_code=symbol.GetEventCode();
      int n=list.Total();
      for(int j=0; j<n; j++)
        {
         CEventBaseObj *event=list.At(j);
         if(event==NULL)
            continue;
         ushort event_id=event.ID();
         this.m_last_event=event_id;
         if(this.EventAdd((ushort)event.ID(),event.LParam(),event.DParam(),event.SParam()))
           {
            ::EventChartCustom(this.m_chart_id,(ushort)event_id,event.LParam(),event.DParam(),event.SParam());
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| Создаёт объект-символ и помещает его в список                    |
//+------------------------------------------------------------------+
bool CSymbolsCollection::CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index)
  {
   if(this.IsPresentSymbolInList(name))
     {
      return true;
     }
   if(#ifdef __MQL5__ !::SymbolInfoInteger(name,SYMBOL_EXIST) #else !Exist(name) #endif )
     {
      string t1=CMessage::Text(MSG_LIB_SYS_INPUT_ERROR_NO_SYMBOL);
      string t2=CMessage::Text(MSG_LIB_TEXT_SYMBOL_ON_SERVER);
      ::Print(DFUN,t1,name,t2);
      this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL;
      return false;
     }
   CSymbol *symbol=NULL;
   switch(symbol_status)
     {
      case SYMBOL_STATUS_FX         :  symbol=new CSymbolFX(name,index);         break;   // Форекс символ
      case SYMBOL_STATUS_FX_MAJOR   :  symbol=new CSymbolFXMajor(name,index);    break;   // Форекс символ-мажор
      case SYMBOL_STATUS_FX_MINOR   :  symbol=new CSymbolFXMinor(name,index);    break;   // Форекс символ-минор
      case SYMBOL_STATUS_FX_EXOTIC  :  symbol=new CSymbolFXExotic(name,index);   break;   // Форекс символ-экзотик
      case SYMBOL_STATUS_FX_RUB     :  symbol=new CSymbolFXRub(name,index);      break;   // Форекс символ/рубль
      case SYMBOL_STATUS_METAL      :  symbol=new CSymbolMetall(name,index);     break;   // Металл
      case SYMBOL_STATUS_INDEX      :  symbol=new CSymbolIndex(name,index);      break;   // Индекс
      case SYMBOL_STATUS_INDICATIVE :  symbol=new CSymbolIndicative(name,index); break;   // Индикатив
      case SYMBOL_STATUS_CRYPTO     :  symbol=new CSymbolCrypto(name,index);     break;   // Криптовалютный символ
      case SYMBOL_STATUS_COMMODITY  :  symbol=new CSymbolCommodity(name,index);  break;   // Товарный символ
      case SYMBOL_STATUS_EXCHANGE   :  symbol=new CSymbolExchange(name,index);   break;   // Биржевой символ
      case SYMBOL_STATUS_FUTURES    :  symbol=new CSymbolFutures(name,index);    break;   // Фьючерс
      case SYMBOL_STATUS_CFD        :  symbol=new CSymbolCFD(name,index);        break;   // Контракт на разницу
      case SYMBOL_STATUS_STOCKS     :  symbol=new CSymbolStocks(name,index);     break;   // Ценная бумага
      case SYMBOL_STATUS_BONDS      :  symbol=new CSymbolBonds(name,index);      break;   // Облигация
      case SYMBOL_STATUS_OPTION     :  symbol=new CSymbolOption(name,index);     break;   // Опцион
      case SYMBOL_STATUS_COLLATERAL :  symbol=new CSymbolCollateral(name,index); break;   // Неторгуемый актив
      case SYMBOL_STATUS_CUSTOM     :  symbol=new CSymbolCustom(name,index);     break;   // Пользовательский символ
      default                       :  symbol=new CSymbolCommon(name,index);     break;   // Остальное
     }
   if(symbol==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_SYM_OBJ),name);
      return false;
     }
   if(!this.m_list_all_symbols.Add(symbol))
     {
      string t1=CMessage::Text(MSG_LIB_SYS_FAILED_ADD_SYM_OBJ);
      string t2=CMessage::Text(MSG_LIB_TEXT_SYMBOL_TO_LIST);
      ::Print(DFUN,t1,name,t2);
      delete symbol;
      return false;
     }
   return true;
  }
//+------------------------------------------------------------------+
//| Возвращает флаг наличия объекта-символа                          |
//| по его имени в списке всех символов                              |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPresentSymbolInList(const string symbol_name)
  {
   CArrayObj *list=dynamic_cast<CListObj*>(&this.m_list_all_symbols);
   list.Sort(SORT_BY_SYMBOL_NAME);
   list=CSelect::BySymbolProperty(list,SYMBOL_PROP_NAME,symbol_name,EQUAL);
   return(list==NULL || list.Total()==0 ? false : true);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг наличия видимого объекта-символа                 |
//| по его имени в окне "Обзор рынка"                                |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPresentSymbolInMW(const string symbol_name)
  {
   int total=SymbolsTotal(true);
   for(int i=0;i<total;i++)
     {
      string name=::SymbolName(i,true);
      if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE))
         continue;
      if(name==symbol_name)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает флаг наличия объекта-символа в контрольном списке     |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPresentSymbolInControlList(const string symbol_name)
  {
   int total=this.m_list_names.Total();
   for(int i=0;i<total;i++)
     {
      string name=this.m_list_names.At(i);
      if(name==NULL)
         continue;
      if(name==symbol_name)
         return true;
     }
   return false;
  }
//+------------------------------------------------------------------+
//| Устанавливает список используемых символов                       |
//+------------------------------------------------------------------+
bool CSymbolsCollection::SetUsedSymbols(const string &symbol_used_array[])
  {
   ::ArrayCopy(this.m_array_symbols,symbol_used_array);
   this.m_mode_list=this.TypeSymbolsList(this.m_array_symbols);
   this.m_list_all_symbols.Clear();
   this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW);
   //--- Используется только текущий символ
   if(this.m_mode_list==SYMBOLS_MODE_CURRENT)
     {
      string name=::Symbol();
      ENUM_SYMBOL_STATUS status=this.SymbolStatus(name);
      return this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name));
     }
   else
     {
      bool res=true;
      //--- Используется предопределённый список символов
      if(this.m_mode_list==SYMBOLS_MODE_DEFINES)
        {
         int total=::ArraySize(this.m_array_symbols);
         for(int i=0;i<total;i++)
           {
            string name=this.m_array_symbols[i];
            ENUM_SYMBOL_STATUS status=this.SymbolStatus(name);
            bool add=this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name));
            res &=add;
            if(!add) 
               continue;
           }
         return res;
        }
      //--- Используется полный список символов сервера
      else if(this.m_mode_list==SYMBOLS_MODE_ALL)
        {
         return this.CreateSymbolsList(false);
        }
      //--- Используется список символов из окна "Обзор рынка"
      else if(this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH)
        {
         this.MarketWatchEventsControl(false);
         return true;
        }
     }
   return false;
  }
//+------------------------------------------------------------------+
//| Создание списка символов (Обзор рынка или полный список)         |
//+------------------------------------------------------------------+
bool CSymbolsCollection::CreateSymbolsList(const bool flag)
  {
   bool res=true;
   int total=::SymbolsTotal(flag);
   for(int i=0;i<total && i<SYMBOLS_COMMON_TOTAL;i++)
     {
      string name=::SymbolName(i,flag);
      if(flag && !::SymbolInfoInteger(name,SYMBOL_VISIBLE))
         continue;
      ENUM_SYMBOL_STATUS status=this.SymbolStatus(name);
      bool add=this.CreateNewSymbol(status,name,i);
      res &=add;
      if(!add) 
         continue;
     }
   return res;
  }
//+------------------------------------------------------------------+
//| Сохраняет имена используемых символов из "Обзора рынка"          |
//+------------------------------------------------------------------+
void CSymbolsCollection::CopySymbolsNames(void)
  {
   this.m_list_names.Clear();
   int total=this.m_list_all_symbols.Total();
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      this.m_list_names.Add(symbol.Name());
     }
  }
//+------------------------------------------------------------------+
//|Возвращает тип используемого списка символов (Обзор рынка/Сервер) |
//+------------------------------------------------------------------+
ENUM_SYMBOLS_MODE CSymbolsCollection::TypeSymbolsList(const string &symbol_used_array[])
  {
   int total=::ArraySize(symbol_used_array);
   if(total<1)
      return SYMBOLS_MODE_CURRENT;
   string type=::StringSubstr(symbol_used_array[0],13);
   return
     (
      type=="MARKET_WATCH" ? SYMBOLS_MODE_MARKET_WATCH   :
      type=="ALL"          ? SYMBOLS_MODE_ALL            :
      (total==1 && symbol_used_array[0]==::Symbol() ? SYMBOLS_MODE_CURRENT : SYMBOLS_MODE_DEFINES)
     );
  }
//+------------------------------------------------------------------+
//| Возвращает количество видимых символов в окне "Обзор рынка"      |
//+------------------------------------------------------------------+
int CSymbolsCollection::SymbolsTotalVisible(void) const
  {
   int total=::SymbolsTotal(true),n=0;
   for(int i=0;i<total;i++)
     {
      if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE))
         continue;
      n++;
     }
   return n;
  }
//+------------------------------------------------------------------+
//| Возвращает индекс символа в окне "Обзор рынка"                   |
//+------------------------------------------------------------------+
int CSymbolsCollection::SymbolIndexInMW(const string name) const
  {
   int total=::SymbolsTotal(true);
   for(int i=0;i<total;i++)
     {
      if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE))
         continue;
      if(SymbolName(i,true)==name)
         return i;
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+
//| Определяет по имени и возвращает принадлежность символа к группе |
//+------------------------------------------------------------------+
ENUM_SYMBOL_STATUS CSymbolsCollection::SymbolStatus(const string symbol_name) const
  {
   ENUM_SYMBOL_STATUS status=this.StatusByCustomPredefined(symbol_name);
   return(status==SYMBOL_STATUS_COMMON ? this.StatusByCalcMode(symbol_name) : status);
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к мажорам                      |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedFXMajor(const string name) const
  {
   int total=::ArraySize(DataSymbolsFXMajors);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsFXMajors[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к минорам                      |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedFXMinor(const string name) const
  {
   int total=::ArraySize(DataSymbolsFXMinors);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsFXMinors[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к экзотикам                    |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedFXExotic(const string name) const
  {
   int total=::ArraySize(DataSymbolsFXExotics);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsFXExotics[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к рублёвым                     |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedFXRUB(const string name) const
  {
   int total=::ArraySize(DataSymbolsFXRub);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsFXRub[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к индикативам                  |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedIndicative(const string name) const
  {
   int total=::ArraySize(DataSymbolsFXIndicatives);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsFXIndicatives[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к металлам                     |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedMetall(const string name) const
  {
   int total=::ArraySize(DataSymbolsMetalls);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsMetalls[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к товарам                      |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedCommodity(const string name) const
  {
   int total=::ArraySize(DataSymbolsCommodities);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsCommodities[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к индексам                     |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedIndex(const string name) const
  {
   int total=::ArraySize(DataSymbolsIndexes);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsIndexes[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к криптовалюте                 |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedCrypto(const string name) const
  {
   int total=::ArraySize(DataSymbolsCrypto);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsCrypto[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает принадлежность символа к опционам                     |
//+------------------------------------------------------------------+
bool CSymbolsCollection::IsPredefinedOption(const string name) const
  {
   int total=::ArraySize(DataSymbolsOptions);
   for(int i=0;i<total;i++)
      if(name==DataSymbolsOptions[i])
         return true;
   return false;
  }
//+------------------------------------------------------------------+
//| Возвращает категорию по пользовательским критериям               |
//+------------------------------------------------------------------+
ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCustomPredefined(const string symbol_name) const
  {
   return
     (
      this.IsPredefinedFXMajor(symbol_name)     ?  SYMBOL_STATUS_FX_MAJOR     :
      this.IsPredefinedFXMinor(symbol_name)     ?  SYMBOL_STATUS_FX_MINOR     :
      this.IsPredefinedFXExotic(symbol_name)    ?  SYMBOL_STATUS_FX_EXOTIC    :
      this.IsPredefinedFXRUB(symbol_name)       ?  SYMBOL_STATUS_FX_RUB       :
      this.IsPredefinedOption(symbol_name)      ?  SYMBOL_STATUS_OPTION       :
      this.IsPredefinedCommodity(symbol_name)   ?  SYMBOL_STATUS_COMMODITY    :
      this.IsPredefinedCrypto(symbol_name)      ?  SYMBOL_STATUS_CRYPTO       :
      this.IsPredefinedMetall(symbol_name)      ?  SYMBOL_STATUS_METAL        :
      this.IsPredefinedIndex(symbol_name)       ?  SYMBOL_STATUS_INDEX        :
      this.IsPredefinedIndicative(symbol_name)  ?  SYMBOL_STATUS_INDICATIVE   :
      SYMBOL_STATUS_COMMON
     );
  }  
//+------------------------------------------------------------------+
//|Возвращает принадлежность к категории по расчёту залоговых средств|
//+------------------------------------------------------------------+
ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCalcMode(const string symbol_name) const
  {
   ENUM_SYMBOL_CALC_MODE calc_mode=(ENUM_SYMBOL_CALC_MODE)::SymbolInfoInteger(symbol_name,SYMBOL_TRADE_CALC_MODE);
   return
     (
      calc_mode==SYMBOL_CALC_MODE_EXCH_OPTIONS_MARGIN                                                                               ?  SYMBOL_STATUS_OPTION       :
      calc_mode==SYMBOL_CALC_MODE_SERV_COLLATERAL                                                                                   ?  SYMBOL_STATUS_COLLATERAL   :
      calc_mode==SYMBOL_CALC_MODE_FUTURES                                                                                           ?  SYMBOL_STATUS_FUTURES      :
      calc_mode==SYMBOL_CALC_MODE_CFD           || calc_mode==SYMBOL_CALC_MODE_CFDINDEX || calc_mode==SYMBOL_CALC_MODE_CFDLEVERAGE  ?  SYMBOL_STATUS_CFD          :
      calc_mode==SYMBOL_CALC_MODE_FOREX         || calc_mode==SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE                                    ?  SYMBOL_STATUS_FX           :
      calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS   || calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX                                     ?  SYMBOL_STATUS_STOCKS       :
      calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS    || calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS_MOEX                                      ?  SYMBOL_STATUS_BONDS        :
      calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES  || calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS                                   ?  SYMBOL_STATUS_FUTURES      :
      SYMBOL_STATUS_COMMON
     );
  }
//+------------------------------------------------------------------+
//| Возвращает объект-символ из списка по имени                      |
//+------------------------------------------------------------------+
CSymbol *CSymbolsCollection::GetSymbolObjByName(const string name)
  {
   CArrayObj *list=this.GetList(SYMBOL_PROP_NAME,name,EQUAL);
   if(list==NULL || list.Total()==0)
      return NULL;
   CSymbol *symbol=list.At(0);
   return(symbol!=NULL ? symbol : NULL);
  }
//+------------------------------------------------------------------+
//| Возвращает из списка по имени индекс объекта-символа             |
//+------------------------------------------------------------------+
int CSymbolsCollection::GetIndexObjByName(const string name)
  {
   int total=this.m_list_all_symbols.Total();
   for(int i=0;i<total;i++)
     {
      CSymbol *symbol=this.m_list_all_symbols.At(i);
      if(symbol==NULL)
         continue;
      if(symbol.Name()==name)
         return i;
     }
   return WRONG_VALUE;
  }
//+------------------------------------------------------------------+
//| Возвращает описание события окна "Обзор рынка"                   |
//+------------------------------------------------------------------+
string CSymbolsCollection::EventMWDescription(const ENUM_MW_EVENT event)
  {
   return
     (
      event==MARKET_WATCH_EVENT_SYMBOL_ADD   ?  CMessage::Text(MSG_SYM_EVENT_SYMBOL_ADD)  :
      event==MARKET_WATCH_EVENT_SYMBOL_DEL   ?  CMessage::Text(MSG_SYM_EVENT_SYMBOL_DEL)  :
      event==MARKET_WATCH_EVENT_SYMBOL_SORT  ?  CMessage::Text(MSG_SYM_EVENT_SYMBOL_SORT) :
      EnumToString(event)
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание режима работы с символами                    |
//+------------------------------------------------------------------+
string CSymbolsCollection::ModeSymbolsListDescription(void)
  {
   return
     (
      this.m_mode_list==SYMBOLS_MODE_CURRENT       ? CMessage::Text(MSG_SYM_SYMBOLS_MODE_CURRENT)        : 
      this.m_mode_list==SYMBOLS_MODE_DEFINES       ? CMessage::Text(MSG_SYM_SYMBOLS_MODE_DEFINES)        :
      this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH  ? CMessage::Text(MSG_SYM_SYMBOLS_MODE_MARKET_WATCH)   :
      CMessage::Text(MSG_SYM_SYMBOLS_MODE_ALL)
     );
  }
//+------------------------------------------------------------------+

