Тестируем 'CopyTicks' - страница 41

 
Столкнулся с багом, когда CopyTicksRange возвращает все запрошенные тики верно, но при этом LastError == ERR_HISTORY_TIMEOUT(4403). 


 
fxsaber:

tkc-файлы разбиты по месяцам. Вопросы из-за этого

  1. Если на терминале еще не закачаны тиковые данные, то при вызове CopyTicks как терминал узнает, какие tkc-файлы тянуть?
Тянет каждый месяц, начиная с текущего.
  1. CopyTicksRange реализован на основе CopyTicks или же самостоятельно?
На основе CopyTicks, т.е. совсем не оптимизирован.
  1. Правильно ли понимаю, что получить тики за сентябрь, например, будет всегда быстрее через CopyTicksRange, чем через CopyTicks, т.к. CopyTicks не знает через входные параметры, за какой месяц нужно тянуть данные?

Нет, CopyTicksRange будет таким же тормозным из-за пункта выше. Вот скрипт, показывающий, некоторую абсурдность текущей реализации CopyTicksRange

#define TOSTRING(A) #A + " = " + (string)(A)

void OnStart()
{  
  
  MqlTick Ticks[];
  
  ResetLastError();
  
  Print(__FUNCTION__);
  Print(TOSTRING(CopyTicksRange(_Symbol, Ticks, COPY_TICKS_ALL, 1, 2)));
  Print(TOSTRING(_LastError));
}

Казалось бы четко дана информация, какие tkc-файлы нужно тянуть. Но нет, будет тянуть так же, как CopyTicks - все tkc-файлы. И прекратит работу по таймауту. Хотя на самом деле должен был отработать почти мгновенно.

  1. Нужно в индикаторе получить как можно быстрее историю. Есть возможность сделать запрос через CopyTicksRange и получить отлуп в виде -1, пока все не закачается. А если запрашивать по месяцу: текущий, затем предудыщий и т.д. То получится не медленнее же, но при этом индикатор будет готов работать хоть с какой-то историей.  Верно?

Без разницы, как оказалось (см. пункты выше).

 

CopyTicks не работает в OnDeinit в случаях, если UninitializeReason != REASON_CHARTCHANGE

#define TOSTRING(A) (#A + " = " + (string)(A))

void TickTest()
{
  MqlTick Ticks[];

  ResetLastError();
  Print(TOSTRING(CopyTicks(_Symbol, Ticks)));
  Print(TOSTRING(_LastError));
}

void OnInit()
{
  Print("\n" + __FUNCTION__);
  
  TickTest();
}

void OnDeinit( const int )
{
  Print("\n" + __FUNCTION__);
  Print(TOSTRING(UninitializeReason()));
  
  TickTest();
}


Результат (после снятия эксперта)

OnInit
CopyTicks(_Symbol,Ticks) = 2000
_LastError = 0

OnDeinit
UninitializeReason() = 1
CopyTicks(_Symbol,Ticks) = -1
_LastError = 4401


ЗЫ Это происходит в советниках. В индикаторах CopyTicks в OnDeinit отрабатывает нормально.

 
При смене счета (другой торговый сервер) нужно записать в файл последние 2000 тиков старого счета. Как это сделать?


Так не получится

void OnDeinit( const int )
{
  MqlTick Ticks[];

  CopyTicks(_Symbol, Ticks); // Если была смена торгового сервера, то БД-тиков поменялась

  FileSave(__FILE__, Ticks);
}


Прошу перед сменой счета генерировать событие CHARTEVENT_ACCOUNTCLOSING, при обработке которого (в OnChartEvent) все торговое окружение еще не переключилось на новое.

 
fxsaber:
При смене счета (другой торговый сервер) нужно записать в файл последние 2000 тиков старого счета. Как это сделать?


Так не получится


Прошу перед сменой счета генерировать событие CHARTEVENT_ACCOUNTCLOSING, при обработке которого (в OnChartEvent) все торговое окружение еще не переключилось на новое.

По уму, надо бы добавить обратную связь - как в том же виндоузе сделано.

В виде флага в событии графика (или не графика), при установке которого само событие (в данном случае, переключение счета) отменяется.

 

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

Утомляют такие приколы

#define TOSTRING(A) (#A + " = " + (string)(A))

void OnStart()
{
  MqlTick Ticks[];

  if (CopyTicks(_Symbol, Ticks, COPY_TICKS_ALL, 0, 131072 + 1) > 0) // Если прибавлять не единицу, а ноль, то все будет работать
  {
    const ulong BeginTime = Ticks[0].time_msc;
    
    Print(TOSTRING(CopyTicksRange(_Symbol, Ticks, COPY_TICKS_INFO, BeginTime, LONG_MAX)));
    Print(TOSTRING(CopyTicksRange(_Symbol, Ticks, COPY_TICKS_INFO, BeginTime, (TimeCurrent() + 1) * 1000)));
  }
}


Результат

CopyTicksRange(_Symbol,Ticks,COPY_TICKS_INFO,BeginTime,LONG_MAX) = 0
CopyTicksRange(_Symbol,Ticks,COPY_TICKS_INFO,BeginTime,(TimeCurrent()+1)*1000) = 131073


Убираем единицу из исходника

CopyTicksRange(_Symbol,Ticks,COPY_TICKS_INFO,BeginTime,LONG_MAX) = 131072
CopyTicksRange(_Symbol,Ticks,COPY_TICKS_INFO,BeginTime,(TimeCurrent()+1)*1000) = 131072


Воспроизводится на разных символах и торговых серверах. Проверял в выходной день - котиры стоят.


Когда баги победим в этой теме?

 

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

Такой вопрос. Загрузил тики ручками (685 007 шт.) через меню Символы. Мне нужны на EURUSD с 2016.11.01 00:00 по 2016.11.08 00:00. Вот скриншот.



Запрашиваю программно так:

void OnStart()
  {
   string symbol="EURUSD";
   MqlTick ticks_array[];
   uint flags=COPY_TICKS_INFO;
   ulong from_msc,to_msc;
   from_msc=(ulong)D'01.11.2016 00:00';
   to_msc=(ulong)D'08.11.2016 00:00';
//--- получить тики - 20 попыток
   for(int att=0;att<20;att++)
     {
      int copied=CopyTicksRange(symbol,ticks_array,flags,from_msc,to_msc);
      if(copied>0)
         break;
      Sleep(100);
     }
//--- остановка
   DebugBreak();
  }


На выходе 0. Что не так?

 
Dennis Kirichenko:

На выходе 0. Что не так?

На 1000 from и to умножьте.

 
fxsaber:

На 1000 from и to умножьте.


Блин, позор мне, зарапортовался. Спасибо.

 
Тучу времени потерял, чтобы локализовать этот баг CopyTicksRange


template <typename T>
T MyPrint( const T Value, const string Str )
{
  static const bool IsDebug = MQLInfoInteger(MQL_DEBUG);

//  if (IsDebug)
  {
//    DebugBreak(); // если хочется посмотреть средствами дебага

    Print(Str + " = " + (string)Value);
  }
  
  return(Value);
}

#define _P(A) MyPrint(A, __FUNCSIG__ ", Line = " + (string)__LINE__ + ": " + #A)

int GetSymbolTicks( const string Symb, MqlTick &Ticks[] )
{
  const bool Selected = SymbolInfoInteger(Symb, SYMBOL_SELECT);

  const int Amount = SymbolInfoInteger(Symb, SYMBOL_CUSTOM) && (Selected || SymbolSelect(Symb, true)) ? _P(CopyTicksRange(Symb, Ticks, COPY_TICKS_INFO)) : -1; // здесь баг!
  
  if (!Selected)
    SymbolSelect(Symb, false);

  return(Amount);
}

bool TicksToSymbol( const string Symb, const MqlTick &Ticks[] )
{
  const int Size = ArraySize(Ticks);
  
  CustomTicksDelete(Symb, Ticks[0].time_msc, Ticks[Size - 1].time_msc);
  
  return(Size ? (_P(CustomTicksReplace(Symb, Ticks[0].time_msc, Ticks[Size - 1].time_msc, Ticks)) > 0) : false);
}

void OnStart()
{
  MqlTick Ticks[];
    
  if (CopyTicksRange(_Symbol, Ticks, COPY_TICKS_INFO, D'2017.12.01' * 1000, (TimeCurrent() + 1) * 1000) > 100) // Если поставить сегодня - D'2017.12.05', то баг не проявится
  {
    ArrayResize(Ticks, 100);
    
    static const string Name = _Symbol + "_Custom";
    
    CustomSymbolDelete(Name);
    
    if (CustomSymbolCreate(Name) && CustomSymbolSetInteger(Name, SYMBOL_DIGITS, _Digits))
    {    
      TicksToSymbol(Name, Ticks);
    
      MqlTick Ticks2[];
      
      GetSymbolTicks(Name, Ticks2);
    }

    CustomSymbolDelete(Name);
  }
}

После первого запуска на EURUSD M1 MetaQuotes-Demo имеем верный результат

bool TicksToSymbol(const string,const MqlTick&[]), Line = 36: CustomTicksReplace(Symb,Ticks[0].time_msc,Ticks[Size-1].time_msc,Ticks) = 100
int GetSymbolTicks(const string,MqlTick&[]), Line = 22: CopyTicksRange(Symb,Ticks,COPY_TICKS_INFO) = 100


Все последующие запуски будут показывать баг

bool TicksToSymbol(const string,const MqlTick&[]), Line = 36: CustomTicksReplace(Symb,Ticks[0].time_msc,Ticks[Size-1].time_msc,Ticks) = 100
int GetSymbolTicks(const string,MqlTick&[]), Line = 22: CopyTicksRange(Symb,Ticks,COPY_TICKS_INFO) = 0


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


ЗЫ Обратите внимание на выделенный комментарий в исходнике!

Причина обращения: