Кто-нибудь знает, как разработать мультивалютный индикатор?

 
Кто-нибудь знает, как разработать мультивалютный индикатор?

Я хочу выбрать от 1 до 10 различных валют и 5 баров для каждой валюты.

Но я не знаю, как это сделать.

 

В стандартном индикаторе буферные массивы формируются из данных параметров, передаваемых через функцию события OnCalulate( ... ). Но для мультивалютного и/или мультитаймфреймового индика тора вам придется использовать одно из двух решений:

  • Использование старого метода вариаций "iFunction", таких как iTime(), iVolume, iOpen, iClose и т.д., но с другим символом, таким как "EURUSD", "JPYUSD" и т.д. вместо стандартного _Symbol или Symbol().
  • Используя более новый метод первого варианта функции ArrayCopyRates() вместе с указателями массивов MqlRates, "скопированные" массивы фактически не будут занимать места и будут просто указателями на существующие данные различных символов и тайм-фреймов.

Однако, чтобы это работало, для работы мульти-символа и/или мульти-таймфрейма должно существовать одно из двух условий:

  • Либо соответствующие графики для символов и тайм-фреймов уже открыты, так что ошибка не возникает,
  • иначе при первом запросе данных вы получите ошибку 4066 (ERR_HISTORY_WILL_UPDATED), и вам придется кодировать цикл sleep & retry, чтобы дождаться загрузки данных и затем снова запросить данные.

Мое личное решение, которое я считаю наиболее эффективным и простым способом обработки ошибки 4066, - это метод ArrayCopyRates() и MqlRates .

Более подробную информацию об этом можно найти в документации и файлах справки по MQL4.

PS! NB! При обращении к встроенным функциям индикаторов, таким как iMA(), iATR() и т.д. для различных символов и тайм-фреймов, не забудьте также реализовать циклы sleep и retry, чтобы не получить ошибку 4066. Вот цитата из документа MQL4:

Any indicator can be calculated on the data of not only current chart, but also on the data of any available symbol/period. If data (symbol name and/or timeframe differ from the current ones) are requested from another chart, the situation is possible that the corresponding chart was not opened in the client terminal and the necessary data must be requested from the server. In this case, error ERR_HISTORY_WILL_UPDATED (4066 - the requested history data are under updating) will be placed in the last_error variable, and one will has to re-request (see example of ArrayCopySeries())
 
Помните, что ОП спрашивает об индикаторе. Sleep() игнорируется в индикаторах
 
GumRai:
Помните, что ОП спрашивает об индикаторе. Sleep() игнорируется в индикаторах.

Извините, не знал этого! Я использую этот метод довольно широко в советниках, но не в индикаторах, поэтому не знал о недостатке сна.

В этом случае ему придется построить цикл повтора вокруг последовательных вызовов на каждом тике функции OnCalculate() (где использование ArrayCopyRates() является лучшим решением).

В качестве альтернативы, если он работает в функции OnInit(), это может быть предпочтительным методом подготовки данных для индикатора, с очень длинным количеством повторных попыток (без сна) для этого случая.

 
FMIC:

...

  • или вы получите ошибку 4066 (ERR_HISTORY_WILL_UPDATED) при первом запросе данных, и вам придется закодировать цикл sleep & retry, чтобы дождаться загрузки данных и затем снова запросить данные.

PS! NB! При обращении к встроенным функциям индикаторов, таким как iMA(), iATR() и т.д. для различных символов и тайм-фреймов, не забудьте также реализовать циклы sleep и retry, чтобы не получить ошибку 4066. Вот цитата из документа MQL4:


Если только они не изменили что-то в последнее время, вы будете получать ошибку 4066 каждый раз с первого вызова функции (и только с этого первого вызова), независимо от условий или хода обновления истории. Это не имеет никакого практического применения.
 
Ovo:
Если только они не изменили что-то недавно, вы будете получать ошибку 4066 каждый раз с первого вызова функции (и только с этого первого вызова), независимо от условий или хода обновления истории. Это не имеет практического применения.
Со мной такого не происходило. Когда данные уже полностью доступны, я не получаю ошибку 4066. Однако, если они не доступны напрямую, то да, я получаю ошибку только при первом вызове любой функции для данного символа и таймфрейма. После этого любая другая функция, запрашивающая эти данные, больше не выдает ошибку.
 

FMIC:

В этом случае ему придется построить цикл повторного вызова вокруг последовательных вызовов на каждом тике функции OnCalculate() (где использование ArrayCopyRates() является лучшим решением).

В качестве альтернативы, если это работает в функции OnInit(), это может быть предпочтительным методом подготовки данных для индикатора, с очень длинным счетом повторных попыток (без sleep) для этого случая.

  1. Цикл (длинный или иной) в индикаторе не будет работать. Пока индикатор работает, ничего другого в терминале происходить не может. Вот почему Sleep не может работать в индикаторах. И почему ArrayCopyRates является асинхронным (для индикаторов).
  2. Включите массив ставок в init. Протестируйте его в OnTick и обработайте повторы там. Также помните, что разные графики создают новые бары в разное время.
    string pairs[] = {"EURUSD", "GBPUSD" ...}
    MqlRates pair0[], pair1[], ...
    bool initial;
    OnInit(){ initial=true;
       ArrayCopyRates(pair0, pairs[0], _Period);   
       ArrayCopyRates(pair1, pairs[1], _Period);
       :
    }
    OnCalculate( ... ){
       int count = IndicatorCounted();
       if(initial){
          if(pair1[0].time == 0) return;
          if(pair2[0].time == 0) return;
          :
          initial=false; count = 0; // process all bars
       }
       for(int i = Bars - 1 - MathMax(lookback, count); i >= 0; --i){
          int shift0 = iBarsShift(pairs[0], _Period, Time[i]);
          int shift1 = iBarsShift(pairs[1], _Period, Time[i]);
          buffer[i] = pair0[shift0].close - pair1[shift1].close;

  3. Если вы не хотите использовать ArrayCopyRates, то это не обязательно, но вы все равно должны загрузить другие пары, заменив [в if(initial)] pairN[0].time на iTime().
 
   if(pair1[0].time == 0) return;

Это никогда не будет правдой.

Если для символа и таймфрейма загружена история, функция получит самое последнее значение.

Если история не загружена, вы получите ошибку Array out of range.

То же самое с iTime и т.д.

 
GumRai:

Это никогда не будет правдой.

Если для символа и таймфрейма загружена история, функция получит самое последнее значение.

Если история не загружена, вы получите ошибку Array out of range.

То же самое с iTime и т.д.

Я склонен согласиться!

Лично я просто проверяю возвращаемое значение функции "ArrayCopyRates()" и после этого просто отслеживаю размер массива, прежде чем обращаться к данным массива.

Что касается "iTime()" и других подобных функций, я всегда сначала проверяю "iBars()".

 
GumRai:

Это никогда не будет правдой.

  if(pair1[0].time == 0) return;

Если для символа и таймфрейма загружена история, функция получит самое последнее значение.

Если история не загружена, вы получите ошибку Array out of range.

То же самое с iTime и т.д.

Существует множество исторических (до сборки 600) примеров просмотра ACR. Другого способа сделать это не существует. Последующие вызовы ACR или iTime НЕ возвращают 4066, поэтому как вы можете узнать, были ли загружены данные.

iTime всегда возвращает ноль при ошибке.

 
WHRoeder:

Существует множество исторических (до сборки 600) примеров просмотра ACR. Другого способа сделать это не существует. Последующие вызовы ACR или iTime НЕ вернут 4066, так что как вы можете узнать, были ли данные загружены.

iTime всегда возвращал ноль при ошибке.

Что вы имеете в виду под "нет другого способа сделать это"?

Проверка количества возвратов из "ArrayCopyRates" и проверка размера массива кажется более надежным методом проверки, чем "pair1[0].time == 0", который может легко вернутьошибку "Array index is out of range".

EDIT: Удалил некоторые из моих утверждений после более внимательного прочтения вашего сообщения.