CopyTicks

Функция получает в массив ticks_array тики в формате MqlTick, при этом индексация ведётся от прошлого к настоящему, то есть тик с индексом 0 является самым старым в массиве. Для анализа тика необходимо проверять поле flags, которое сообщает, что именно было изменено в данном тике.

int  CopyTicks(
   string           symbol_name,           // имя символа
   MqlTick&         ticks_array[],         // массив для приёма тиков
   uint             flags=COPY_TICKS_ALL,  // флаг, определяющий тип получаемых тиков
   ulong            from=0,                // дата, начиная с которой запрашиваются тики
   uint             count=0                // количество тиков, которые необходимо получить
   );

Параметры

symbol_name

[in]  Символ.

ticks_array

[out]  Массив типа MqlTick для приема тиков.

flags

[in]  Флаг, определяющий тип запрашиваемых тиков. COPY_TICKS_INFO – тики, вызванные изменениями Bid и/или Ask, COPY_TICKS_TRADE – тики с изменения Last и Volume, COPY_TICKS_ALL – все тики. При любом типе запроса в оставшиеся поля структуры MqlTick дописываются значения предыдущего тика.

from

[in]  Дата, начиная с которой запрашиваются тики. Указывается в миллисекундах с 01.01.1970. Если параметр from=0, то отдаются последние count тиков.

count

[in]  Количество запрашиваемых тиков. Если параметры from и count не указаны, то в массив ticks_array[] будут записаны все доступные последние тики, но не более 2000.

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

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

Примечание

Функция CopyTicks() позволяет запрашивать и анализировать все пришедшие тики. Первый вызов CopyTicks() инициирует синхронизацию базы тиков, хранящихся на жёстком диске по данному символу. Если тиков в локальной базе не хватает, то недостающие тики автоматически будут загружены с торгового сервера. При этом будут синхронизированы тики с даты from, указанной в  CopyTicks(), по текущий момент. После этого все приходящие по данному символу тики будут поступать в тиковую базу и поддерживать её в актуальном синхронизированном состоянии.

Если параметры from и count не указаны, то в массив ticks_array[] будут записаны все доступные тики, но не более 2000. Параметр flags позволяет задать тип требуемых тиков.

COPY_TICKS_INFO – отдаются тики, в которых есть изменения цены Bid и/или Ask. Но при этом будут также заполнены данные остальных полей, например, если изменилась только цена Bid, то в поля ask и volume будут записаны  последние известные значения. Чтобы узнать точно, что именно изменилось, необходимо анализировать поле flags, которое будет иметь значение  TICK_FLAG_BID и/или TICK_FLAG_ASK.  Если тик имеет нулевые значения цен Bid и Ask, и при этом флаги показывают, что эти данные цены изменились (flags=TICK_FLAG_BID|TICK_FLAG_ASK), то это говорит об опустошении стакана заявок. Другими словами,  в этот момент отсутствуют заявки на покупку и  продажи.

COPY_TICKS_TRADE – отдаются тики, в которых есть изменения последней цены сделки и объема. Но при этом будут также заполнены данные остальных полей, то есть в поля Bid и Ask будут записаны  последние известные значения. Чтобы узнать точно, что именно изменилось, необходимо анализировать поле flags, которое будет иметь значение TICK_FLAG_LAST и TICK_FLAG_VOLUME.

COPY_TICKS_ALL – отдаются все тики, в которых есть хоть какое-то изменение. При этом неизмененные поля также заполняются последними известными значениями.

Вызов CopyTicks() с флагом  COPY_TICKS_ALL выдает сразу все тики из запрашиваемого диапазона, в то время как вызов в других режимах требует некоторого времени на предобработку и выборку тиков, и поэтому не даёт существенного выигрыша по скорости выполнения.

При запросе тиков (неважно, COPY_TICKS_INFO или COPY_TICKS_TRADE), в каждом тике содержится полная ценовая информация на момент тика (bid, ask, last и volume). Это сделано для удобства анализа торговой обстановки на момент каждого тика, чтобы не приходилось каждый раз запрашивать глубокую тиковую историю и искать в ней значения по другим полям.

В индикаторах функция CopyTicks() возвращает результат немедленно: При вызове из индикатора CopyTick() сразу же вернёт доступные по символу тики, а также запустит синхронизацию базы тиков, если данных не хватило. Все индикаторы на одном символе работают в одном общем потоке, поэтому  индикатор не имеет права ждать завершения синхронизации. После окончания синхронизации при последующем вызове CopyTicks() вернёт все запрашиваемые тики. Функция OnCalculate() в индикаторах вызывается после поступления каждого тика.

В экспертах и скриптах функция CopyTicks() может дожидаться результата до 45 секунд: В отличие от индикатора каждый эксперт и скрипт работает в собственном потоке, и поэтому может дожидаться окончания синхронизации до 45 секунд. Если за это время тики так и не будут синхронизированы в необходимом объёме, то CopyTicks() по таймауту вернёт только имеющиеся в наличии тики, при этом синхронизация продолжится. Функция OnTick() в экспертах не является обработчиком каждого тика, она лишь уведомляет эксперта об изменениях на рынке. Изменения могут быть пакетными: в терминал может одновременно прийти несколько тиков, но функция OnTick() будет вызвана лишь один раз для уведомления эксперта о последнем состоянии рынка.

Скорость выдачи: терминал хранит по каждому символу 4096 последних тиков в кеше для быстрого доступа (для символов с запущенным стаканом – 65536 тиков), запросы к этим данным выполняются быстрее всего. При запросе тиков текущей торговой сессии за пределами кеша CopyTicks() обращается уже к тикам, которые хранятся в памяти терминала, эти запросы требуют большего времени на выполнение. Самыми медленными являются запросы тиков за другие дни, так как в этом случае данные читаются уже с диска.

Пример:

#property copyright "Copyright 2000-2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
//--- запрашиваем 100 миллионов тиков, чтобы гарантировать получение всей тиковой истории
input int      getticks=100000000; // сколько тиков требуется
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---  
   int     attempts=0;     // счетчик попыток
   bool    success=false;  // флаг успешного выполнения копирования тиков
   MqlTick tick_array[];   // массив для приема тиков
   MqlTick lasttick;       // для получения данных последнего тика
   SymbolInfoTick(_Symbol,lasttick);
//--- сделаем 3 попытки получить тики
   while(attempts<3)
     {
      //--- замерим время старта перед получением тиков
      uint start=GetTickCount();
//--- запросим тиковую историю с момента 1970.01.01 00:00.001 (параметр from=1 ms)
      int received=CopyTicks(_Symbol,tick_array,COPY_TICKS_ALL,1,getticks);
      if(received!=-1)
        {
         //--- выведем информацию о количестве тиков и затраченном времени времени
         PrintFormat("%s: received %d ticks in %d ms",_Symbol,received,GetTickCount()-start);
         //--- если тиковая история синхронизирована, то код ошибки равен нулю
         if(GetLastError()==0)
           {
            success=true;
            break;
           }
         else
            PrintFormat("%s: Ticks are not synchronized yet, %d ticks received for %d ms. Error=%d",
            _Symbol,received,GetTickCount()-start,_LastError);
        }
      //--- считаем попытки
      attempts++;
      //--- пауза в 1 секунду в ожидании завершения синхронизации тиковой базы
      Sleep(1000);
     }
//--- не удалось получить запрошенные тики от самого начала истории с трех попыток 
   if(!success)
     {
      PrintFormat("Ошибка! Не удалось получить %d тиков по %s с трех попыток",getticks,_Symbol);
      return;
     }
   int ticks=ArraySize(tick_array);
//--- выведем время первого тика в массиве
   datetime firstticktime=tick_array[ticks-1].time;
   PrintFormat("Last tick time = %s.%03I64u",
               TimeToString(firstticktime,TIME_DATE|TIME_MINUTES|TIME_SECONDS),tick_array[ticks-1].time_msc%1000);
//--- выведем время последнего тика в массиве
   datetime lastticktime=tick_array[0].time;
   PrintFormat("First tick time = %s.%03I64u",
               TimeToString(lastticktime,TIME_DATE|TIME_MINUTES|TIME_SECONDS),tick_array[0].time_msc%1000);
 
//---                                                           
   MqlDateTime today;
   datetime current_time=TimeCurrent();                         
   TimeToStruct(current_time,today);                            
   PrintFormat("current_time=%s",TimeToString(current_time));   
   today.hour=0;
   today.min=0;
   today.sec=0;
   datetime startday=StructToTime(today);
   datetime endday=startday+24*60*60;
   if((ticks=CopyTicksRange(_Symbol,tick_array,COPY_TICKS_ALL,startday*1000,endday*1000))==-1) 
     {
      PrintFormat("CopyTicksRange(%s,tick_array,COPY_TICKS_ALL,%s,%s) failed, error %d",       
                  _Symbol,TimeToString(startday),TimeToString(endday),GetLastError());          
      return;                                                                                  
     }
   ticks=MathMax(100,ticks); 
//--- теперь выведем первые 100 тиков последнего дня
   int counter=0;
   for(int i=0;i<ticks;i++)
     {
      datetime time=tick_array[i].time;
      if((time>=startday) && (time<endday) && counter<100)
        {
         counter++;
         PrintFormat("%d. %s",counter,GetTickDescription(tick_array[i]));
        }
     }
//--- выведем первые 100 сделок последнего дня
   counter=0;
   for(int i=0;i<ticks;i++)
     {
      datetime time=tick_array[i].time;
      if((time>=startday) && (time<endday) && counter<100)
        {
         if(((tick_array[i].flags&TICK_FLAG_BUY)==TICK_FLAG_BUY) || ((tick_array[i].flags&TICK_FLAG_SELL)==TICK_FLAG_SELL))
           {
            counter++;
            PrintFormat("%d. %s",counter,GetTickDescription(tick_array[i]));
           }
        }
     }
  }
//+------------------------------------------------------------------+
//| возвращает строковое описание тика                               |
//+------------------------------------------------------------------+
string GetTickDescription(MqlTick &tick)
  {
   string desc=StringFormat("%s.%03d ",
                            TimeToString(tick.time),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);
//--- проверим сначала тик на торговые флаги
   if(buy_tick || sell_tick)
     {
      //--- сформируем вывод для торгового тика
      desc=desc+(buy_tick?StringFormat("Buy Tick: Last=%G Volume=%d ",tick.last,tick.volume):"");
      desc=desc+(sell_tick?StringFormat("Sell Tick: Last=%G Volume=%d ",tick.last,tick.volume):"");
      desc=desc+(ask_tick?StringFormat("Ask=%G ",tick.ask):"");
      desc=desc+(bid_tick?StringFormat("Bid=%G ",tick.ask):"");
      desc=desc+"(Trade tick)";
     }
   else
     {
      //--- для инфо тика сформируем вывод немного иначе
      desc=desc+(ask_tick?StringFormat("Ask=%G ",tick.ask):"");
      desc=desc+(bid_tick?StringFormat("Bid=%G ",tick.ask):"");
      desc=desc+(last_tick?StringFormat("Last=%G ",tick.last):"");
      desc=desc+(volume_tick?StringFormat("Volume=%d ",tick.volume):"");
      desc=desc+"(Info tick)";
     }
//--- вернем описание тика
   return desc;
  }
//+------------------------------------------------------------------+
/* Пример вывода
Si-12.16: received 11048387 ticks in 4937 ms
Last tick time = 2016.09.26 18:32:59.775 
First tick time = 2015.06.18 09:45:01.000 
1.  2016.09.26 09:45.249 Ask=65370 Bid=65370 (Info tick)
2.  2016.09.26 09:47.420 Ask=65370 Bid=65370 (Info tick)
3.  2016.09.26 09:50.893 Ask=65370 Bid=65370 (Info tick)
4.  2016.09.26 09:51.827 Ask=65370 Bid=65370 (Info tick)
5.  2016.09.26 09:53.810 Ask=65370 Bid=65370 (Info tick)
6.  2016.09.26 09:54.491 Ask=65370 Bid=65370 (Info tick)
7.  2016.09.26 09:55.913 Ask=65370 Bid=65370 (Info tick)
8.  2016.09.26 09:59.350 Ask=65370 Bid=65370 (Info tick)
9.  2016.09.26 09:59.678 Bid=65370 (Info tick)
10. 2016.09.26 10:00.000 Sell Tick: Last=65367 Volume=3 (Trade tick)
11. 2016.09.26 10:00.000 Sell Tick: Last=65335 Volume=45 (Trade tick)
12. 2016.09.26 10:00.000 Sell Tick: Last=65334 Volume=95 (Trade tick)
13. 2016.09.26 10:00.191 Sell Tick: Last=65319 Volume=1 (Trade tick)
14. 2016.09.26 10:00.191 Sell Tick: Last=65317 Volume=1 (Trade tick)
15. 2016.09.26 10:00.191 Sell Tick: Last=65316 Volume=1 (Trade tick)
16. 2016.09.26 10:00.191 Sell Tick: Last=65316 Volume=10 (Trade tick)
17. 2016.09.26 10:00.191 Sell Tick: Last=65315 Volume=5 (Trade tick)
18. 2016.09.26 10:00.191 Sell Tick: Last=65313 Volume=3 (Trade tick)
19. 2016.09.26 10:00.191 Sell Tick: Last=65307 Volume=25 (Trade tick)
20. 2016.09.26 10:00.191 Sell Tick: Last=65304 Volume=1 (Trade tick)
21. 2016.09.26 10:00.191 Sell Tick: Last=65301 Volume=1 (Trade tick)
22. 2016.09.26 10:00.191 Sell Tick: Last=65301 Volume=10 (Trade tick)
23. 2016.09.26 10:00.191 Sell Tick: Last=65300 Volume=5 (Trade tick)
24. 2016.09.26 10:00.191 Sell Tick: Last=65300 Volume=1 (Trade tick)
25. 2016.09.26 10:00.191 Sell Tick: Last=65300 Volume=6 (Trade tick)
26. 2016.09.26 10:00.191 Sell Tick: Last=65299 Volume=1 (Trade tick)
27. 2016.09.26 10:00.191 Bid=65370 (Info tick)
28. 2016.09.26 10:00.232 Ask=65297 (Info tick)
29. 2016.09.26 10:00.276 Sell Tick: Last=65291 Volume=31 (Trade tick)
30. 2016.09.26 10:00.276 Sell Tick: Last=65290 Volume=1 (Trade tick)
*/

Смотри также

SymbolInfoTick, Структура для получения текущих цен, OnTick()