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

 

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

Теперь мне нужно использовать курсы всех пар, скопированные с помощью функции ArrayCopyRates, для построения графических индикаторов, таких как RSI... как я нарисовал на картинке ниже:

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

 

Нет возможности разделить область индикатора. Все должно рисоваться отдельно, никаких буферов, никакого автоматического масштабирования. См.

Видели ли вы такую картинку? (MetaQuotes Software Corp.) - MQL4 форум - Страница 12
Видели ли вы такую картинку? (MetaQuotes Software Corp.) - MQL4 форум - Страница 14
Видели ли вы такую картинку? (MetaQuotes Software Corp.) - MQL4 форум - Страница 36

 
WHRoeder:

Нет возможности разделить область индикатора. Все должно рисоваться отдельно, никаких буферов, никакого автоматического масштабирования. См.

Видели ли вы такую картинку? (MetaQuotes Software Corp.) - MQL4 форум - Страница 12
Видели ли вы такую картинку? (MetaQuotes Software Corp.) - MQL4 форум - Страница 14
Видели ли вы такую картинку? (MetaQuotes Software Corp.) - MQL4 форум - Страница 36

Поймите. Тогда все элементы должны быть нарисованы как объекты.
 

Это индикатор, который я где-то взял, но никогда не пытался его расшифровать. Он показывает отображение 3 таймфреймов текущего графика. Самое интересное, что свечи рисуются с помощью гистограмм. Довольно аккуратно, но не то, чем я сейчас увлекаюсь.

С наилучшими пожеланиями

Файлы:
 
Хорошо, спасибо. Я в командировке на работе и когда вернусь, протестирую.
 
Fernando Carreiro:

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

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

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

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

Чтобы расширить выводы Фернандо - даже если символ совпадает с символом графика, если таймфрейм другой, то массив статичен.

Поэтому, чтобы иметь виртуальную копию в индикаторе, это должен быть тот же символ И тот же таймфрейм. Все остальное статично.

 
honest_knave: Просто чтобы расширить ваши выводы Fernando - даже если символ такой же, как и символ графика, если таймфрейм другой, то массив статичен. Поэтому, чтобы иметь виртуальную копию в индикаторе, это должен быть тот же символ И тот же таймфрейм. Все остальное статично.
Спасибо за обновление!
 
Здравствуйте,

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

Это мое первое сообщение на форуме, поэтому, пожалуйста, дайте мне знать, если я пропустил какой-либо протокол, и я буду рад исправить его в следующем сообщении.

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

Мой индикатор рисует fib на диапазоне предыдущего дня (дневной максимум - дневной минимум или дневной минимум - дневной максимум) и в текущий день проводит линии на максимуме, минимуме и 50% fib. Если индикатор используется у брокера с GMT (воскресная дневная свеча), пользователь может задать входной параметр, чтобы выбрать, будет ли он в понедельник использовать только пятничный или воскресный диапазон, или пятницу + воскресенье. Для брокера с закрытием в Нью-Йорке (GMT+2) это не имеет значения, поскольку воскресных свечей нет.

Другая особенность этого индикатора - позволить пользователю перемещать fib вокруг, и линии (high, 50% и low) на текущий день будут подстраиваться под новый диапазон, установленный fib. Это позволит пользователю скорректировать диапазон в случае его сужения.

Индикатор будет в основном использоваться на нескольких 1h графиках, но пользователь должен иметь возможность переключать таймфреймы без потери изменений, сделанных на fib.

Для построения fib мне нужно найти не только максимум и минимум предыдущего дня, но и время для этих точек.

Идея проста, но я столкнулся с несколькими трудностями.

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

       Hi = iHigh(NULL, PERIOD_D1, 1);
       Lo = iLow(NULL, PERIOD_D1, 1);

Это хорошо, но теперь мне нужно найти, в какое время в предыдущий день был максимум и минимум. Я решил прикинуть время до 1ч свечи на максимуме и минимуме, используя iHighest и iLowest. И вот тут начались проблемы.


Чтобы использовать iHighest и iLowest, мне нужно указать первую 1h свечу и размер диапазона, поэтому в моем случае это будет первая 1h и последняя 1h свеча предыдущего дня. Поэтому я использовал открытие предыдущей дневной свечи для начала предыдущего дня и открытие на дневной свече текущего дня -1, чтобы найти конец предыдущего дня:

       PrevDayBegin = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 1));                
       PrevDayEnd = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1);

И это отлично работает, если вы используете индикатор только на валютах (опять же предполагая, что это середина недели), потому что PrevDayBegin будет индексом свечи 0:00 1h, а PrevDayEnd будет индексом свечи 23:00 1h. Проблема заключается во фьючерсах (индексы, золото, нефть и т.д.). Открытие дневной свечи всегда происходит в 0:00, но 1-я свеча на фьючерсах приходится на 1 час ночи по GMT+2 брокеров, поэтому строка кода выше, которая вычисляет PrevDayBegin, возвращает 1ч свечу на 23:00 предыдущего дня.

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

       if(TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayBegin)) != TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayEnd)))
         PrevDayBegin--;  

И вся эта логика отлично работает, если у вас есть все актуальные 1h свечи, но взгляните на лог ниже, где показаны некоторые отпечатки того, что произошло сегодня. Для справки, я закрыл MT4 накануне вечером и открыл его снова сегодня утром (около 7 утра по британскому времени), поэтому на графиках отсутствовали данные только за несколько часов.

2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == ДРУГОЙ ДЕНЬ НЕДЕЛИ ==
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.08 19:00)
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 20 (2017.02.08 00:00)

Глядя на лог, кажется, что самая последняя свеча на 1h графике была 2017.02.08 20:00 (индекс 0), поэтому iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1) приближает это к (индекс 1) 2017.02.08 19:00. Следовательно, все вычисления для индикатора путаются, потому что iHighest и iLowest будут использовать неправильный диапазон.

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

Например, в OnInit() я включил следующие строки кода, чтобы вызвать обновление графиков на 1h, Daily и текущем таймфрейме (просто на случай, если платформа была закрыта, когда график был открыт на другом таймфрейме):

   // Triggers history update
   MqlRates mqlrates_array_d1[];
   MqlRates mqlrates_array_h1[];
   MqlRates mqlrates_array[];
  
   ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1);
   ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1);
   ArrayCopyRates(mqlrates_array,NULL,0);  
Еще одна вещь, которую я заметил: похоже, что MT4 обновляет последнюю свечу Time[0] на таймфрейме, который открыт на графике, прежде чем загрузить всю недостающую историю, поэтому я решил проверить, является ли Time[1] также действительной ценой.

Этот код был вставлен в OnCalculate() и основан на кодах от @whroeder1(здесь) и @Fernando Carreiro& @Wemerson Guimaraes(здесь):

bool isHistoryLoading;

OnInit();
:
isHistoryLoading = true;
:

OnCalculate( ... )
:
      MqlRates mqlrates_array_d1[];
      MqlRates mqlrates_array_h1[];
      MqlRates mqlrates_array[];
      
      if(isHistoryLoading)
        {      
         ResetLastError();        
        
         if(ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1)>0)
           {
            if(GetLastError() == 0)
              {
               if((iTime(NULL,PERIOD_D1,0) > 0) && (iTime(NULL,PERIOD_D1,1) > 0))
                 {
                  ResetLastError();
  
                  if(ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1)>0)
                    {
                     if(GetLastError() == 0)
                       {
                        if((iTime(NULL,PERIOD_H1,0) > 0) && (iTime(NULL,PERIOD_H1,1) > 0))
                          {
                           ResetLastError();
      
                           if(ArrayCopyRates(mqlrates_array,NULL,0)>0)
                             {
                              if(GetLastError() == 0)
                                {
                                 if((iTime(NULL,0,0) > 0) && (iTime(NULL,0,1) > 0))                            
                                   {
                                    isHistoryLoading = false;
                                
                                    if(DebugLog)
                                      Print("Chart up-to-date!");        
                                    }
                                }
                             }
                          }
                       }
                    }                      
                 }
              }
           }
        }
        
      if(isHistoryLoading)
        {
         if(DebugLog)
           Print("Waiting for chart to update!");
         return(rates_total);
        }    

:

А это лог, когда платформа была открыта и индикатор загрузился в первый раз:

2017.02.09 06:56:18.492 Пользовательский индикатор Prev_Day_Range_LRT_50_v0.6 SPX500,H1: успешно загружен
2017.02.09 06:56:18.630 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: инициализирован
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: График обновлен!
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Индикатор не существует! Создаем его.
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == ДРУГОЙ ДЕНЬ НЕДЕЛИ ==
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 20 (2017.02.07 23:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 42 (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR День недели = 3
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 28) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Candle = 20) (Price = 2287.88) (Time = 2017.02.07 23:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib от Time1=2017.02.07 14:00 Price1=2299.33 до Time2=2017.02.07 23:00 Price2=2287.88
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend1 131296489639296384' from Time1=2017.02.08 00:00 Price1=2299.33 to Time2=2017.02.09 00:00 Price2=2299.33
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend2 131296489639296384' from Time1=2017.02.08 00:00 Price1=2293.605 to Time2=2017.02.09 00:00 Price2=2293.605
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend3 131296489639296384' from Time1=2017.02.08 00:00 Price1=2287.88 to Time2=2017.02.09 00:00 Price2=2287.88

Похоже, что любые ссылки на свечи 0 и 1 или функция ArrayCopyRates обращаются только к той информации, которая уже загружена в графики, поэтому ArrayCopyRates, похоже, возвращает действительное количество скопированных элементов, а iTime(..., 0) и iTime(..., 1) возвращают действительную цену для последних 2 свечей, сохраненных при закрытии платформы в предыдущий день.

Это означает, что индикатор был построен так, как будто это было вчера (PERIOD_D1 [0] = (2017.02.08 00:00)).

Индикатор построен так, что линии high, 50% и low всегда строятся на текущий день, даже если пользователь перемещает fib (это 3 линии тренда, показанные в логе выше). Поэтому у меня есть часть кода в OnCalculate(), которая проверяет, построена ли средняя линия тренда в текущий день (у пользователя есть опция ввода, чтобы отключить верхнюю и нижнюю линии, поэтому единственная линия, которая всегда будет построена, это средняя).

OnCalculate( ... )
:

      if(ObjectFind(Trend2Name) != -1)                // Check whether mid range line exists
        {
            
         if((TimeDay(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeDay(TimeCurrent()))
           && (TimeMonth(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeMonth(TimeCurrent()))
           && (TimeYear(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeYear(TimeCurrent()))) // Indicator has already been ploted today        
           {
            return(rates_total);
           }
         else     // Indicator exists but in a past date, so delete it and plot it on current day
           {
            if(DebugLog)
               Print("Indicator in a past date! Deleting it and creating it today!");
              
            if(ObjectFind(FibName) != -1)
              FiboLevelsDelete(0,FibName);              
            // Indicator will be created by the OnChartEvent() when it detects the fib was deleted.
           }
        }
      else        // Indicator doesn't exist, so create it
        {
         if(DebugLog)
            Print("Indicator doesn't exist! Creating it.");
         CreateIndicator();
        }
:

После нескольких тиков данные будут частично загружены, и приведенный выше фрагмент кода обнаружит, что линии были построены в предыдущий день, удалит fib и вызовет пересчет диапазонов и перерисовку объектов (т.е. fib, линий тренда и т.д.).


2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Индикатор в прошлой дате! Удаляю его и создаю сегодня!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDRFibo 131296489639296384 удален!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Удаление PDRRectangle 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Удаление PDRTrend1 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Удаление PDRTrend2 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Удаление PDRTrend3 131296489639296384

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

Это более полная версия лога, показанного в начале сообщения, которая показывает, что не только PrevDayEnd рассчитывается неправильно, так как 2-я свеча (индекс 1) на 1h графике - (2017.02.07 21:00), но и CurrDayBegin, которая должна быть 1-й свечой текущего дня на 1h графике, приближается по iBarShift к (2017.02.08 06:00).

CurrDayBegin = iTime(NULL, PERIOD_D1, 0);
      
while(TimeDayOfWeek(iTime(NULL, PERIOD_H1, iBarShift(NULL, PERIOD_H1, CurrDayBegin))) != TimeDayOfWeek(TimeCurrent()))

     // If iBarShift can't find the 0am candle and returns the 11pm candle of prev day.

  CurrDayBegin = CurrDayBegin + 3600;        // Move 1h until you find the 1st candle of today.                                        

2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == ДРУГОЙ ДЕНЬ НЕДЕЛИ ==
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.07 21:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 22 (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 06:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR День недели = 3
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 8) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Candle = 19) (Price = 2288.57) (Time = 2017.02.07 03:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib от Time1=2017.02.07 03:00 Price1=2288.57 до Time2=2017.02.07 14:00 Price2=2299.33
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend1 131296489639296384' from Time1=2017.02.08 06:00 Price1=2288.57 to Time2=2017.02.09 06:00 Price2=2288.57
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend2 131296489639296384' from Time1=2017.02.08 06:00 Price1=2293.95 to Time2=2017.02.09 06:00 Price2=2293.95
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend3 131296489639296384' from Time1=2017.02.08 06:00 Price1=2299.33 to Time2=2017.02.09 06:00 Price2=2299.33

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

Спасибо за терпение в этом очень длинном сообщении.

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

Вот скриншоты индикатора:

(1) Рассчитано с использованием неполной истории (обратите внимание, что горизонтальные линии начинаются не с начала дня)

Показатель, рассчитанный при неполной истории

(2) Пересчитано с использованием полной истории (горизонтальные линии начинаются в начале дня)

Показатель пересчитан с использованием полной истории

Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
  • www.mql5.com
Hi i m building a custom indicator and got problems with the 4066 Error...