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

 
4x_Gypsy:

Большой подсказкой было "Но я не знаю, как это сделать".

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

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

Кроме того, здесь есть Google и возможность поиска. Если я не знаю, как что-то сделать, это мой следующий шаг - попытаться решить проблему самостоятельно.

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

 
gooly:

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

Кроме того, здесь есть Google и возможность поиска. Если я не знаю, как что-то сделать, это мой следующий шаг, пытающийся решить проблему самостоятельно.

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

Спасибо за отзыв, и рад, что он был положительным. lol

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

 

Привет, ребята,

Извините за долгий период отсутствия активности здесь. Я был в разъездах по работе, а также занят некоторыми проектами и был вынужден оставить проект в стороне на некоторое время...

После прочтения обновлений, у меня есть несколько моментов, которые нужно прояснить:

  1. Я не хочу, чтобы кто-то кодировал все вещи за меня, просто нужно показать мне правильное направление и я сделаю все остальное. Хорошо... я буду тестировать решение WHRoeder сейчас и делать свои вещи и позже опубликую результат здесь. Предложение WHRoeder:https://www.mql5.com/en/forum/158938
  2. Перед созданием этой темы я искал похожие сообщения, но не нашел... тогда создал ее.
  3. Извините, что долго не отвечал, но я действительно был перегружен работой, но сейчас я продолжаю работать с индикатором.
  4. Извините за мой плохой английский! Мой язык португальский, и когда я пишу на английском, мне приходится использовать переводчик Google, а он не идеален.


 
Вот мой тест.

Просто позвольте пользователям проинформировать их активы, и после, покажите все пары High/Low значений.

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

Как вы можете видеть на изображении ниже, индикатор был добавлен в окно GBPUSD... и курсы GBPUSD прекрасно обновляются тик за тиком. Но курс EURUSD не обновляется и остается с тем же значением.

Копирование тарифов


Ниже приведен код индикатора:

//+------------------------------------------------------------------+
//|                                                MultiCurrency.mq4 |
//|                         Copyright 2016, Wemerson Couto Guimarães |
//|                  https://www.mql5.com/pt/users/wemersonrv/seller |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Wemerson Couto Guimarães"
#property link      "https://www.mql5.com/pt/users/wemersonrv/seller"
#property version   "1.00"
#property strict
#property indicator_separate_window

input string UsePairs="EURUSD,GBPUSD"; // Pares separados por vírgula.

struct pair_struct{
   string symbol;
   MqlRates rates[];
};
pair_struct pairs[];
bool initial;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){
   int i=0, j=0, c;
   string _pairs[], msg="";
   bool pairok=false;
   initial = true;
   ENUM_INIT_RETCODE result = INIT_SUCCEEDED;
   
   StringSplit(UsePairs, StringGetCharacter(",",0), _pairs);
   
   for( i=0; i< ArraySize(_pairs); i++){
      pairok=false;
      
      for( j=0; j<SymbolsTotal(true); j++){
         if( SymbolName(j, true) == _pairs[i]){
            pairok=true;
            break;
         }
      }
      if( pairok ){
         c=ArraySize(pairs);
         ArrayResize(pairs, c+1);
         pairs[c].symbol = _pairs[i];
      }else{
         msg += _pairs[i] + ", ";
      }
   }
   if( msg != "" ){
      string invalids = ArraySize(pairs)== 1?"Invalid Pair: ": "Invalid Pairs: ";
      msg = invalids +  StringSubstr(msg,0,StringLen(msg)-2) + ". Please Check!";
      Alert(msg);
      result = INIT_PARAMETERS_INCORRECT;
   }else{
      for(i=0; i<ArraySize(pairs); i++){
         ArrayCopyRates( pairs[i].rates, pairs[i].symbol, PERIOD_CURRENT );
      }
   }   
   
   return(result);

}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
   
   Comment("");
   
}

//+------------------------------------------------------------------+
//| 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[])
  {

   int i=0;
   if( initial ){
      for( i=0; i<ArraySize(pairs); i++){
         if(pairs[i].rates[0].time == 0) return(rates_total);
      }
      initial=false;
   }
   
   string log="";
   
   for(i=0; i<ArraySize(pairs); i++){
      log += "\nPair: " + pairs[i].symbol + 
             " - High: "+ DoubleToStr(pairs[i].rates[0].high, Digits()) + 
             " - Low: "+ DoubleToStr(pairs[i].rates[0].low, Digits());
   }

   Comment( "\n\n*** Pair Rates***\n" + log );
   return(rates_total);
   
}
//+------------------------------------------------------------------+

 
Я пытаюсь использовать RefreshRates(), но все равно с тем же результатом... только пара в том же окне работает, другие пары не обновляются.
 
wemersonrv:
Я пытаюсь использовать RefreshRates(), но все равно с тем же результатом... только пара в том же окне работает, другие пары не обновляются.

RefreshRates() не имеет никакого отношения к данным MqlRates. Код примера WHRoeder действителен только для сборки Pre-600. Для последней сборки вам необходимо проверить различные моменты, упомянутые в моем сообщении, такие как проверка кодов возврата ArrayCopyRates(), а также кодов ошибок, размера массива тарифов и, как дополнительная мера предосторожности, указанная WHRoeder, достоверность атрибута времени.

PS! Если у вас проблемы с английским языком, напишите мне в PM. Я португалец (Португалия)

 

Привет, ребята.

Тестируя, я включил "повторное копирование" ставок в функции OnCalculate... добавив цикл, который сначала FREE массив пар во всех итерациях, затем снова копирует ставки. Похоже, что это работает и не возвращает ошибку.

Я не знаю, лучший ли это способ сделать то, что мне нужно, но, очевидно, он работает и без ошибок.


   int i=0;
   if( initial ){
      for( i=0; i<ArraySize(pairs); i++){
         if(pairs[i].rates[0].time == 0) return(rates_total);
      }
      initial=false;
   }

   // My change to recopy rates every tick by adding a loop at starting of OnCalculate() to do this
   // AS FMIC says, ArrayCopyRates needs the array without content, 
   // then before recopy, free the array.
   for(i=0; i<ArraySize(pairs); i++){
      ArrayFree(pairs[i].rates);
      ArrayCopyRates(pairs[i].rates, pairs[i].symbol, PERIOD_CURRENT);
   }
 
wemersonrv: Тестируя, я включил "повторное копирование" ставок в функцию OnCalculate... добавив цикл, который сначала FREE массив пар во всех итерациях, затем снова копирует ставки. Вроде бы работает и не возвращает ошибку.
  1. Как указано в документации.
    Если данные (название символа и/или таймфрейм отличаются от текущих) запрашиваются с другого графика, возможна ситуация, что соответствующий график не был открыт в клиентском терминале, и необходимые данные должны быть запрошены с сервера. В этом случае в переменную last_error будет помещена ошибка ERR_HISTORY_WILL_UPDATED (4066 - запрашиваемые исторические данные находятся в стадии обновления), и придется делать повторный запрос.
    И проверено здесь
    ArrayCopyRates вернет ошибку, если истории нет вообще (ERR_NO_HISTORY_DATA = 4073.) Повторные вызовы также будут неудачными, пока загрузка не завершится. Если история есть, но не актуальна, ArrayCopyRates возвращает действительный результат и также устанавливает `_LastError` в ERR_HISTORY_WILL_UPDATED (= 4066).
  2. Проверьте свой код возврата, при необходимости перейдите в спящий режим и повторите попытку. Что такое значения возврата функции? Как их использовать? - MQL4 форум и Распространенные ошибки в MQL4 программах и как их избежать - MQL4 Статьи
 

Обновление для тех, кто следит за этой темой!

Я помогал OP через PM исправить его код, так как у него проблемы с английским, а мы оба говорим на португальском. В ходе тестирования мы столкнулись с еще одним "приколом", который происходит с функцией"ArrayCopyRates()". При использовании массива MqlRates с"ArrayCopyRates()" в советнике, массив данных является виртуальным, который всегда сообщает о текущем состоянии дел, поэтому данные всегда свежие.

Однако в индикаторе это не так. Массив не является виртуальной копией, а статической копией, установленной во времени в момент вызова"ArrayCopyRates()". Данные не обновляются, когда Символ отличается от символа графика. Когда это тот же символ, что и на графике, то данные массива "живые" и обновляются, как и ожидалось, но когда это другой символ, то это статическая копия.

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

 

Привет всем.

  • FMIC, спасибо за поддержку!
  • WHRoeder, спасибо тебе тоже... Ты всегда рядом со всеми нами!
  • Спасибо всем участникам форума за ваши соображения и даже спасибо за дебаты, которые развернулись в этой теме. Это было очень интересно!!!

Это (почти) то же самое, что я делаю позже, но разница в том, что я запускаю ArrayFree перед ArrayCopyRates... и я не делаю валидацию, которую вы мне помогли.

Вот окончательный код, который FMIC помог мне. Теперь он работает нормально в коде индикатора..:

input string UsePairs="NZDCAD,EURUSD,GBPUSD,USDJPY"; // pairs separated by commas
struct pair_struct{
   string symbol;
   MqlRates rates[];
   bool valid;
};
pair_struct pairs[];
bool initial;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){
   
   int i=0, j=0, c;
   string _pairs[], msg="";
   bool pairok=false;
   initial = true;
   ENUM_INIT_RETCODE result = INIT_SUCCEEDED;
   
   StringSplit(UsePairs, StringGetCharacter(",",0), _pairs);
   
   for( i=0; i< ArraySize(_pairs); i++){
      pairok=false;
      
      for( j=0; j<SymbolsTotal(true); j++){
         if( SymbolName(j, true) == _pairs[i] ){
            pairok=true;
            break;
         }
      }
      if( pairok ){
         c=ArraySize(pairs);
         ArrayResize(pairs, c+1);
         pairs[c].symbol = _pairs[i];
         pairs[c].valid = false;
      }else{
         msg += _pairs[i] + ", ";
      }
   }
   if( msg != "" ){
      string invalids = ArraySize(pairs)== 1?"Invalid Pair: ": "Invalid Pairs: ";
      msg = invalids +  StringSubstr(msg,0,StringLen(msg)-2) + ". Please Check!";
      Alert(msg);
      result = INIT_PARAMETERS_INCORRECT;
   }
   return(result);

}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
   
   Comment("");
   
}

//+------------------------------------------------------------------+
//| 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[])
  {

   InitializeRates();
   
   int i=0;
   string log="";
   for(i=0; i<ArraySize(pairs); i++){
      log += "\nPar: " + pairs[i].symbol;
      if( pairs[i].valid ){
         log += " - Time: "+ TimeToString( pairs[i].rates[0].time ) + 
                " - Open: "+ DoubleToString( pairs[i].rates[0].open, (int)MarketInfo( pairs[i].symbol, MODE_DIGITS ) ) +
                " - Close: "+ DoubleToString( pairs[i].rates[0].close, (int)MarketInfo( pairs[i].symbol, MODE_DIGITS ) ) +
                " - High: "+ DoubleToString( pairs[i].rates[0].high, (int)MarketInfo( pairs[i].symbol, MODE_DIGITS ) ) +
                " - Low: "+ DoubleToString( pairs[i].rates[0].low, (int)MarketInfo( pairs[i].symbol, MODE_DIGITS ) );
      }else{
         log += " - Currently not valid!";
      }
   }

   Comment( "\n\n*** Pair Rates***\n" + log );
   return(rates_total);
   
}
//+------------------------------------------------------------------+

void InitializeRates(){
 
   for( int i=0; i<ArraySize( pairs ); i++ ){
      pairs[i].valid = false;
      ResetLastError();
      if( ArrayCopyRates(pairs[i].rates, pairs[i].symbol, PERIOD_CURRENT) > 0 ){
         if( _LastError == 0 ){
            if( ArraySize(pairs[i].rates) > 0 ){
               if( pairs[i].rates[0].time > 0 )
                  pairs[i].valid = true;
            }
         }
      }
   }

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