CustomTicksAdd

Добавляет в ценовую историю пользовательского инструмента данные из массива типа MqlTick. Пользовательский символ должен быть выбран в окне MarketWatch (Обзор рынка).

bool  CustomTicksAdd(
   const string     symbol,             // имя символа
   const MqlTick&   ticks[],            // массив с тиковыми данными, которые необходимо применить к пользовательскому инструменту
   uint             count=WHOLE_ARRAY   // количество элементов, которые будут использованы из массива ticks[]
   );

Параметры

symbol

[in]  Имя пользовательского инструмента.

ticks[]

[in]   Массив тиковых данных типа MqlTick, упорядоченных по времени в порядке возрастания, то есть требуется чтобы ticks[k].time_msc <= ticks[n].time_msc, если k<n.

count=WHOLE_ARRAY

[in]  Количество элементов из массива ticks[], которые будут использованы для добавления. Значение WHOLE_ARRAY означает, что необходимо использовать все элементы массива ticks[].

Возвращаемое значение

Количество добавленных тиков либо -1 в случае ошибки.

Примечание

Функция CustomTicksAdd работает только для пользовательских символов, открытых в окне MarketWatch (Обзор рынка). Если символ не выбран в MarketWatch, то для вставки тиков необходимо использовать CustomTicksReplace.

Функция CustomTicksAdd позволяет транслировать тики так, как если бы они приходили от сервера брокера. Данные записываются не напрямую в базу тиков, а отправляются в окно "Обзор рынка". И уже из него терминал сохраняет тики в своей базе. При большом объеме данных, передаваемых за один вызов, функция меняет свое поведение для экономии ресурсов. Если передается более 256 тиков, данные делятся на две части. Первая часть (большая) сразу напрямую записывается в базу тиков (как это делает CustomTicksReplace). Вторая часть, состоящая из последних 128 тиков, передается в окно "Обзор рынка" и после этого сохраняется терминалом в базе.

Структура MqlTick имеет два поля со значением времени – time (время тика в секундах) и time_msc (время тика в миллисекундах) – которые ведут отсчет от 01 января 1970 года. Обработка этих полей в добавляемых тиках производится по следующим правилам в указанном порядке:

  1. если значение ticks[k].time_msc!=0, то используем его для заполнения поля ticks[k].time, то есть для тика выставляется время ticks[k].time=ticks[k].time_msc/1000 (деление целочисленное)
  2. если ticks[k].time_msc==0 и ticks[k].time!=0, то время в миллисекундах получается умножением на 1000, то есть  ticks[k].time_msc=ticks[k].time*1000
  3. если ticks[k].time_msc==0 и ticks[k].time==0, то в эти поля записывается текущее время торгового сервера с точностью до миллисекунд на момент вызова функции CustomTicksAdd.

Если значение полей ticks[k].bid, ticks[k].ask, ticks[k].last или ticks[k].volume больше нуля, то в поле ticks[k].flags пишется комбинация соответствующих флагов:

  • TICK_FLAG_BID – тик изменил цену бид
  • TICK_FLAG_ASK  – тик изменил цену аск
  • TICK_FLAG_LAST – тик изменил цену последней сделки
  • TICK_FLAG_VOLUME – тик изменил объем

Если значение какого-то поля меньше или равно нуля, соответствующий ему флаг не записываются в поле ticks[k].flags.

 

Флаги TICK_FLAG_BUY и TICK_FLAG_SELL в историю пользовательского инструмента не добавляются.

 

Пример:

//+------------------------------------------------------------------+
//|                                               CustomTicksAdd.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
 
#define   CUSTOM_SYMBOL_NAME     Symbol()+".C"     // наименование пользовательского символа
#define   CUSTOM_SYMBOL_PATH     "Forex"           // название группы, в которой будет создан символ
#define   CUSTOM_SYMBOL_ORIGIN   Symbol()          // наименование символа, на основе которого будет создан пользовательский
 
#define   DATATICKS_TO_COPY      UINT_MAX          // количество копируемых тиков
#define   DATATICKS_TO_PRINT     20                // количество выводимых тиков в журнал
 
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- получаем код ошибки при создании пользовательского символа
   int create=CreateCustomSymbol(CUSTOM_SYMBOL_NAMECUSTOM_SYMBOL_PATHCUSTOM_SYMBOL_ORIGIN);
   
//--- если код ошибки не 0 (успешное создание символа) и не 5304 (символ уже создан) - уходим
   if(create!=0 && create!=5304)
      return;
 
//--- получим в массив MqlTick данные тиков стандартного символа
   MqlTick array[]={};
   if(!GetTicksToArray(CUSTOM_SYMBOL_ORIGINDATATICKS_TO_COPYarray))
      return;
   
//--- распечатаем время первого и последнего полученных тиков стандартного символа
   int total=(int)array.Size();
   PrintFormat("First tick time: %s.%03u, Last tick time: %s.%03u",
               TimeToString(array[0].timeTIME_DATE|TIME_MINUTES|TIME_SECONDS), array[0].time_msc%1000,
               TimeToString(array[total-1].timeTIME_DATE|TIME_MINUTES|TIME_SECONDS), array[total-1].time_msc%1000);
               
//--- распечатаем в журнале DATATICKS_TO_PRINT последних тиков стандартного символа
   PrintFormat("\nThe last %d ticks for the standard symbol '%s':"DATATICKS_TO_PRINTCUSTOM_SYMBOL_ORIGIN);
   for(int i=total-DATATICKS_TO_PRINTi<totali++)
     {
      if(i<0)
         continue;
      PrintFormat("  %dth Tick: %s"iGetTickDescription(array[i]));
     }
   
//--- добавляем пользовательский символ в окно MarketWatch (обзор рынка)
   ResetLastError();
   if(!SymbolSelect(CUSTOM_SYMBOL_NAMEtrue))
     {
      Print("SymbolSelect() failed. Error "GetLastError());
      return;
     }
     
//--- добавим в ценовую историю пользовательского символа данные из массива тиков
   Print("...");
   uint start=GetTickCount();
   PrintFormat("Start of adding %u ticks to the history of the custom symbol '%s'"array.Size(), CUSTOM_SYMBOL_NAME);
   int added=CustomTicksAdd(CUSTOM_SYMBOL_NAMEarray);
   PrintFormat("Added %u ticks to the history of the custom symbol '%s' in %u ms"addedCUSTOM_SYMBOL_NAMEGetTickCount()-start);
   
//--- получим в массив MqlTick данные тиков пользовательского символа
   Print("...");
   if(!GetTicksToArray(CUSTOM_SYMBOL_NAMEarray.Size(), array))
      return;
   
//--- распечатаем время первого и последнего полученных тиков пользовательского символа
   total=(int)array.Size();
   PrintFormat("First tick time: %s.%03u, Last tick time: %s.%03u",
               TimeToString(array[0].timeTIME_DATE|TIME_MINUTES|TIME_SECONDS), array[0].time_msc%1000,
               TimeToString(array[total-1].timeTIME_DATE|TIME_MINUTES|TIME_SECONDS), array[total-1].time_msc%1000);
               
//--- распечатаем в журнале DATATICKS_TO_PRINT последних тиков пользовательского символа
   PrintFormat("\nThe last %d ticks for the custom symbol '%s':"DATATICKS_TO_PRINTCUSTOM_SYMBOL_NAME);
   for(int i=total-DATATICKS_TO_PRINTi<totali++)
     {
      if(i<0)
         continue;
      PrintFormat("  %dth Tick: %s"iGetTickDescription(array[i]));
     }
 
//--- выведем на график в комментарии подсказку о клавишах завершения работы скрипта
   Comment(StringFormat("Press 'Esc' to exit or 'Del' to delete the '%s' symbol and exit"CUSTOM_SYMBOL_NAME));
//--- в бесконечном цикле ожидаем нажатия клавиш Esc или Del для выхода
   while(!IsStopped() && TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE)==0)
     {
      Sleep(16);
      //--- при нажатии Del, удаляем созданный пользовательский символ и его данные
      if(TerminalInfoInteger(TERMINAL_KEYSTATE_DELETE)<0)
        {
         //--- удаляем данные баров
         int deleted=CustomRatesDelete(CUSTOM_SYMBOL_NAME0LONG_MAX);
         if(deleted>0)
            PrintFormat("%d history bars of the custom symbol '%s' were successfully deleted"deletedCUSTOM_SYMBOL_NAME);
         
         //--- удаляем тиковые данные
         deleted=CustomTicksDelete(CUSTOM_SYMBOL_NAME0LONG_MAX);
         if(deleted>0)
            PrintFormat("%d history ticks of the custom symbol '%s' were successfully deleted"deletedCUSTOM_SYMBOL_NAME);
         
         //--- удаляем символ
         if(DeleteCustomSymbol(CUSTOM_SYMBOL_NAME))
            PrintFormat("Custom symbol '%s' deleted successfully"CUSTOM_SYMBOL_NAME);
         break;
        }
     }
//--- перед выходом очистим график
   Comment("");
   /*
   результат:
   Requested 4294967295 ticks to download tick history for the symbol 'EURUSD'
   The tick history for the 'EURUSDsymbol is received in the amount of 351183943 ticks in 56454 ms
   First tick time2011.12.19 00:00:08.000Last tick time2024.06.20 21:18:12.010
   
   The last 20 ticks for the standard symbol 'EURUSD':
     351183923th Tick2024.06.20 21:17:46.380 Bid=1.07124 (Info tick)
     351183924th Tick2024.06.20 21:17:47.779 Ask=1.07125 Bid=1.07125 (Info tick)
     351183925th Tick2024.06.20 21:17:48.584 Ask=1.07124 Bid=1.07124 (Info tick)
     351183926th Tick2024.06.20 21:17:49.481 Ask=1.07125 (Info tick)
     351183927th Tick2024.06.20 21:17:49.985 Ask=1.07122 Bid=1.07122 (Info tick)
     351183928th Tick2024.06.20 21:17:50.482 Ask=1.07124 Bid=1.07124 (Info tick)
     351183929th Tick2024.06.20 21:17:51.584 Ask=1.07123 Bid=1.07123 (Info tick)
     351183930th Tick2024.06.20 21:17:52.786 Ask=1.07124 Bid=1.07124 (Info tick)
     351183931th Tick2024.06.20 21:17:53.487 Ask=1.07125 Bid=1.07125 (Info tick)
     351183932th Tick2024.06.20 21:17:53.989 Ask=1.07126 Bid=1.07126 (Info tick)
     351183933th Tick2024.06.20 21:17:55.789 Ask=1.07125 Bid=1.07125 (Info tick)
     351183934th Tick2024.06.20 21:17:58.495 Ask=1.07126 Bid=1.07126 (Info tick)
     351183935th Tick2024.06.20 21:18:00.102 Bid=1.07126 (Info tick)
     351183936th Tick2024.06.20 21:18:00.698 Ask=1.07129 Bid=1.07129 (Info tick)
     351183937th Tick2024.06.20 21:18:03.699 Bid=1.07129 (Info tick)
     351183938th Tick2024.06.20 21:18:04.699 Ask=1.07128 Bid=1.07128 (Info tick)
     351183939th Tick2024.06.20 21:18:05.901 Ask=1.07129 Bid=1.07129 (Info tick)
     351183940th Tick2024.06.20 21:18:07.606 Ask=1.07128 Bid=1.07128 (Info tick)
     351183941th Tick2024.06.20 21:18:11.512 Ask=1.07127 Bid=1.07127 (Info tick)
     351183942th Tick2024.06.20 21:18:12.010 Ask=1.07126 Bid=1.07126 (Info tick)
   ...
   Start of adding 351183943 ticks to the history of the custom symbol 'EURUSD.C'
   Added 351183943 ticks to the history of the custom symbol 'EURUSD.Cin 269890 ms
   ...
   Requested 351183943 ticks to download tick history for the symbol 'EURUSD.C'
   The tick history for the 'EURUSD.Csymbol is received in the amount of 351183943 ticks in 116407 ms
   First tick time2011.12.19 00:00:08.000Last tick time2024.06.20 21:18:12.010
   
   The last 20 ticks for the custom symbol 'EURUSD.C':
     351183923th Tick2024.06.20 21:17:46.380 Ask=1.07124 Bid=1.07124 (Info tick)
     351183924th Tick2024.06.20 21:17:47.779 Ask=1.07125 Bid=1.07125 (Info tick)
     351183925th Tick2024.06.20 21:17:48.584 Ask=1.07124 Bid=1.07124 (Info tick)
     351183926th Tick2024.06.20 21:17:49.481 Ask=1.07125 Bid=1.07125 (Info tick)
     351183927th Tick2024.06.20 21:17:49.985 Ask=1.07122 Bid=1.07122 (Info tick)
     351183928th Tick2024.06.20 21:17:50.482 Ask=1.07124 Bid=1.07124 (Info tick)
     351183929th Tick2024.06.20 21:17:51.584 Ask=1.07123 Bid=1.07123 (Info tick)
     351183930th Tick2024.06.20 21:17:52.786 Ask=1.07124 Bid=1.07124 (Info tick)
     351183931th Tick2024.06.20 21:17:53.487 Ask=1.07125 Bid=1.07125 (Info tick)
     351183932th Tick2024.06.20 21:17:53.989 Ask=1.07126 Bid=1.07126 (Info tick)
     351183933th Tick2024.06.20 21:17:55.789 Ask=1.07125 Bid=1.07125 (Info tick)
     351183934th Tick2024.06.20 21:17:58.495 Ask=1.07126 Bid=1.07126 (Info tick)
     351183935th Tick2024.06.20 21:18:00.102 Ask=1.07126 Bid=1.07126 (Info tick)
     351183936th Tick2024.06.20 21:18:00.698 Ask=1.07129 Bid=1.07129 (Info tick)
     351183937th Tick2024.06.20 21:18:03.699 Ask=1.07129 Bid=1.07129 (Info tick)
     351183938th Tick2024.06.20 21:18:04.699 Ask=1.07128 Bid=1.07128 (Info tick)
     351183939th Tick2024.06.20 21:18:05.901 Ask=1.07129 Bid=1.07129 (Info tick)
     351183940th Tick2024.06.20 21:18:07.606 Ask=1.07128 Bid=1.07128 (Info tick)
     351183941th Tick2024.06.20 21:18:11.512 Ask=1.07127 Bid=1.07127 (Info tick)
     351183942th Tick2024.06.20 21:18:12.010 Ask=1.07126 Bid=1.07126 (Info tick)
   */
  }
//+------------------------------------------------------------------+
//| Создаёт пользовательский символ, возвращает код ошибки           |
//+------------------------------------------------------------------+
int CreateCustomSymbol(const string symbol_nameconst string symbol_pathconst string symbol_origin=NULL)
  {
//--- определяем наименование символа, на основе которого будет создан пользовательский
   string origin=(symbol_origin==NULL ? Symbol() : symbol_origin);
   
//--- если пользовательский символ создать не удалось, и это не ошибка 5304 - сообщаем об этом в журнале
   ResetLastError();
   int error=0;
   if(!CustomSymbolCreate(symbol_namesymbol_pathorigin))
     {
      error=GetLastError();
      if(error!=5304)
         PrintFormat("CustomSymbolCreate(%s, %s, %s) failed. Error %d"symbol_namesymbol_pathoriginerror);
     }
//--- успешно
   return(error);
  }
//+------------------------------------------------------------------+
//| Удаляет пользовательский символ                                  |
//+------------------------------------------------------------------+
bool DeleteCustomSymbol(const string symbol_name)
  {
//--- скроем символ из окна Обзор рынка
   ResetLastError();
   if(!SymbolSelect(symbol_namefalse))
     {
      PrintFormat("SymbolSelect(%s, false) failed. Error %d"GetLastError());
      return(false);
     }
      
//--- если пользовательский символ удалить не удалось - сообщаем об этом в журнале и возвращаем false
   ResetLastError();
   if(!CustomSymbolDelete(symbol_name))
     {
      PrintFormat("CustomSymbolDelete(%s) failed. Error %d"symbol_nameGetLastError());
      return(false);
     }
//--- успешно
   return(true);
  }
//+------------------------------------------------------------------+
//| Получает указанное количество тиков в массив                     |
//+------------------------------------------------------------------+
bool GetTicksToArray(const string symbolconst uint countMqlTick &array[])
  {
//--- сообщим о начале загрузки исторических данных
   PrintFormat("Requested %u ticks to get tick history for the symbol '%s'"countsymbol);
   
//--- сделаем 3 попытки получить тики 
   int attempts=0;
   while(attempts<3)
     {
      //--- замерим время старта перед получением тиков
      uint start=GetTickCount();
      
      //--- запросим тиковую историю с момента 1970.01.01 00:00.001 (параметр from=1 ms)
      int received=CopyTicks(symbolarrayCOPY_TICKS_ALL1count);
      if(received!=-1)
        {
         //--- выведем информацию о количестве тиков и затраченном времени 
         PrintFormat("The tick history for the '%s' symbol is received in the amount of %u ticks in %d ms"symbolreceivedGetTickCount()-start);
         
         //--- если тиковая история синхронизирована, то код ошибки равен нулю - возвращаем true
         if(GetLastError()==0)
            return(true);
 
         PrintFormat("%s: Ticks are not synchronized yet, %d ticks received for %d ms. Error=%d"
                     symbolreceivedGetTickCount()-startGetLastError());
        }
      //--- считаем попытки 
      attempts++; 
      //--- пауза в 1 секунду в ожидании завершения синхронизации тиковой базы 
      Sleep(1000);
     }
//--- не удалось скопировать тики за 3 попытки
   return(false);
  }
//+------------------------------------------------------------------+ 
//| возвращает строковое описание тика                               | 
//+------------------------------------------------------------------+ 
string GetTickDescription(MqlTick &tick
  { 
   string desc=StringFormat("%s.%03u "TimeToString(tick.timeTIME_DATE|TIME_MINUTES|TIME_SECONDS),tick.time_msc%1000);
   
//--- проверим флаги тика
   bool buy_tick   = ((tick.flags &TICK_FLAG_BUY)   == TICK_FLAG_BUY); 
   bool sell_tick  = ((tick.flags &TICK_FLAG_SELL)  == TICK_FLAG_SELL); 
   bool ask_tick   = ((tick.flags &TICK_FLAG_ASK)   == TICK_FLAG_ASK); 
   bool bid_tick   = ((tick.flags &TICK_FLAG_BID)   == TICK_FLAG_BID); 
   bool last_tick  = ((tick.flags &TICK_FLAG_LAST)  == TICK_FLAG_LAST); 
   bool volume_tick= ((tick.flags &TICK_FLAG_VOLUME)== TICK_FLAG_VOLUME); 
   
//--- проверим сначала тик на торговые флаги (для CustomTicksAdd() их нет)
   if(buy_tick || sell_tick
     { 
      //--- сформируем вывод для торгового тика 
      desc += (buy_tick ? StringFormat("Buy Tick: Last=%G Volume=%d "tick.lasttick.volume)  : ""); 
      desc += (sell_tickStringFormat("Sell Tick: Last=%G Volume=%d ",tick.lasttick.volume) : ""); 
      desc += (ask_tick ? StringFormat("Ask=%G "tick.ask) : ""); 
      desc += (bid_tick ? StringFormat("Bid=%G "tick.ask) : ""); 
      desc += "(Trade tick)"
     } 
   else 
     { 
      //--- для инфо тика сформируем вывод немного иначе 
      desc += (ask_tick   ? StringFormat("Ask=%G ",  tick.ask)    : ""); 
      desc += (bid_tick   ? StringFormat("Bid=%G ",  tick.ask)    : ""); 
      desc += (last_tick  ? StringFormat("Last=%G "tick.last)   : ""); 
      desc += (volume_tickStringFormat("Volume=%d ",tick.volume): ""); 
      desc += "(Info tick)"
     } 
//--- вернем описание тика 
   return(desc); 
  } 

 

Смотри также

CustomRatesDelete, CustomRatesUpdate, CustomTicksReplace, CopyTicks, CopyTicksRange