CustomTicksReplace

Полностью заменяет ценовую историю пользовательского инструмента в указанном временном интервале данными из массива типа MqlTick.

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

Параметры

symbol

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

from_msc

[in]  Время первого тика в ценовой истории из указанного диапазона, подлежащего удалению. Время в миллисекундах с 01.01.1970.

to_msc

[in]  Время последнего тика в ценовой истории из указанного диапазона, подлежащего удалению. Время в миллисекундах с 01.01.1970.

ticks[]

[in]   Массив тиковых данных типа MqlTick, упорядоченных по времени в порядке возрастания.

count=WHOLE_ARRAY

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

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

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

Примечание

Так как в потоке котировок нередко несколько тиков могут иметь одно и то же время с точностью до миллисекунды (точное время тика хранится в поле time_msc структры MqlTick), то функция CustomTicksReplace не делает автоматической сортировки элементов массива ticks[] по времени. Поэтому массив тиков должен быть предварительно упорядочен по возрастанию времени.

Замена тиков производится последовательно день за днём до времени указанного в to_msc либо до момента возникновения ошибки. Сначала обрабатывается первый день из указанного диапазона, затем следующий, и так далее.  Как только обнаружится несоответствие времени тика порядку возрастания (неубывания), то процесс замены тиков сразу же прекращается на текущем дне. При этом тики за предыдущие дни будут успешно заменены, а текущий день (на момент неправильного тика) и все оставшиеся дни в указанном интервале останутся без изменения.

Если в массиве ticks[] отсутствуют тиковые данные за какой-то день (вообще говоря, интервал любой длительности), то после применения тиковых данных из ticks[] в истории пользовательского инструмента образуется "дыра", соответствующая пропущенным данным. Другим словами, вызов CustomTicksReplace с вырезанными тиками за конкретный интервал будет равносильно удалению части тиковой истории как будто вызывается CustomTicksDelete с интервалом "дыры".

Если в базе тиков в указанном интервале времени данные отсутствуют, то CustomTicksReplace просто добавит в нее тики из массива ticks[].

Функция CustomTicksReplace работает напрямую с базой данных тиков.

 

Пример:

//+------------------------------------------------------------------+
//|                                           CustomTicksReplace.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].time,TIME_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]));
     }
 
//--- теперь поменяем значения Ask и Bid тиков в массиве по формуле Ask(Symbol) = 1.0 / Ask(Symbol), Bid(Symbol) = 1.0 / Bid(Symbol)
   for(int i=0i<totali++)
     {
      array[i].ask = (array[i].ask !=0 ? 1.0 / array[i].ask : array[i].ask);
      array[i].bid = (array[i].bid !=0 ? 1.0 / array[i].bid : array[i].bid);
     }
   Print("\nNow the ticks are changed");
 
//--- заменим тиковую историю пользовательского символа данными из изменённого массива тиков
   Print("...");
   start=GetTickCount();
   PrintFormat("Start replacing %u changed ticks in the history of the custom symbol '%s'"array.Size(), CUSTOM_SYMBOL_NAME);
   int replaced=CustomTicksReplace(CUSTOM_SYMBOL_NAMEarray[0].time_mscarray[total-1].time_mscarray);
   PrintFormat("Replaced %u ticks in the history of the custom symbol '%s' in %u ms"replacedCUSTOM_SYMBOL_NAMEGetTickCount()-start);
   
//--- получим в массив MqlTick только что заменённые данные тиков пользовательского символа
   Print("...");
   if(!GetTicksToArray(CUSTOM_SYMBOL_NAMEarray.Size(), array))
      return;
   
//--- распечатаем время первого и последнего полученных изменённых тиков пользовательского символа
   total=(int)array.Size();
   PrintFormat("First changed tick time: %s.%03u, Last changed 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 changed 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 Changed 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 get tick history for the symbol 'EURUSD'
   The tick history for the 'EURUSDsymbol is received in the amount of 351195822 ticks in 55735 ms
   First tick time2011.12.19 00:00:08.000Last tick time2024.06.21 08:39:03.113
   
   The last 20 ticks for the standard symbol 'EURUSD':
     351195802th Tick2024.06.21 08:38:10.076 Ask=1.07194 (Info tick)
     351195803th Tick2024.06.21 08:38:13.162 Ask=1.07195 (Info tick)
     351195804th Tick2024.06.21 08:38:13.872 Bid=1.07195 (Info tick)
     351195805th Tick2024.06.21 08:38:14.866 Ask=1.07194 Bid=1.07194 (Info tick)
     351195806th Tick2024.06.21 08:38:17.374 Bid=1.07194 (Info tick)
     351195807th Tick2024.06.21 08:38:18.883 Bid=1.07194 (Info tick)
     351195808th Tick2024.06.21 08:38:19.771 Bid=1.07194 (Info tick)
     351195809th Tick2024.06.21 08:38:20.873 Ask=1.07195 Bid=1.07195 (Info tick)
     351195810th Tick2024.06.21 08:38:22.278 Ask=1.07196 Bid=1.07196 (Info tick)
     351195811th Tick2024.06.21 08:38:22.775 Bid=1.07196 (Info tick)
     351195812th Tick2024.06.21 08:38:23.477 Bid=1.07196 (Info tick)
     351195813th Tick2024.06.21 08:38:38.194 Ask=1.07197 (Info tick)
     351195814th Tick2024.06.21 08:38:38.789 Ask=1.07196 (Info tick)
     351195815th Tick2024.06.21 08:38:39.290 Ask=1.07197 (Info tick)
     351195816th Tick2024.06.21 08:38:43.695 Ask=1.07196 (Info tick)
     351195817th Tick2024.06.21 08:38:52.203 Ask=1.07195 Bid=1.07195 (Info tick)
     351195818th Tick2024.06.21 08:38:55.105 Ask=1.07196 Bid=1.07196 (Info tick)
     351195819th Tick2024.06.21 08:38:57.607 Ask=1.07195 Bid=1.07195 (Info tick)
     351195820th Tick2024.06.21 08:39:00.512 Ask=1.07196 Bid=1.07196 (Info tick)
     351195821th Tick2024.06.21 08:39:03.113 Ask=1.07195 Bid=1.07195 (Info tick)
   ...
   Start of adding 351195822 ticks to the history of the custom symbol 'EURUSD.C'
   Added 351195822 ticks to the history of the custom symbol 'EURUSD.Cin 349407 ms
   ...
   Requested 351195822 ticks to get tick history for the symbol 'EURUSD.C'
   The tick history for the 'EURUSD.Csymbol is received in the amount of 351195822 ticks in 190203 ms
   First tick time2011.12.19 00:00:08.000Last tick time2024.06.21 08:39:03.113
   
   The last 20 ticks for the custom symbol 'EURUSD.C':
     351195802th Tick2024.06.21 08:38:10.076 Ask=1.07194 Bid=1.07194 (Info tick)
     351195803th Tick2024.06.21 08:38:13.162 Ask=1.07195 Bid=1.07195 (Info tick)
     351195804th Tick2024.06.21 08:38:13.872 Ask=1.07195 Bid=1.07195 (Info tick)
     351195805th Tick2024.06.21 08:38:14.866 Ask=1.07194 Bid=1.07194 (Info tick)
     351195806th Tick2024.06.21 08:38:17.374 Ask=1.07194 Bid=1.07194 (Info tick)
     351195807th Tick2024.06.21 08:38:18.883 Ask=1.07194 Bid=1.07194 (Info tick)
     351195808th Tick2024.06.21 08:38:19.771 Ask=1.07194 Bid=1.07194 (Info tick)
     351195809th Tick2024.06.21 08:38:20.873 Ask=1.07195 Bid=1.07195 (Info tick)
     351195810th Tick2024.06.21 08:38:22.278 Ask=1.07196 Bid=1.07196 (Info tick)
     351195811th Tick2024.06.21 08:38:22.775 Ask=1.07196 Bid=1.07196 (Info tick)
     351195812th Tick2024.06.21 08:38:23.477 Ask=1.07196 Bid=1.07196 (Info tick)
     351195813th Tick2024.06.21 08:38:38.194 Ask=1.07197 Bid=1.07197 (Info tick)
     351195814th Tick2024.06.21 08:38:38.789 Ask=1.07196 Bid=1.07196 (Info tick)
     351195815th Tick2024.06.21 08:38:39.290 Ask=1.07197 Bid=1.07197 (Info tick)
     351195816th Tick2024.06.21 08:38:43.695 Ask=1.07196 Bid=1.07196 (Info tick)
     351195817th Tick2024.06.21 08:38:52.203 Ask=1.07195 Bid=1.07195 (Info tick)
     351195818th Tick2024.06.21 08:38:55.105 Ask=1.07196 Bid=1.07196 (Info tick)
     351195819th Tick2024.06.21 08:38:57.607 Ask=1.07195 Bid=1.07195 (Info tick)
     351195820th Tick2024.06.21 08:39:00.512 Ask=1.07196 Bid=1.07196 (Info tick)
     351195821th Tick2024.06.21 08:39:03.113 Ask=1.07195 Bid=1.07195 (Info tick)
   
   Now the ticks are changed
   ...
   Start replacing 351195822 changed ticks in the history of the custom symbol 'EURUSD.C'
   Replaced 351195822 ticks in the history of the custom symbol 'EURUSD.Cin 452266 ms
   ...
   Requested 351195822 ticks to get tick history for the symbol 'EURUSD.C'
   The tick history for the 'EURUSD.Csymbol is received in the amount of 351195822 ticks in 199812 ms
   First changed tick time2011.12.19 00:00:08.000Last changed tick time2024.06.21 08:39:03.113
   
   The last 20 changed ticks for the custom symbol 'EURUSD.C':
     351195802th Changed tick2024.06.21 08:38:10.076 Ask=0.93289 Bid=0.93289 (Info tick)
     351195803th Changed tick2024.06.21 08:38:13.162 Ask=0.93288 Bid=0.93288 (Info tick)
     351195804th Changed tick2024.06.21 08:38:13.872 Ask=0.93288 Bid=0.93288 (Info tick)
     351195805th Changed tick2024.06.21 08:38:14.866 Ask=0.93289 Bid=0.93289 (Info tick)
     351195806th Changed tick2024.06.21 08:38:17.374 Ask=0.93289 Bid=0.93289 (Info tick)
     351195807th Changed tick2024.06.21 08:38:18.883 Ask=0.93289 Bid=0.93289 (Info tick)
     351195808th Changed tick2024.06.21 08:38:19.771 Ask=0.93289 Bid=0.93289 (Info tick)
     351195809th Changed tick2024.06.21 08:38:20.873 Ask=0.93288 Bid=0.93288 (Info tick)
     351195810th Changed tick2024.06.21 08:38:22.278 Ask=0.93287 Bid=0.93287 (Info tick)
     351195811th Changed tick2024.06.21 08:38:22.775 Ask=0.93287 Bid=0.93287 (Info tick)
     351195812th Changed tick2024.06.21 08:38:23.477 Ask=0.93287 Bid=0.93287 (Info tick)
     351195813th Changed tick2024.06.21 08:38:38.194 Ask=0.93286 Bid=0.93286 (Info tick)
     351195814th Changed tick2024.06.21 08:38:38.789 Ask=0.93287 Bid=0.93287 (Info tick)
     351195815th Changed tick2024.06.21 08:38:39.290 Ask=0.93286 Bid=0.93286 (Info tick)
     351195816th Changed tick2024.06.21 08:38:43.695 Ask=0.93287 Bid=0.93287 (Info tick)
     351195817th Changed tick2024.06.21 08:38:52.203 Ask=0.93288 Bid=0.93288 (Info tick)
     351195818th Changed tick2024.06.21 08:38:55.105 Ask=0.93287 Bid=0.93287 (Info tick)
     351195819th Changed tick2024.06.21 08:38:57.607 Ask=0.93288 Bid=0.93288 (Info tick)
     351195820th Changed tick2024.06.21 08:39:00.512 Ask=0.93287 Bid=0.93287 (Info tick)
     351195821th Changed tick2024.06.21 08:39:03.113 Ask=0.93288 Bid=0.93288 (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, CustomTicksDelete, CopyTicks, CopyTicksRange