Особенности языка mql5, тонкости и приёмы работы - страница 33

fxsaber
14380
fxsaber  
Artyom Trishkin:

Выделенное может возвращать 0. В БКС столкнулся.

Ага, криворукие брокеры. Они бы еще туда отрицательные числа запихали.

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

Alexey Kozitsyn
9790
Alexey Kozitsyn  
Artyom Trishkin:

Что именно не так? Именно вопрос и звучал - что делаю не так для получения данных индикатора с неродного таймфрейма?

Пример: индикатор запущен на М1, а данные от АО нужно получать с М5. Так вот - пока у нас limit>1 (нужно пересчитать историю), то АО с М5 возвращает нули с ошибкой отсутствия данных. Как только история вся просчитана (limit==0), то данные от АО с М5 начинают поступать.

Для начала - не нужно делать такие записи:

periodForWork=PeriodForWork;

Я сначала подумал, что Вы присваиваете переменной ее же значение.

Далее:

size_ao=CopyBuffer(handle_ao,0,0,count,array_ao);

Не нужно копирование производить при инициализации. Инициализация не для этого. Тем более эта запись не будет иметь смысла при запросе данных со старших ТФ, которые еще не будут рассчитаны на момент запроса из OnInit().

ArraySetAsSeries(BufferAO,true);

А вот эту запись как раз достаточно один раз сделать на этапе инициализации.

Дальше... гм... субъективно, я бы сделал не так.

Мне нравится разбивать программу на:

1. Первый запуск (анализ истории);

2. Последующие запуски:

2.1. Каждый тик;

2.2. Сформировавшийся бар;

Т.е:

if( prev_calculated > 0 )             // Не первый запуск
{
 if( rates_total <= prev_calculated ) // Новый бар не сформирован
  {
  }
 else                                 // Новый бар сформирован
  {
  }
}
else                                  // Первый запуск
{
}

И только после - основной цикл (функция) расчетов.

Copy-функции у Вас выдают не информативные ошибки. Просто код - не очень. 

Нет проверки синхронизации данных старшего ТФ.

А самое важное здесь - это разобраться с последовательностью. Советую создать тестовый индикатор, чтобы он только запрашивал данные старшего ТФ при первом запуске и разобраться, как происходит копирование. Т.е. убрать из начала кода вот это:

ArraySetAsSeries(array_ao,true);

И сделать распринтовку первого и последнего элемента массива. И только потом, если это необходимо, менять направление индексации.

Alexey Kozitsyn
9790
Alexey Kozitsyn  
В общем, начните с этого:
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
input   ENUM_TIMEFRAMES inpTimeframe=PERIOD_M5;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int _handle;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   _handle=iAO(_Symbol,inpTimeframe);
   if(_handle==INVALID_HANDLE)
     {
      Print(__FUNCTION__,": ОШИБКА #",GetLastError(),"! Хэндл индикатора iAO ТФ "+EnumToString(inpTimeframe)+" не получен!");
      return( INIT_FAILED );
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//--- Массив-приемник значений индикатора
   double ao[];
//---
   if(prev_calculated>0)
     {

     }
   else                                        // Если первый запуск
     {
      //--- Количество просчитанных баров старшего ТФ
      int bars;
      if(( bars=BarsCalculated(_handle))<0 || !(bool)SeriesInfoInteger(_Symbol,inpTimeframe,SERIES_SYNCHRONIZED))
         return( 0 );
      //--- 
      int num=CopyBuffer(_handle,0,0,bars,ao);
      //---
      if(num<0)
        {
         Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": Запрашиваемая таймсерия еще не построена!");
         return( 0 );
        }
      else if(num!=bars)
        {
         Print(__FUNCTION__,": ОШИБКА #",GetLastError(),": Скопированы не все данные (",num," из ",bars,")");
         return( 0 );
        }
      //---
      Print(__FUNCTION__,": Успех! Скопировано ",num," из ",bars," значение индикатора АО ТФ "+EnumToString(inpTimeframe));
     }
//---
   return( rates_total );
  }
//+------------------------------------------------------------------+
Artyom Trishkin
Модератор
123705
Artyom Trishkin  
Alexey Kozitsyn:

Для начала - не нужно делать такие записи:

Я сначала подумал, что Вы присваиваете переменной ее же значение.

Далее:

Не нужно копирование производить при инициализации. Инициализация не для этого. Тем более эта запись не будет иметь смысла при запросе данных со старших ТФ, которые еще не будут рассчитаны на момент запроса из OnInit().

А вот эту запись как раз достаточно один раз сделать на этапе инициализации.

Дальше... гм... субъективно, я бы сделал не так.

Мне нравится разбивать программу на:

1. Первый запуск (анализ истории);

2. Последующие запуски:

2.1. Каждый тик;

2.2. Сформировавшийся бар;

Т.е:

И только после - основной цикл (функция) расчетов.

Copy-функции у Вас выдают не информативные ошибки. Просто код - не очень. 

Нет проверки синхронизации данных старшего ТФ.

А самое важное здесь - это разобраться с последовательностью. Советую создать тестовый индикатор, чтобы он только запрашивал данные старшего ТФ при первом запуске и разобраться, как происходит копирование. Т.е. убрать из начала кода вот это:

И сделать распринтовку первого и последнего элемента массива. И только потом, если это необходимо, менять направление индексации.

Делаю переменные такими, которые с первого взгляда понятны мне. Вам не понятны - делайте их такими, которые понятны вам ;)

Начинаю писать не глобальные переменные всегда с маленькой буквы - причина проста: регистрозависимый интеллиенс...

Это и есть тестовый код, так как не тестовый - достаточно большой, и на МТ4 летает при переключении тф, и нет ошибок отсутствия данных - всё всегда есть. В МТ5 же при переключении тф только по полминуты грузит историю, а потом ещё и не работает с данными не своего тф - говорит про их отсутствие.

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

Опять что-то не то думаю?

kaus_bonus
105
kaus_bonus  
Artyom Trishkin:

В МТ5 же при переключении тф только по полминуты грузит историю


писал об этом

я правильно понимаю тогда, что подготовив кэш,терминал при последующих обращениях (начиная со 2 обращения) затрачивает на порядки меньше времени?

можно ли как-то уменьшить время первого обращения после перезагрузки терминала,чтобы было как в МТ4?
Теперь выводы:

    Разница только в скорости начальной инициализации кеша чарта 0.6 мс МТ4 против 113 мс у МТ5

подробней тут

https://www.mql5.com/ru/forum/1111/page1871#comment_4866969

https://www.mql5.com/ru/forum/1111/page1871#comment_4867939

такое есть и будет. чем больше ТФ или символов будет запрашивать,тем более тормозное начало работы будет.

Ошибки, баги, вопросы
Ошибки, баги, вопросы
  • www.mql5.com
Форум алго-трейдеров MQL5
Artyom Trishkin
Модератор
123705
Artyom Trishkin  
kaus_bonus:


писал об этом

подробней тут

https://www.mql5.com/ru/forum/1111/page1871#comment_4866969

https://www.mql5.com/ru/forum/1111/page1871#comment_4867939

такое есть и будет. чем больше ТФ или символов будет запрашивать,тем более тормозное начало работы будет.

Да хорошо бы если б только при первом запуске индикатора. У меня же пока при каждом переключении таймфрейма грузится история по пол-минуты. Понимаю, что такого быть не должно, но ... что-то не то делаю что-ли... Причём лишь на одном индикаторе такое - в котором пытаюсь получить доступ к неродному таймфрейму.
kaus_bonus
105
kaus_bonus  
Artyom Trishkin:
Да хорошо бы если б только при первом запуске индикатора. У меня же пока при каждом переключении таймфрейма грузится история по пол-минуты. Понимаю, что такого быть не должно, но ... что-то не то делаю что-ли... Причём лишь на одном индикаторе такое - в котором пытаюсь получить доступ к неродному таймфрейму.

ну замерьте скорость копирования данных с другого ТФ и посмотрите,где узкое место. 
Alexey Kozitsyn
9790
Alexey Kozitsyn  
Artyom Trishkin:

Если для расчетов нужно использовать несколько индикаторов с разных ТФ - нужно получить хэндл каждого ТФ.

Если хотите, чтобы все быстрее считалось - уменьшите размер истории в терминале.

Вы запустили мой тестовый индикатора? Данные собираются?

Artyom Trishkin
Модератор
123705
Artyom Trishkin  
Alexey Kozitsyn:

Если для расчетов нужно использовать несколько индикаторов с разных ТФ - нужно получить хэндл каждого ТФ.

Если хотите, чтобы все быстрее считалось - уменьшите размер истории в терминале.

Вы запустили мой тестовый индикатора? Данные собираются?

Нет, не запускал ещё.

Получается, что если нужны ВСЕ таймфреймы, то нужно создать 21 хэндл индикатора АО? Это не расточительно?

Alexey Kozitsyn
9790
Alexey Kozitsyn  
Artyom Trishkin:

Нет, не запускал ещё.

Получается, что если нужны ВСЕ таймфреймы, то нужно создать 21 хэндл индикатора АО? Это не расточительно?

А как иначе получить данные с нужного символа/ТФ? CopyBuffer работает только с хэндлами.