← К каталогу
Исходный код · ID 3518

copier.mqh

Вы автор или правообладатель?

Сообщите нам, если считаете, что материал размещён без разрешения.

Краткий обзор

О программе

Данный файл является библиотекой исходного кода для MetaTrader 4 (MQL4) и предназначен для организации обмена торговыми данными между счетами через файл. Библиотека содержит набор классов, которые описывают отдельные позиции и ордера, таблицу соответствия имён инструментов, механизм чтения и записи файла обмена, а также управление группами ордеров, объединённых общим магическим номером.

Основу составляют классы CSymbolData, CCrossTableItem, CCrossTable, CFileData и CGroupOrders. Класс CSymbolData хранит сведения об одной позиции или ордере и умеет загружать их из строки файла. Класс CCrossTable отвечает за список доступных инструментов и сопоставление имён между счетами. Класс CFileData выполняет чтение и запись файла обмена, а также сбор статистики по счёту и инструментам. Класс CGroupOrders управляет группой ордеров с общим магическим номером, включая открытие, закрытие, изменение защитных уровней и дробление объёма.

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

Состав библиотеки

Классов: 5 · методов: 56 · конструкторов: 2 · деструкторов: 1 · отдельных функций: 1

Классы
Класс class CSymbolData

Класс-контейнер, хранящий сведения об отдельной позиции или ордере: тикеты на стороне источника и приёмника, символы, тип, объём, цены открытия и закрытия, стоп-лосс, тейк-профит, время, магический номер, комментарий и состояние.

Класс class CCrossTableItem

Класс-элемент таблицы соответствия символов, хранящий пару связанных имён инструментов.

Класс class CCrossTable

Класс таблицы соответствия символов, загружаемой из файла и используемой для сопоставления имён инструментов между счетами.

Класс class CFileData

Класс, отвечающий за обмен данными между счетами через файл: хранит сведения о счёте, список инструментов и массив записей о позициях и ордерах.

Класс class CGroupOrders

Класс управления группой ордеров, объединённых общим магическим номером, с поддержкой дробления объёма.

Функции
Функция void LOG(string x)

Выводит сообщение в журнал при включённой отладке.

Методы и конструкторы
Метод · CSymbolData void Reset()

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

Конструктор · CSymbolData CSymbolData()

Конструктор по умолчанию, создающий пустой объект с обнулёнными полями.

Метод · CSymbolData void operator=(const int nil)

Оператор присваивания, выполняющий сброс объекта к пустому состоянию.

Метод · CSymbolData void operator=(const CSymbolData &data)

Оператор присваивания, копирующий все поля из другого объекта того же класса.

Метод · CSymbolData bool Load(long laccount,bool master_ishedge,bool ishedge,string &sdata[],long ltime_offset)

Заполняет объект данными из массива строк, полученных из файла обмена, с учётом типа счёта и смещения времени; возвращает признак успешной загрузки.

Метод · CSymbolData long GetMagic(long iaccount)

Возвращает магический номер, связанный с данной записью.

Метод · CSymbolData void Print()

Выводит в журнал отладочную информацию о позиции или ордере.

Метод · CCrossTableItem void Print()

Выводит в журнал пару символов, хранящихся в элементе таблицы соответствия.

Метод · CCrossTable int GetAllTradeSymbols(bool bremove)

Формирует список доступных для торговли инструментов из обзора рынка; при необходимости удаляет неторговые символы и возвращает их количество.

Метод · CCrossTable void Init()

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

Метод · CCrossTable int LoadCrossCFD(string smaster_suffix,string sslave_suffix,string sCopirName)

Загружает таблицу соответствия символов из файла, создавая файл с примером при его отсутствии; возвращает число загруженных пар.

Метод · CCrossTable string cross_fx(string name)

Подбирает подходящее имя инструмента для торговли по заданному имени с учётом таблицы соответствия и пользовательских суффиксов; возвращает пустую строку, если соответствие не найдено.

Метод · CFileData void Reset()

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

Конструктор · CFileData CFileData()

Конструктор по умолчанию, создающий пустой объект с обнулёнными полями.

Деструктор · CFileData ~CFileData()

Деструктор, освобождающий массивы данных при уничтожении объекта.

Метод · CFileData bool do_action_filedata_order(CSymbolData &order)

Виртуальный обработчик, вызываемый для каждой загруженной записи о позиции или ордере; в базовом классе ничего не изменяет.

Метод · CFileData void do_action_filedata_init()

Виртуальный обработчик инициализации, вызываемый после загрузки списка символов и таблицы соответствия; в базовом классе пуст.

Метод · CFileData void OnInit(string sVERSION,string sName,string smaster_suffix,string sslave_suffix,bool bRemoveNoTrade)

Инициализирует объект: сохраняет версию и имя, загружает список торговых символов и таблицу соответствия, затем вызывает обработчик инициализации.

Метод · CFileData void OnDeinit(const int reason)

Освобождает массивы данных при завершении работы.

Метод · CFileData void FilterComment(string &comment)

Заменяет в строке комментария символ-разделитель, чтобы он не нарушал формат обмена данными.

Метод · CFileData ulong ConvertTicket(ulong thist)

Приводит тикет к корректному виду с учётом особенностей платформы.

Метод · CFileData bool IsSendEquity()

Виртуальный метод, определяющий, нужно ли передавать данные об эквити; в базовом классе возвращает false.

Метод · CFileData bool do_filter_filedata_update(bool bupdate)

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

Метод · CFileData void Master(int iMaxHistory)

Собирает данные о счёте-источнике и его открытых позициях и ордерах, при необходимости сохраняет их в файл обмена.

Метод · CFileData void Slave(ulong iAccountNumber)

Читает файл обмена для указанного счёта-источника и загружает из него данные, если файл изменился.

Метод · CFileData void ClearTicket(ulong tclear)

Сбрасывает тикет указанной записи, помечая её как обработанную.

Метод · CFileData void Save()

Формирует и записывает в файл обмена данные о счёте, инструментах и позициях для передачи на счёт-приёмник.

Метод · CFileData int GetIndexSymbolData(string ssymbol)

Возвращает индекс инструмента в загруженном списке или -1, если инструмент не найден.

Метод · CFileData int GetSymbolDataCountBuy(int i)

Возвращает количество покупок по инструменту с заданным индексом.

Метод · CFileData int GetSymbolDataCountSell(int i)

Возвращает количество продаж по инструменту с заданным индексом.

Метод · CFileData void ResetTriggerCopyByCount()

Удаляет глобальные переменные-триггеры, связанные с открытием позиций по инструментам.

Метод · CFileData int GetSymbolDataCountAll(int i)

Возвращает общее количество позиций по инструменту с заданным индексом.

Метод · CFileData double GetSymbolDataDD(int i)

Возвращает относительную просадку по инструменту с заданным индексом.

Метод · CFileData int LoadFile(string sfile,ulong iAccountNumber)

Загружает данные из файла обмена: сведения о счёте, список инструментов и записи о позициях и ордерах; возвращает код результата.

Метод · CFileData enum_type_data GetData(string &sstring,string &sdata[])

Разбирает строку файла обмена и определяет её тип: версия, данные счёта, инструмент или позиция.

Метод · CFileData bool NettingPosition(CSymbolData &data)

Объединяет загруженные записи по одному инструменту в общую нетто-позицию с учётом направления и объёма.

Метод · CFileData double NettingPositionMaster(string sSymbol,ENUM_ORDER_TYPE &etype)

Определяет по накопленным данным направление и объём нетто-позиции по заданному инструменту.

Метод · CGroupOrders void do_action_open_success(bool is_reopen)

Виртуальный обработчик, вызываемый после успешного открытия позиции; в базовом классе пуст.

Метод · CGroupOrders void do_action_closed_success()

Виртуальный обработчик, вызываемый при загрузке уже закрытой позиции; в базовом классе пуст.

Метод · CGroupOrders bool do_action_order_check_open_by_count(int icount,double master_dd_full)

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

Метод · CGroupOrders bool do_action_order_check_open(bool is_hedge,bool &is_reopen)

Виртуальный фильтр перед открытием позиции; запрещает открытие для записей из истории и в базовом классе разрешает остальные случаи.

Метод · CGroupOrders bool do_action_order_check_close()

Виртуальный фильтр перед закрытием позиции; в базовом классе разрешает закрытие.

Метод · CGroupOrders bool do_action_order_check_partclose()

Виртуальный фильтр перед частичным закрытием позиции; в базовом классе разрешает операцию.

Метод · CGroupOrders bool do_action_order_check_partlot()

Виртуальный фильтр перед частичным изменением объёма; в базовом классе разрешает операцию.

Метод · CGroupOrders bool do_action_order_check_modify()

Виртуальный фильтр перед изменением защитных уровней; запрещает изменение для записей из истории и в остальных случаях разрешает.

Метод · CGroupOrders bool do_action_groupmodify_check_modify(long etype,double dopen,double dstop,double dtake)

Виртуальный фильтр перед изменением защитных уровней группы; запрещает изменение для записей из истории и в остальных случаях разрешает.

Метод · CGroupOrders bool do_action_order(CSymbolData &order)

Виртуальный обработчик, позволяющий скорректировать запись о позиции или ордере; в базовом классе ничего не изменяет.

Метод · CGroupOrders bool EniqueType(long ileft,long iright)

Проверяет, относятся ли два типа ордеров к одному направлению (покупка или продажа).

Метод · CGroupOrders bool OnInit(ulong laccount,CSymbolData &eorder,double dmultiplicator,double dmaxlot,double duserlot)

Инициализирует управление группой: сохраняет параметры инструмента, множитель объёма, ограничения по лоту и данные записи.

Метод · CGroupOrders bool Check(CPositionInfo &position,long imagic)

Проверяет, относится ли позиция к данной группе по комментарию, инструменту и магическому номеру.

Метод · CGroupOrders bool Check(COrderInfo &order,long imagic)

Проверяет, относится ли ордер к данной группе по комментарию, инструменту и магическому номеру.

Метод · CGroupOrders bool Check(CDealInfo &deal,long imagic)

Проверяет, относится ли сделка к данной группе по комментарию, инструменту и магическому номеру.

Метод · CGroupOrders double GroupInHistory(bool is_hedge,bool &in_market)

Проверяет, есть ли позиции группы в рынке или в истории, и возвращает цену для возможного повторного входа.

Метод · CGroupOrders int GetGroupsCount()

Возвращает количество групп ордеров, различающихся магическими номерами.

Метод · CGroupOrders bool GroupControl(bool is_hedge,int icount,double master_dd_full)

Управляет группой ордеров: при необходимости открывает, доливает, сокращает или закрывает позиции в соответствии с целевым объёмом.

Метод · CGroupOrders bool GroupControlCloseNetting(bool is_hedge)

Управляет закрытием группы на неттинговом счёте, когда требуется закрыть позицию по инструменту.

Метод · CGroupOrders bool GroupClose(bool is_hedge,int itype,double dcloselot)

Закрывает позиции и удаляет отложенные ордера группы полностью или на указанный объём.

Метод · CGroupOrders bool GroupModify(bool is_hedge)

Изменяет защитные уровни позиций и отложенных ордеров группы в соответствии с данными записи.

Метод · CGroupOrders bool GroupInfo(int &itype,double &daverage,double &dlot,double &dprofit,int &icount)

Собирает сводную информацию о группе: направление, среднюю цену, суммарный объём, прибыль и количество ордеров.

Получить полный код

Поиск по коду файла

#ifndef __SOVETNIKOV_COPIER__
#define __SOVETNIKOV_COPIER__ ""

#ifndef __DEBUG__
#define __DEBUG__ true
#endif

#ifndef CopirName
#define CopirName "OrdersCopier"
#endif

#define LOG_DEBUG(x) if(__DEBUG__) x;

#define NO_ERRORS 0
#define ERROR_NO_CONNECTION ERR_CANNOT_OPEN_FILE
#define ERR_INVALID_VERSION ERR_USER_ERROR_FIRST+1
#ifdef __MQL4__
#define ERR_FILE_READERROR 5015
#endif

void LOG(string x)
  {
#ifdef __DEBUG__
   Print(x);
#endif
  }

#include <sovetnikovNET\defines.mqh>
#include <sovetnikovNET\Orders.mqh>

#include <Trade\PositionInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Trade\HistoryOrderInfo.mqh>

enum enum_type_data
  {
   type_data_continue, //no data, invalid data,continue
   type_data_version,//version
   type_data_account,//account master data
   type_data_symbol,//symbol
   type_data_position,//position
  };

/*класс будет хранить информацию по каждому символу  в зависимости от неттинг или хедже счета*/
class CSymbolData
  {

public:
   ulong              master_ticket; //тикет на мастере
   ulong              first_ticket; //если были частичные закрытия то сохраним исходный тикет
   ulong              client_ticket;  //тикет на клиенте
   string            master_symbol; //имя инструмента
   string            client_symbol; //имя инструмента
   int               type; //4 тип
   double            lot; //8 лот
   double            lotout; //8 Лот закрытый
   double            open; //8 цена открытие ордера
   double            close; //8 цена закрытие ордера
   double            stop; //8 стоп
   double            take; //8 тейк
   datetime          tmOpen;//8 открытие
   datetime          tmClose;//8 закрытие
   long              magic; //4 меджик - на клиенте тут формируется (int)(master_ticket+account), если это мт5, то там формировать будет (long)(master_ticket+account)
   double            real_open; //реальная цена открытия на клиенте

#ifdef __MQL5__
   long              master_magic; //меджик мастера (при загрузке на клиенте данных от мастера) mt5
#else
   int               master_magic; //меджик мастера (при загрузке на клиенте данных от мастера) mt4
#endif

   string            comment;
   long              state;
   bool              history;

   void              Reset()
     {
      master_ticket=0; //тикет на мастере
      first_ticket=0;
      client_ticket=0;  //тикет на клиенте
      master_symbol=""; //имя инструмента
      client_symbol=""; //имя инструмента
      type=0; //4 тип
      lot=0; //8 лот
      lotout=0; //8 лот закрытый
      open=0; //8 цена открытие ордера
      real_open=0; //реальная цена открытия на слейв
      close=0; //8 цена закрытие ордера
      stop=0; //8 стоп
      take=0; //8 тейк
      tmOpen=0;//8 открытие
      tmClose=0;//8 закрытие
      magic=0; //4 меджик - у мастера тут свой меджик, на клиенте тут храним меджик для контроля ордера
      master_magic=0; //сюда сохраняем на клиенте меджик мастера, он пригодится в будущем
      comment="";
      state=0;
      history=false; //открытый ордер по умолчанию
     }
                     CSymbolData()
     {
      Reset();
     }

   void              operator=(const int nil=NULL) //нулевая инициализация переменных
     {
      Reset();
     }

   void              operator=(const CSymbolData &data)//простое копирование
     {
      master_ticket=data.master_ticket; //тикет на мастере
      first_ticket=data.first_ticket;
      client_ticket=data.client_ticket;  //тикет на клиенте
      master_symbol=data.master_symbol; //имя инструмента
      client_symbol=data.client_symbol; //имя инструмента
      type=data.type; //4 тип
      lot=data.lot; //8 лот
      lotout=data.lotout;
      open=data.open; //8 цена открытие ордера
      real_open=data.real_open;
      close=data.close; //8 цена закрытие ордера
      stop=data.stop; //8 стоп
      take=data.take; //8 тейк
      tmOpen=data.tmOpen;//8 открытие
      tmClose=data.tmClose;//8 закрытие
      magic=data.magic; //4 меджик (будем такой же ставить)

      master_magic=data.master_magic;
      comment=data.comment;
      state=data.state;
      history=data.history;
     }

   bool              Load(long laccount,bool master_ishedge,bool ishedge,string &sdata[],long ltime_offset)
     {
      if(ArraySize(sdata)==16)
        {

         /*//по умолчанию точность double 6 цифр после запятой, сделал поддержку до 8 цифр на случай появления криптовалют с такой точностью
                   swrite=StringFormat("%s;%lld;%lld;%s;%d;%.8f;%.8f;%.8f;%.8f;%.8f;%lld;%lld;%lld;%ls;%d\n\r",
                                     orders[i].history?"closed":"open",//0
                                     orders[i].master_ticket,//1
                                     orders[i].first_ticket,//2
                                     orders[i].master_symbol,//3
                                     orders[i].type,//4
                                     orders[i].lot,//5
                                     orders[i].open,//6
                                     orders[i].close,//7
                                     orders[i].stop,//8
                                     orders[i].take,//9
                                     orders[i].tmOpen>0?orders[i].tmOpen:0,//10
                                     orders[i].tmClose>0?orders[i].tmClose:0,//11
                                     orders[i].magic,//12
                                     orders[i].comment,//13
                                     orders[i].state);//14
                                     */
         history=false;
         if(sdata[0]=="closed")
            history=true;

         master_ticket=StringToInteger(sdata[1]);
         first_ticket=StringToInteger(sdata[2]); //эти данные мастер заполняет если было частичное закрытие и тут будет ордер первый до частичного закрытия

         master_symbol=sdata[3];

         client_symbol=master_symbol; //тут будем корректировать по настройкам

         type=(int)StringToInteger(sdata[4]);
         lot=StringToDouble(sdata[5]);
         lotout=StringToDouble(sdata[6]);
         open=StringToDouble(sdata[7]);
         close=StringToDouble(sdata[8]);
         stop=StringToDouble(sdata[9]);
         take=StringToDouble(sdata[10]);
         tmOpen=(datetime)StringToInteger(sdata[11]);
         tmClose=(datetime)StringToInteger(sdata[12]);

         /*if(tmOpen>0)
            tmOpen=(datetime)(tmOpen-ltime_offset);
         if(tmClose>0)
            tmClose=(datetime)(tmClose-ltime_offset);
         */

#ifdef  __MQL5__
         master_magic=StringToInteger(sdata[13]); //сохраним на будущее меджик с мастера

         magic=(long)(laccount+master_ticket);//mt5

         if(!ishedge && master_ishedge)
            magic=(long)(laccount);//mt5
#else
         master_magic=(int)StringToInteger(sdata[13]); //сохраним на будущее меджик с мастера

         magic=(int)(laccount+master_ticket); //mt4

         if(!ishedge && master_ishedge)
            magic=(int)(laccount); //mt4
#endif

         comment=sdata[14];
         state=StringToInteger(sdata[15]);

         return true; //загрузка успешная
        }

      return false; //неверные данные
     }

   long              GetMagic(long iaccount)
     {
      return magic;
     }

   void              Print()
     {
      if(master_ticket<=0)
         return;

      PrintFormat("Print: %s;%lld;%lld;Master=%s;Client=%s;%d;%.8f;%.8f;%.8f;%.8f;%.8f;%.8f;%.8f;%s;%s;%lld;%ls;%d",
                  history?"closed":"open",//0
                  master_ticket,//1
                  first_ticket,//2
                  master_symbol,//3
                  client_symbol,//3
                  type,//4
                  lot,//5
                  lotout,//6
                  open,//7
                  real_open, //real open
                  close,//8
                  stop,//9
                  take,//10
                  tmOpen>0?TimeToString(tmOpen,TIME_DATE|TIME_MINUTES|TIME_SECONDS):"",//11
                  tmClose>0?TimeToString(tmClose,TIME_DATE|TIME_MINUTES|TIME_SECONDS):"",//12
                  magic,//13
                  comment,//14
                  state);//15
     }
  };

class CCrossTableItem
  {
public:
   string            first;
   string            second;

   void              Print()
     {
      PrintFormat("%s=%s",first,second);
     }

  };

class CCrossTable
  {
public:
   CCrossTableItem   crossCFD[];
   string            aSymbols[];
   int               ibuy[],isell[];
   double            dd[];
   string            master_suffix;
   string            slave_suffix;

   int               GetAllTradeSymbols(bool bremove)
     {
      int SymbolsNumber=0;

      static int lastSymbols=0;

      ArrayResize(aSymbols,0,1000);

      int j=0;
      for(int i=0; i<SymbolsTotal(true); i++)
        {
         string name=SymbolName(i,true);

         if(SymbolInfoInteger(name,SYMBOL_TRADE_MODE)==SYMBOL_TRADE_MODE_DISABLED)
           {
            if(bremove)
              {
               PrintFormat("Delete no trade symbol: %s",name);
               SymbolSelect(name,false); //удаляем неторговые сразу из списка если разрешено
              }

            continue;
           }

         ArrayResize(aSymbols,j+1);
         aSymbols[j]=name;
         j++;
         SymbolsNumber++;

        }

      ArrayResize(ibuy,j);
      ArrayResize(isell,j);
      ArrayResize(dd,j);

      ArrayInitialize(ibuy,0);
      ArrayInitialize(isell,0);
      ArrayInitialize(dd,0);

      lastSymbols=SymbolsTotal(true);

      return(SymbolsNumber);
     }

   void              Init()
     {
      CPositionInfo  m_position;
      int isymbols_total=ArraySize(aSymbols);

      ArrayInitialize(ibuy,0);
      ArrayInitialize(isell,0);
      ArrayInitialize(dd,0);

      if(isymbols_total==0 || AccountBalance()==0.0)
         return; //нет ордеров

      for(int i=0; i<PositionsTotal(); i++)
        {
         if(!m_position.SelectByIndex(i))
            continue;

         int itype=m_position.PositionType();

         if(itype>=2)
            continue; //пропустим неверные типы данных
#ifdef __MQL5__
         double dpr=m_position.Profit()+m_position.Swap()+m_position.Commission()*2;
#else
         double dpr=m_position.Profit()+m_position.Swap()+m_position.Commission();
#endif

         string smb=m_position.Symbol();

         for(int j=0; j<isymbols_total; j++)
           {
            if(aSymbols[j]==smb)
              {
               if(itype==POSITION_TYPE_BUY)
                  ibuy[j]++;
               if(itype==POSITION_TYPE_SELL)
                  isell[j]++;

               dd[j]+=dpr; //суммируем профит
               break;
              }
           }

        }

      for(int j=0; j<isymbols_total; j++)
        {
         dd[j]=NormalizeDouble(dd[j]*100/AccountBalance(),2); //посчитаем просадку
        }

     }

   int               LoadCrossCFD(string smaster_suffix,string sslave_suffix,string sCopirName)
     {
      ArrayResize(crossCFD,0,1000);

      master_suffix=smaster_suffix;
      slave_suffix=sslave_suffix;

      string sfile=StringFormat("%s/crosstable.txt",sCopirName);

      if(!FileIsExist(sfile))
        {

         int fs=FileOpen(sfile,FILE_WRITE|FILE_UNICODE|FILE_SHARE_READ|FILE_SHARE_WRITE,"\n",CP_UTF8);
         if(fs!=INVALID_HANDLE)
           {
            FileWriteString(fs,"XAUUSD=GOLD\n");
            FileWriteString(fs,"XAGUSD=SILVER\n");
            FileWriteString(fs,"USDRUB=USDRUR\n");
            FileWriteString(fs,"BTCUSD=BITCOIN\n");
            FileWriteString(fs,"LTCUSD=LITECOIN\n");
            FileWriteString(fs,"ETHUSD=ETHEREUM\n");
            FileWriteString(fs,"XRPUSD=RIPPLE\n");
            FileWriteString(fs,"XBNUSD=BITCOINC\n");

            FileClose(fs);
           }
        }

      int f=FileOpen(sfile,FILE_READ|FILE_UNICODE|FILE_SHARE_READ,"\n",CP_UTF8);
      string buf[],ss="";
      int ccc=0;
      if(f!=INVALID_HANDLE)
        {
         if(__DEBUG__)
            Print("Load crosstable.txt");

         while(!FileIsEnding(f))
           {
            ss=FileReadString(f);
            string_explode("=",ss,buf);

            if(ArraySize(buf)==2)
              {
               ccc=ArraySize(crossCFD);
               if(ArrayResize(crossCFD,ccc+1)!=-1)
                 {
                  crossCFD[ccc].first=Trim(buf[0]);
                  crossCFD[ccc].second=Trim(buf[1]);

                  if(__DEBUG__)
                     crossCFD[ccc].Print();
                 }

              }

           }
         FileClose(f);
        }

      if(master_suffix!="" || slave_suffix!="")
         PrintFormat("User suffix: %s=%s",master_suffix,slave_suffix);

      return ArraySize(crossCFD); //вернем размер
     }

   string            cross_fx(string name)
     {

      if(name=="")
         return ("");

      for(int j=0; j<ArrayRange(crossCFD,0); j++)
        {

         if(StringCompare(name,crossCFD[j].first,false)==0 || StringCompare(name,crossCFD[j].second,false)==0)
           {

            if(SymbolInfoDouble(crossCFD[j].second,SYMBOL_POINT)!=0.0)
              {
               if(SymbolInfoInteger(crossCFD[j].second,SYMBOL_SELECT))
                 {

                  return crossCFD[j].second;
                 }
              }

            if(SymbolInfoDouble(crossCFD[j].first,SYMBOL_POINT)!=0.0)
              {
               if(SymbolInfoInteger(crossCFD[j].first,SYMBOL_SELECT))
                 {

                  return crossCFD[j].first;
                 }
              }
           }
        }

      for(int i=0; i<ArraySize(aSymbols); i++)
        {
         if(StringCompare(name,aSymbols[i],true)==0) //точное совпадение
           {
            if(SymbolInfoDouble(aSymbols[i],SYMBOL_POINT)!=0.0)
              {
               if(SymbolInfoInteger(aSymbols[i],SYMBOL_SELECT))
                 {

                  return aSymbols[i];
                 }
              }
           }

        }

      string smaster=name;

      if(master_suffix!="" && StringFind(smaster,master_suffix,1)!=-1)
         StringReplace(smaster,master_suffix,""); //убираем суффикс если его нашли

      for(int i=0; i<ArraySize(aSymbols); i++)
        {
         string sslave=aSymbols[i];

         if(slave_suffix!="" && StringFind(sslave,slave_suffix,1)!=-1)
            StringReplace(sslave,slave_suffix,""); //убираем суффикс если его нашли

         if(StringCompare(smaster,sslave)==0)
           {
            if(SymbolInfoDouble(aSymbols[i],SYMBOL_POINT)!=0.0)
              {
               if(SymbolInfoInteger(aSymbols[i],SYMBOL_SELECT))
                 {

                  return aSymbols[i];
                 }
              }
           }
        }

      return ""; //не нашли
     }
  };

class CFileData
  {
private:
   string            sVersion,sCopirName;
   ulong             tm_last_open_file;
public:
   int               ierror;
   double            dbalance,dequity,dmargin; //баланс счета и эквити счета и маржи в %
   double            master_dbalance,master_dequity,master_dmargin; //баланс счета и эквити счета и маржи в % - ьастера для получения клиентом
   int               ileverage; //плечо
   int               master_ileverage; //плечо
   long              ilasttotal;
   bool              is_hedge,is_fifo; //тип счета неттинг или хедж
   bool              master_is_hedge,master_is_fifo; //тип счета неттинг или хедж
   bool              bRestart; //при рестарте ставим флаг true для сохранения файла даже без сделок

   string            currency; //валюта слейв счета
   string            master_currency; //валюта мастер счета
   ulong             lastupdate; //последнее обновлене тик таймер
   datetime          time; //время на мастер\слейв
   datetime          master_time; //время на мастере для расчета смещения
   long              time_offset; //смещение для корректировки времени откерытия
   bool              is_save; //возможность выключить сохранение в файл
   CSymbolData       orders[];//ордера открытые  и закрытые
   CSymbolData       position[]; //для нет счета

   string            master_aSymbols[]; //список пар куда сохраняем с мастера когда грузим на клиент
   int               master_ibuy[],master_isell[];
   double            master_dd[], //просадка по символу
                     master_dd_full; //просадка по счету мастера

   CCrossTable       m_crosstable;

   bool              bLoad; //флаг успешной загрузки данных

   ulong             m_master_account;

   void              Reset()
     {
      dbalance=0;
      dequity=0;
      dmargin=0;
      master_dbalance=0;
      master_dequity=0;
      master_dmargin=0;
      master_dd_full=0;
      ileverage=0;
      is_hedge=false;
      is_fifo=false;
      master_ileverage=0;
      master_is_hedge=false;
      master_is_fifo=false;
      tm_last_open_file=0;
      lastupdate=0;
      time=0;
      master_time=0;
      time_offset=0;
      is_save=true;
      ilasttotal=0;
      sVersion="1.00";
      currency="";
      master_currency="";
      bLoad=false;
      ArrayResize(orders,0,500);
      ArrayResize(position,0,500);

      ArrayResize(master_aSymbols,0,1000);
      ArrayResize(master_ibuy,0,1000);
      ArrayResize(master_isell,0,1000);
      ArrayResize(master_dd,0,1000);
      ierror=0;

      m_master_account=0;
     }
                     CFileData()
     {
      Reset();
     }

                    ~CFileData()
     {
      this.OnDeinit();
     }

   virtual bool      do_action_filedata_order(CSymbolData &order)
     {
      Print("Create func ",__FUNCSIG__);
      return true;
     }

   virtual void      do_action_filedata_init()
     {
     }

   virtual void              OnInit(string sVERSION,string sName,string smaster_suffix,string sslave_suffix,bool bRemoveNoTrade)
     {
      // код доступен только после оплаты
   }

   virtual void              OnDeinit(const int reason=0)
     {
      ArrayFree(orders);

      ArrayFree(master_aSymbols);
      ArrayFree(master_ibuy);
      ArrayFree(master_isell);
      ArrayFree(master_dd);
      ArrayFree(position);

     }

   void              FilterComment(string &comment)
     {
      StringReplace(comment,";",":"); //запрещенный символ, его заменяем т.к. используется для разделителя

     }

#ifdef __MQL4__
   ulong               ConvertTicket(ulong thist)
     {
      if((thist & 0x8000000000000000) != 0)
        {
         thist &=~0x8000000000000000;
        }

      return thist;
     }
#else
   ulong               ConvertTicket(ulong thist)
     {
      return thist;
     }
#endif

   virtual bool      IsSendEquity() { return false;}

   virtual bool      do_filter_filedata_update(bool bupdate)
     {
      return bupdate;
     }

   void              Master(int iMaxHistory)
     {
      double dmargincurrent=AccountInfoDouble(ACCOUNT_MARGIN);
      dbalance=AccountInfoDouble(ACCOUNT_BALANCE);
      dequity=AccountInfoDouble(ACCOUNT_EQUITY);

      dmargin=0;
      if(dequity>0 && dmargincurrent!=0)
         dmargin=NormalizeDouble((dequity/dmargincurrent)*100,3);//возвращаем уровень в процентах с 3 точностью

      ileverage=(int)AccountInfoInteger(ACCOUNT_LEVERAGE);
#ifdef __MQL5__
      is_hedge=AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING;
      is_fifo=AccountInfoInteger(ACCOUNT_FIFO_CLOSE);
#else
      is_hedge=true;
      is_fifo=false;
#endif

      lastupdate=GetMicrosecondCount();
      bool bneed_save=false;

      int isize=ArraySize(orders);

      CPositionInfo  pos;
      COrderInfo ord;
      CHistoryOrderInfo hist;

      bool bUpdate=false;      //если структура пустая, то обновляем ее
      int jorders=0;

      for(int i=isize-1; i>=0; i--)
        {
         if(orders[i].master_ticket==0)
           {
            continue;
           }

         bool bFind=false;

         if(!bUpdate && orders[i].history==false &&  pos.SelectByTicket(orders[i].master_ticket))
           {

            int iDigit=(int)SymbolInfoInteger(pos.Symbol(),SYMBOL_DIGITS);
            int iLotDigits=LotDigits(pos.Symbol());

            if(orders[i].type!=pos.PositionType())
              {
               bUpdate=true;
               LOG(StringFormat("Change type: %s new: %s #%lld",TypeToString(orders[i].type),TypeToString(pos.PositionType()),pos.Ticket()));
              }
            if(NormalizeDouble(orders[i].lot,iLotDigits)!=NormalizeDouble(pos.Volume(),iLotDigits))
              {
               bUpdate=true;
               LOG(StringFormat("Change lot: %f new: %f #%lld",orders[i].lot,pos.Volume(),pos.Ticket()));
              }
            if(NormalizeDouble(orders[i].open,iDigit)!=NormalizeDouble(pos.PriceOpen(),iDigit))
              {
               bUpdate=true;
               LOG(StringFormat("Change open: %f new: %f #%lld",orders[i].open,pos.PriceOpen(),pos.Ticket()));
              }
            if(NormalizeDouble(orders[i].stop,iDigit)!=NormalizeDouble(pos.StopLoss(),iDigit))
              {
               bUpdate=true;
               LOG(StringFormat("Change sl: %f new: %f #%lld",orders[i].stop,pos.StopLoss(),pos.Ticket()));
              }
            if(NormalizeDouble(orders[i].take,iDigit)!=NormalizeDouble(pos.TakeProfit(),iDigit))
              {
               bUpdate=true;
               LOG(StringFormat("Change tp: %f new: %f #%lld",orders[i].take,pos.TakeProfit(),pos.Ticket()));
              }

            bFind=true;
           }

         if(!bFind && !bUpdate && orders[i].history==false && ord.Select(orders[i].master_ticket))
           {

            int iDigit=(int)SymbolInfoInteger(ord.Symbol(),SYMBOL_DIGITS);
            int iLotDigits=LotDigits(ord.Symbol());

            if(orders[i].type!=ord.OrderType())
              {
               bUpdate=true;
               LOG(StringFormat("Change order type: %s new: %s #%lld",TypeToString(orders[i].type),TypeToString(ord.OrderType()),ord.Ticket()));
              }
            if(NormalizeDouble(orders[i].lot,iLotDigits)!=NormalizeDouble(ord.VolumeInitial(),iLotDigits))
              {
               bUpdate=true;
               LOG(StringFormat("Change order lot: %f new: %f #%lld",orders[i].lot,ord.VolumeInitial(),ord.Ticket()));
              }
            if(NormalizeDouble(orders[i].open,iDigit)!=NormalizeDouble(ord.PriceOpen(),iDigit))
              {
               bUpdate=true;
               LOG(StringFormat("Change order open: %f new: %f #%lld",orders[i].open,ord.PriceOpen(),ord.Ticket()));
              }
            if(NormalizeDouble(orders[i].stop,iDigit)!=NormalizeDouble(ord.StopLoss(),iDigit))
              {
               bUpdate=true;
               LOG(StringFormat("Change order sl: %f new: %f #%lld",orders[i].stop,ord.StopLoss(),ord.Ticket()));
              }
            if(NormalizeDouble(orders[i].take,iDigit)!=NormalizeDouble(ord.TakeProfit(),iDigit))
              {
               bUpdate=true;
               LOG(StringFormat("Change order tp: %f new: %f #%lld",orders[i].take,ord.TakeProfit(),ord.Ticket()));
              }

            if(orders[i].state!=ord.State())
              {
               bUpdate=true;
               LOG(StringFormat("Change order state: %s new: %s #%lld",EnumToString((ENUM_ORDER_STATE)orders[i].state),EnumToString((ENUM_ORDER_STATE)ord.State()),ord.Ticket()));
              }

            bFind=true;
           }

         if(!bUpdate && !bFind && orders[i].history==false)
           {

            ulong iticket=orders[i].first_ticket>0?orders[i].first_ticket:orders[i].master_ticket;
#ifdef __MQL4__
            if(OrderSelect((int)iticket,SELECT_BY_TICKET))
#else
            if(HistoryOrderSelect(iticket))
#endif
              {

#ifdef __MQL4__
               if(::OrderCloseTime()==0)
                 {
                  orders[i].history=false;
                  continue;
                 }
#endif

               hist.Ticket(iticket);

               if(orders[i].type!=hist.OrderType())
                 {
                  bUpdate=true;
                  LOG(StringFormat("Change history order type: %s new: %s #%lld",TypeToString(orders[i].type),TypeToString(hist.OrderType()),hist.Ticket()));
                 }

               if(orders[i].tmClose!=hist.TimeDone())
                 {
                  bUpdate=true;
                  LOG(StringFormat("Close order #%lld time: %s history flag: %s",
                                   iticket,
                                   TimeToString(hist.TimeDone(),TIME_DATE|TIME_MINUTES|TIME_SECONDS),
                                   BoolToString(orders[i].history)));
                 }

               bFind=true;
              }
           }

         if(bUpdate)
            break; //если хоть один ордер нужно обновить, то обновим и не будем првоерять остальные
        }

      bUpdate=do_filter_filedata_update(bUpdate);

      if(!bUpdate)
        {

         HistorySelect(0,TimeCurrent());

#ifdef __MQL5__
         long itotal=HistoryDealsTotal()+OrdersTotal()+PositionsTotal();
#else
         long itotal=HistoryOrdersTotal()+OrdersTotal();
#endif

         if(itotal!=ilasttotal)
           {

            bUpdate=true;
            ilasttotal=itotal;

           }

        }

      if(bUpdate || bRestart)
        {

         bRestart=false;
         bneed_save=true;

         ArrayFree(orders);

         isize=0;

#ifdef __MQL5__
         for(int i=PositionsTotal()-1; i>=0; i--)
#else
         for(int i=OrdersTotal()-1; i>=0; i--)
#endif
           {

            if(!pos.SelectByIndex(i))
               continue;

            if(pos.PositionType()>=2)
               continue; //проверим по типу, пригодиться для мт4

            isize=ArraySize(orders);

            if(ArrayResize(orders,isize+1)!=-1)
              {
               orders[isize].history=false;
               orders[isize].master_ticket=pos.Ticket();
               orders[isize].master_symbol=pos.Symbol();
               orders[isize].magic=pos.Magic();
               orders[isize].lot=pos.Volume();
               orders[isize].lotout=0; //сюда надо будет записать значение объема на который были закрыты сделки
               orders[isize].type=pos.PositionType();
               orders[isize].open=pos.PriceOpen();
               orders[isize].stop=pos.StopLoss();
               orders[isize].take=pos.TakeProfit();
               orders[isize].tmOpen=pos.Time();
               orders[isize].tmClose=0;
               orders[isize].comment=pos.Comment();
               orders[isize].close=0;
               orders[isize].state=0;
               FilterComment(orders[isize].comment);
              }

           }

         for(int i=OrdersTotal()-1; i>=0; i--)
           {

            if(!ord.SelectByIndex(i))
               continue;

            if(ord.OrderType()>=0 && (ord.OrderType()<2 || ord.OrderType()>=6))
               continue; //првоерим по типу, пригодиться для мт4

            isize=ArraySize(orders);

            if(ArrayResize(orders,isize+1)!=-1)
              {
               orders[isize].history=false;
               orders[isize].master_ticket=ord.Ticket();
               orders[isize].master_symbol=ord.Symbol();
               orders[isize].magic=ord.Magic();
               orders[isize].lot=ord.VolumeCurrent();
               orders[isize].lotout=0;
               orders[isize].type=ord.OrderType();
               orders[isize].open=ord.PriceOpen();
               orders[isize].stop=ord.StopLoss();
               orders[isize].take=ord.TakeProfit();
               orders[isize].tmOpen=ord.TimeSetup();
               orders[isize].tmClose=0;
               orders[isize].comment=ord.Comment();
               orders[isize].close=0;
               orders[isize].state=ord.State();
               FilterComment(orders[isize].comment);

              }

           }

         datetime tmDay1=TimeCurrent()-iMaxHistory*60;//iTime(_Symbol,PERIOD_D1,MaxDays);

         HistorySelect(tmDay1,TimeCurrent()); //загрузим историю за прошлый день, потребуется для отметки если был ордер закрыт

#ifdef __MQL5__
         CDealInfo deal;

         if(HistoryDealsTotal()>0)
           {
            for(int i=HistoryDealsTotal()-1; i>=0; i--)
              {
               if(!deal.SelectByIndex(i))
                  continue;

               if(deal.Entry()==DEAL_ENTRY_INOUT || deal.Entry()==DEAL_ENTRY_OUT)
                 {
                  ulong tdeal=deal.Ticket();
                  long thist=deal.PositionId();

                  ENUM_DEAL_TYPE etype=deal.DealType();

                  if(etype==DEAL_TYPE_BUY || etype==DEAL_TYPE_SELL)
                    {
                     if(etype==DEAL_TYPE_BUY)
                        etype=DEAL_TYPE_SELL;
                     else
                        if(etype==DEAL_TYPE_SELL)
                           etype=DEAL_TYPE_BUY;

                     if(thist>0)
                       {
                        if(pos.SelectByTicket(ConvertTicket(thist)))
                          {
                           if(pos.Time()==0)
                              continue; //если этот оредр еще в рынке, то он не в истории!!
                          }
                        else
                          {

                           bool bfind=false;
                           for(int iisize=ArraySize(orders)-1; iisize>=0; iisize--)
                             {

                              if(orders[iisize].master_ticket==thist)
                                {
                                 orders[iisize].history=true; //пометим  что уже закрыт
                                 bfind=true;
                                 break;
                                }
                             }

                           if(!bfind && thist>0)
                             {
                              isize=ArraySize(orders);

                              if(ArrayResize(orders,isize+1)!=-1)
                                {

                                 orders[isize].history=true;
                                 orders[isize].master_ticket=thist;
                                 orders[isize].master_symbol=deal.Symbol();
                                 orders[isize].magic=deal.Magic();
                                 orders[isize].type=etype;
                                 orders[isize].stop=0;
                                 orders[isize].take=0;
                                 orders[isize].lot=deal.Volume();
                                 orders[isize].lotout=0;

                                 orders[isize].open=0;
                                 orders[isize].close=deal.Price();
                                 orders[isize].comment=deal.Comment();
                                 orders[isize].state=4;
                                 orders[isize].tmOpen=deal.Time();
                                 orders[isize].tmClose=deal.Time();

                                 HistorySelectByPosition(thist);

                                 CDealInfo deal2;
                                 double dsummlot=0.0;
                                 double dlot=0.0,dlotout=0.0;

                                 for(int j=0; j<HistoryDealsTotal(); j++)
                                   {
                                    if(!deal2.SelectByIndex(j))
                                       continue;

                                    double ddeallot=NLot(deal2.Volume(),deal2.Symbol());

                                    if(deal2.Entry()==DEAL_ENTRY_IN)
                                      {

                                       dlot=NLot(dlot+ddeallot,deal2.Symbol());

                                      }

                                    if(deal2.Entry()==DEAL_ENTRY_OUT || deal.Entry()==DEAL_ENTRY_INOUT)
                                      {

                                       dlotout=NLot(dlotout+ddeallot,deal2.Symbol());

                                       if(orders[isize].tmClose==0 || deal2.Time()<orders[isize].tmClose)
                                         {
                                          orders[isize].tmClose=deal2.Time();

                                         }
                                      }
                                   }

                                 FilterComment(orders[isize].comment);
                                 orders[isize].lot=dlot; //объем покупки
                                 orders[isize].lotout=dlotout;//сохранили объем который частично был закрыт

                                 /* if(dsummlot==0.0)
                                    {
                                     orders[isize].lot=dlot;
                                    }*/

                                 HistorySelect(tmDay1,TimeCurrent()); //загрузим историю за прошлый день, потребуется для отметки если был ордер закрыт

                                }
                             }
                          }

                       }
                    }
                 }
              }
           }
#endif

         HistorySelect(tmDay1,TimeCurrent()); //загрузим историю за прошлый день, потребуется для отметки если был ордер закрыт

         for(int i=HistoryOrdersTotal()-1; i>=0; i--)
           {

            if(!hist.SelectByIndex(i))
              {

               continue;
              }

            ulong thist=hist.Ticket();
#ifdef __MQL4__
            if((thist & 0x8000000000000000) != 0)
               continue; //пропускаем историю

            long tmpDeals[],tmpOrders[];
            ArrayCopy(tmpDeals,historyDeals);
            ArrayCopy(tmpOrders,historyOrders);
#endif
            if(pos.SelectByTicket(ConvertTicket(thist)))
              {
               if(pos.Time()==0)
                 {
#ifdef __MQL4__
                  ArrayCopy(historyDeals,tmpDeals);
                  ArrayCopy(historyOrders,tmpOrders);
#endif
                  continue; //если этот оредр еще в рынке, то он не в истории!!
                 }

#ifdef __MQL5__
               continue; //если этот оредр еще в рынке, то он не в истории!!
#endif
              }
#ifdef __MQL4__
            ArrayCopy(historyDeals,tmpDeals);
            ArrayCopy(historyOrders,tmpOrders);
#endif

            if(hist.VolumeInitial()>0 && hist.OrderType()<6 && hist.OrderType()>=0)
              {

               isize=ArraySize(orders);

               if(ArrayResize(orders,isize+1)!=-1)
                 {
                  orders[isize].history=true;
                  orders[isize].master_ticket=hist.Ticket();
                  if(orders[isize].master_ticket==0)
                     orders[isize].master_ticket=hist.Ticket();

                  orders[isize].master_symbol=hist.Symbol();
                  orders[isize].magic=hist.Magic();
                  orders[isize].type=hist.OrderType();
                  orders[isize].stop=hist.StopLoss();
                  orders[isize].take=hist.TakeProfit();
                  orders[isize].lot=hist.VolumeInitial();

                  orders[isize].open=0;
                  orders[isize].close=hist.PriceOpen();
                  orders[isize].comment=hist.Comment();
                  orders[isize].state=hist.State();

                  orders[isize].tmOpen=hist.TimeSetup();
                  orders[isize].tmClose=hist.TimeDone();

#ifdef __MQL4__
                  ArrayCopy(tmpDeals,historyDeals);
                  ArrayCopy(tmpOrders,historyOrders);
#endif

                  HistorySelectByPosition(thist);

                  CDealInfo deal2;

                  for(int j=0; j<HistoryDealsTotal(); j++)
                    {
                     if(!deal2.SelectByIndex(j))
                        continue;

                     if(deal2.Entry()==DEAL_ENTRY_OUT || deal2.Entry()==DEAL_ENTRY_INOUT)
                       {
                        if(orders[isize].tmClose==0 || deal2.Time()<orders[isize].tmClose)
                          {
                           orders[isize].tmClose=deal2.Time();

                          }
                       }
                    }
#ifdef __MQL4__
                  ArrayCopy(historyDeals,tmpDeals);
                  ArrayCopy(historyOrders,tmpOrders);
#endif
                  FilterComment(orders[isize].comment);

                  HistorySelect(tmDay1,TimeCurrent()); //загрузим историю за прошлый день, потребуется для отметки если был ордер закрыт

                 }
              }
           }

#ifndef __MQL5__

         HistorySelect(0,TimeCurrent()); //загрузим историю за прошлый день, потребуется для отметки если был ордер закрыт

         for(int i=0; i<ArraySize(orders); i++)
           {

            if(orders[i].master_ticket==0)
               continue;

            int j=0;

            ulong inext=ConvertTicket(orders[i].master_ticket);
            bool bfind_partclose=false;

            double dsummlot=orders[i].lot;
            double dclose=0;
            datetime tmopen=orders[i].tmOpen;
            datetime tmclose=orders[i].tmClose;
            bool bHistory=false;

            if(::OrderSelect((int)inext,SELECT_BY_TICKET))
              {
               if(::OrderCloseTime()>0)
                 {
                  bHistory=true;
                  if(dclose==0)
                     dclose=::OrderClosePrice();
                 }

               inext=::OrderTicket();
               tmopen=::OrderOpenTime();
               tmclose=::OrderCloseTime();

               for(j=0; j<OrdersHistoryTotal(); j++)
                 {
                  if(!OrderSelect(j,SELECT_BY_POS,MODE_HISTORY))
                     continue;

                  if(StringFind(::OrderComment(),StringFormat("to #%lld",inext),0)==0)
                    {
                     j=0;
                     ClearTicket(::OrderTicket());
                     dsummlot+=::OrderLots();

                     tmopen=::OrderOpenTime();
                     if(dclose==0)
                        dclose=::OrderClosePrice();

                     inext=::OrderTicket(); //берем данные для следующего
                     bfind_partclose=true;
                    }

                 }

               if(bfind_partclose)
                 {
                  orders[i].first_ticket=orders[i].master_ticket;
                  orders[i].master_ticket=inext;
                  if(bHistory)
                     orders[i].lot=dsummlot;
                  orders[i].tmOpen=tmopen;
                  orders[i].tmClose=tmclose;
                  orders[i].close=dclose;

                 }
              }

            /* if(orders[i].master_ticket>0 && !is_hedge)
                {
                 if(HistorySelectByPosition(orders[i].master_ticket))
                   {

                    for(j=0; j<HistoryOrdersTotal(); j++)
                      {
                       ulong torder=HistoryOrderGetTicket(j);

                       HistoryOrderSelect(orders[i].master_ticket); //выбираем данный ордер

                       bool bHide=false;
                       for(int l=0; l<HistoryDealsTotal(); l++)
                         {
                          ulong tdeal=HistoryDealGetTicket(l); //проверяем были ли сделки

                          if(HistoryDealGetInteger(tdeal,DEAL_ENTRY)!=DEAL_ENTRY_INOUT)
                            {
                             bHide=true;

                            }
                         }

                       if(bHide)
                         {

                         }
                      }
                   }
                }*/

           }
#endif

         if(is_save && bneed_save)
           {

            Save();

           }
        }

     }

   void              Slave(ulong iAccountNumber)
     {
      m_master_account=iAccountNumber;

      if(MQLInfoInteger(MQL_TESTER))
         return;

      bool bUpdateFile=false;
      ulong tm_file_open=0;

      string sfile=StringFormat("%s\\master-%lld.csv",sCopirName,iAccountNumber);

      ResetLastError();

      int f=FileOpen(sfile,FILE_READ|FILE_SHARE_READ|FILE_COMMON|FILE_UNICODE|FILE_CSV,"\n",CP_UTF8);
      tm_file_open=0;

      if(f<0)
         ierror=GetLastError();

      if(f!=-1)
        {

         string line=FileReadString(f);
         tm_file_open=(ulong)StringToDouble(line); //время тика
         FileClose(f);
        }

      if(tm_file_open!=tm_last_open_file)
        {
         tm_last_open_file=tm_file_open;
         bUpdateFile=true; //у нас изменился файл

        }

      if(bUpdateFile)
        {
         ierror=0;

         LoadFile(sfile,iAccountNumber); //загрузим данные

        }

     }

   void              ClearTicket(ulong tclear)
     {
      if(tclear<=0)
         return;

      for(int i=0; i<ArraySize(orders); i++)
        {
         if(orders[i].master_ticket==tclear && orders[i].tmClose>0)
           {
            orders[i].master_ticket=0;

            break;
           }
        }
     }

   void              Save()
     {

      m_crosstable.Init();  //пред сохранением просчитаем все данные по парам

      string sfile=StringFormat("%s\\master-%lld.csv",sCopirName,AccountInfoInteger(ACCOUNT_LOGIN));

      datetime tmgmt=TimeGMT();

#ifdef __MQL5__
      datetime tmcu

Показано первые 50% кода (символов: 52579)

Открыть по тарифу

Купите тариф с пакетом открытий или войдите, если тариф уже есть. Открытый файл останется в вашем кабинете навсегда.

Разовая покупка файла

На этой странице откроется полный исходный код файла вместо ознакомительного фрагмента.

Чтобы оформить заказ, введите email и перейдите к оплате.

Стоимость полного кода
5 257,90₽ ≈ $64.27