Вопрос к разработчикам по порядку выдаваемых тиков функцией CopyTicksRange()

 

Вопрос к разработчикам терминала.

Верно ли, что функция CopyTicksRange() выдает тики c изменением Last & Volume с одинаковым временем в миллисекундах в произвольном порядке?

Наблюдаю, что в одних случаях в выданном массиве тики могут быть в порядке 1,2 , в другом случае 2,1.

При этом, если запрашивать тики с параметром COPY_TICKS_ALL тики с Ask & Bid всегда получаются в одинаковом порядке, однако в произвольном порядке между ними вставлены тики с изменением Last & Volume.

Например, есть тики с изменениями Ask& Bid ab1, ab2 и тики с изменениями Last&Volume lv1, lv2, lv3. Время в миллисекундах у них одинаковое.

Функция CopyTicksRange() может выдавать их в следующем порядке:

ab1

ab2

lv1

lv3

lv2

или

lv3

ab1

ab2

lv2

lv1

или

lv1

ab1

lv2

lv3

ab2

 

Билд 2007

Спасибо

 
Однозначность, конечно, должна быть. Но как было на самом деле - в MT5 нет данных. Все таки это два разных источника тиков.
 
fxsaber:
Однозначность, конечно, должна быть. Но как было на самом деле - в MT5 нет данных. Все таки это два разных источника тиков.

Вы тоже видели неправильный порядок?

 
Ilya Baranov:

Вы тоже видели неправильный порядок?

Не обращал на это внимание. Приходить в Терминал тики могут точно в другой последовательности, нежели храниться в истории.

Что касается истории, то лучше плясать от воспроизводимого примера на MQ-Demo.

 
fxsaber:

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

Мой вопрос про запросы истории. Два "одновременных" запроса из двух индикаторов возвращают массивы с разным порядком.

 

Уточню ситуацию.

Есть индикатор запрашивающий историю тиков при запуске. Он приложен на два одинаковых графика. Параметром у индикаторов установлена разная глубина запроса.

После запроса тики сохраняются в файл без какой-либо обработки. Открываю файлы, сравниваю, вижу, что набор тиков для каждом миллисекунды одинаков, однако порядок следования различен.

Кроме того видно, что для тиков с изменением Last & Volume поля Ask & Bid заполнены копированием с предыдущего тика с изменением Ask & Bid. Соответственно, если тик переставлен на другое место, то у него другое значение полей.

Аналогично у тиков с изменением Ask & Bid поля Last, Volume скопированы с предыдущего тика с изменением Last & Volume. Если тики Last & Volume переставлены в другом порядке, то в тиках Ask & Bid другие значения полей.

 

Прикрепите, пожалуйста, индикатор и файлы.


ЗЫ Этот скрипт проблему не показал

// Скрипт записывает TICKS_ALL-тики с определенной даты.
#property script_show_inputs

input datetime StartTime = D'01.02.2019';

string GetTickFlag( uint tickflag )
{
  string flag = " " + (string)tickflag;

#define TICKFLAG_MACRO(A) flag += ((bool)(tickflag & TICK_FLAG_##A)) ? " TICK_FLAG_" + #A : ""; \
                          tickflag -= tickflag & TICK_FLAG_##A;
  TICKFLAG_MACRO(BID)
  TICKFLAG_MACRO(ASK)
  TICKFLAG_MACRO(LAST)
  TICKFLAG_MACRO(VOLUME)
  TICKFLAG_MACRO(BUY)
  TICKFLAG_MACRO(SELL)
#undef TICKFLAG_MACRO

  if (tickflag)
    flag += " FLAG_UNKNOWN (" + (string)tickflag + ")";

  return(flag);
}

#define TOSTR(A) " " + #A + " = " + (string)Tick.A
#define TOSTR2(A) " " + #A + " = " + ::DoubleToString(Tick.A, _Digits)

string TickToString( const MqlTick &Tick )
{
  return(TOSTR(time) + "." + ::IntegerToString(Tick.time_msc % 1000, 3, '0') +
         TOSTR2(bid) + TOSTR2(ask) + TOSTR2(last)+ TOSTR(volume) + GetTickFlag(Tick.flags));
}

#undef TOSTR2
#undef TOSTR


int TicksToFile( const MqlTick &Ticks[], const string FileName )
{
  const int Size = ArraySize(Ticks);

  if (Size)
  {
    const int handle = FileOpen(FileName, FILE_WRITE | FILE_ANSI | FILE_TXT);

    if (handle != INVALID_HANDLE)
    {
      FileSeek(handle, 0, SEEK_END);

      for (int i = 0; i < Size; i++)
        FileWrite(handle, TickToString(Ticks[i]));

      FileClose(handle);
    }
  }

  return(Size);
}

void OnStart()
{
  MqlTick Ticks[];
  
  if (CopyTicksRange(_Symbol, Ticks, COPY_TICKS_ALL, (ulong)StartTime * 1000, LONG_MAX) > 0)
    TicksToFile(Ticks, _Symbol + "_" + TimeToString(StartTime, TIME_DATE) + ".csv");
}
 

Прикладываю код индикатора, воспроизводящего эффект.

Похоже, что эффект проявляется только после того, как будет сделан запрос тиков большой длины. Мне удалось поймать эффект при запросе 8000 минут (примерно 5 дней). Пока использовались запросы около 600 минут, проблема не воспроизводилась.

Сервер "AMPGlobalUSA-Demo"

Символ CLEJ19


Формат файла CSV, разделители - точка с запятой, поля: 

  • время;
  • ask;
  • bid;
  • last;
  • volume;
  • флаги.


Расшифровка флагов:

  • a - TICK_FLAG_ASK;
  • b - TICK_FLAG_BID;
  • l - TICK_FLAG_LAST;
  • v - TICK_FLAG_VOLUME;
  • B - TICK_FLAG_BUY;
  • S - TICK_FLAG_SELL.

В сохраненных файлах наблюдаю следующее (показаны данные за одну миллисекунду):

запрос 660 минут:

...

10:32:29.986; 56.61; 56.60; 56.60; 2.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 2.00; a     

10:32:29.986; 56.61; 56.60; 56.60; 1.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 2.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 1.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 2.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 1.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 4.00;   lv S

10:32:29.986; 56.60; 56.59; 56.60; 4.00; ab    

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 2.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB

..

 

Запрос 8000 минут:

...

10:32:29.986; 56.61; 56.60; 56.60; 2.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 1.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 2.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 1.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 2.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 1.00;   lv S

10:32:29.986; 56.61; 56.60; 56.60; 4.00;   lv S

10:32:29.986; 56.60; 56.59; 56.60; 4.00; ab    

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 2.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.60; 56.59; 56.60; 1.00;   lvB 

10:32:29.986; 56.61; 56.59; 56.60; 1.00; a     

...


Наблюдается перестановка тиков местами, включая тики ask & bid.

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

Предполагаю, что проблема воспроизведется и кодом скрипта, приложенным выше, в определенных условиях.


Кроме того, в определенных местах файла наблюдаю разницу в заполнении поля volume.

Запрос 660 минут:

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 2.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 2.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.52; 56.53; 0.00;  b    

10:53:38.443; 56.53; 56.52; 56.53; 0.00; a   

Запрос 8000 минут:

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 2.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 2.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.53; 56.53; 1.00;   lv S

10:53:38.441; 56.54; 56.52; 56.53; 1.00;  b    

10:53:38.443; 56.53; 56.52; 56.53; 1.00; a     


Сохраненные файлы в приложенном архиве.

Код индикатора:

#define PROGRAM_NAME "TICK_SEQ_IND"
#define VERSION "1.00"

//=====================================================================
//              Parameters
input uint      PShowMinutes = 60;                      //Show minutes

//=====================================================================
//              Indicator properties
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0

//=====================================================================

int OnInit(void)
{
        // Start time
        datetime startTime = TimeTradeServer() - PShowMinutes * 60;
        
        // Load ticks
        MqlTick ticks[];
        int loaded = CopyTicksRange( Symbol() , ticks , COPY_TICKS_ALL , startTime * 1000 , 0 );
        if ( loaded < 0 )
        {
                Print( "Error loading ticks" );
                return INIT_SUCCEEDED;
        }
        
        // Open file
        string fileName = "ticks" + IntegerToString( PShowMinutes ) + ".txt";
        int file = FileOpen( fileName , FILE_WRITE | FILE_TXT );
        if ( file == INVALID_HANDLE )
        {
                Print( "Error opening file" );
                return INIT_SUCCEEDED;          
        }
        
        // Saving ticks to file
        int nTick = ArraySize( ticks );
        for ( int iTick = 0 ;   iTick < nTick ;   iTick ++ )
        {
                saveTick( ticks[ iTick ] , file );
        }
        
        FileClose( file );
        Print( "Saved ticks " + IntegerToString( nTick ) );
        return INIT_SUCCEEDED;
}

void saveTick( const MqlTick& tick , int file_handle )
{
        // Запись в файлы
        int digits = (int) SymbolInfoInteger( Symbol() , SYMBOL_DIGITS );
        FileWriteString( file_handle , TimeToString( tick.time_msc / 1000 , TIME_MINUTES | TIME_SECONDS ) + "." + IntegerToString( tick.time_msc % 1000 , 3 , '0' ) );
        FileWriteString( file_handle , "; " );
        FileWriteString( file_handle , DoubleToString( tick.ask , digits ) );
        FileWriteString( file_handle , "; " );
        FileWriteString( file_handle , DoubleToString( tick.bid , digits ) );
        FileWriteString( file_handle , "; " );
        FileWriteString( file_handle , DoubleToString( tick.last , digits ) );
        FileWriteString( file_handle , "; " );
        FileWriteString( file_handle , DoubleToString( tick.volume , digits ) );
        FileWriteString( file_handle , "; " );
        string flags;
        flags += (bool) (  tick.flags & TICK_FLAG_ASK    ) ? "a" : " ";
        flags += (bool) (  tick.flags & TICK_FLAG_BID    ) ? "b" : " ";
        flags += (bool) (  tick.flags & TICK_FLAG_LAST   ) ? "l" : " ";
        flags += (bool) (  tick.flags & TICK_FLAG_VOLUME ) ? "v" : " ";
        flags += (bool) (  tick.flags & TICK_FLAG_BUY    ) ? "B" : " ";
        flags += (bool) (  tick.flags & TICK_FLAG_SELL   ) ? "S" : " ";
        FileWriteString( file_handle , flags );
        FileWriteString( file_handle , "\n" );  
}

void OnDeinit( const int reason )
{
}

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
        return rates_total;
}


 
Ilya Baranov:

Прикладываю код индикатора, воспроизводящего эффект.

Сервер и символ?

 
Ilya Baranov:

Сервер "AMPGlobalUSA-Demo"

Символ CLEJ19

 

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

Например, берем с 2019.03.07 и 2019.03.11 (сегодня)- битые тики за текущий день.

Берем с 2019.03.07 и 2019.03.08 - совпадающие тики за сегодня.


ЗЫ Интересный сервер - полно тиковой истории.