Как оптимально задать условие поиска увеличения размера некоего значения? - страница 3

 
Выход за границы массива, например у нас всего 100 баров на графике, вы посылаете на поиск 100 бар, и функция пытается считать 100+1 100+2, поставьте там условие.
if(Bars<fi_Index+bars)return false;
 
Почему-то я подобных проверок в стандартных индикаторах не встречал. Взять хотя бы машку. Но там ошибок нет подобных. Странно..
 
shanty:

Хотя всё верно. Мне нужно было 2 повышающихся вершины, а это значит что счётчик будет не 3, а 2. Такой вариант работает. Тока если я уберу строку:

Из функции OnCalculate(), то индикатор сообщает ошибку времени выполнения:

 Это ещё почему?

Я понимаю, что происходит выход за пределы массива. Но где, не понятно. 

Виктор, выход за пределы массива происходит тогда, когда на графике 1000, например, баров и цикл строится от 0 до 1000, но нумеруются они от 0 до 999 и потом ты ещё проверяешь 2 или 3 бара на соответствие твоему условию. В старых билдах такие ошибки просто игнорировались, а теперь за этим надо следить. Хотя если убрать #property strict то тоже эта ошибка будет игнорироваться.

Посмотри эту реализацию

   int i, limit = rates_total-prev_calculated; // Если это запуск индикатора, то prev_calculated = 0, соответственно limit = rates_total
   while(rates_total - limit < 3)                // Цикл выполняется пока ... сам знаешь
    {
     limit--;
    }
    for(i = limit; i >= 0; i--)                // А теперь цикл от rates_total-3 до нулевого бара...


А почему ты не хочешь проверять полное соответствие условию на каждом баре? Тоесть, на каждом баре условие if(1 бар соответствует && 2 бар соответствует && 3 бар соответствует) ... условие выполнено рисуем стрелку...

Наверное как всегда хочешь универсальность, возможность изменять количество проверяемых баров... Ну можно построить цикл от i-того бара до i+n где и проверять соответствие условию...

 
AlexeyVik:

Виктор, выход за пределы массива происходит тогда, когда на графике 1000, например, баров и цикл строится от 0 до 1000, но нумеруются они от 0 до 999 и потом ты ещё проверяешь 2 или 3 бара на соответствие твоему условию. В старых билдах такие ошибки просто игнорировались, а теперь за этим надо следить. Хотя если убрать #property strict то тоже эта ошибка будет игнорироваться.

Посмотри эту реализацию

 int i, limit = rates_total-prev_calculated; // Если это запуск индикатора, то prev_calculated = 0, соответственно limit = rates_total
   while(rates_total - limit < 3)                // Цикл выполняется пока ... сам знаешь
    {
     limit--;
    }
    for(i = limit; i >= 0; i--)                // А теперь цикл от rates_total-3 до нулевого бара...


 Как я понял, выход за пределы массива возникает в самом начале работы индикаторе, а точнее в момент его запуска. Ведь когда limit = , скажем так 999 из всего 1000 имеющихся баров на графике, то 

в момент когда сравниваются соседние бары на первой итерации цикла, то можно смело накинуть 2 бара в стороны 1000... выйдет 999 + 2. Это если мы по счётчику достигаем 2 бара, которые сравниваем. А если их, например, 100, то выход будет на 99 т.е. к 1099-му бару, которого нет в истории. Тут понятно. 

 

AlexeyVik:

А почему ты не хочешь проверять полное соответствие условию на каждом баре? Тоесть, на каждом баре условие if(1 бар соответствует && 2 бар соответствует && 3 бар соответствует) ... условие выполнено рисуем стрелку...

 Алексей, у меня позиция такова, что индикатор нужен только в случае прибавки производительности работы системы в целом. Если пересчёт всех данных будет на каждом баре, то это не есть адекватно, на мой взгляд. Тоже самое можно рализовать в эксперте. Тогда какой резон вообще от индикатора?

Как я понимаю, назначение индикатора запоминать ситуацию на предыдущих барах (либо в буфер, либо в переменные), и досчитывать не обработанные бары. Но никак не пересчитывать всё...

Я понимаю, что, конечно, это не весь график, а лишь пересчёт на последней итерации в пределах от нулевого или первого бара до limit, но всё же.. 

 

AlexeyVik:

Наверное как всегда хочешь универсальность, возможность изменять количество проверяемых баров... Ну можно построить цикл от i-того бара до i+n где и проверять соответствие условию...

 Да, в данном методе нужно только один входной параметр.. кол-во проеряемых баров. Больше ничего. Это ж вполне очевидно.

 

shanty:

 Как я понял, выход за пределы массива возникает в самом начале работы индикаторе, а точнее в момент его запуска. Ведь когда limit = , скажем так 999 из всего 1000 имеющихся баров на графике, то 

в момент когда сравниваются соседние бары на первой итерации цикла, то можно смело накинуть 2 бара в стороны 1000... выйдет 999 + 2. Это если мы по счётчику достигаем 2 бара, которые сравниваем. А если их, например, 100, то выход будет на 99 т.е. к 1099-му бару, которого нет в истории. Тут понятно.

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

Так зачем такой пример где 1000 и 100? Достаточно того, что на графике 1000 баров... Проверяем на 0... соответственно надо посчитать 1 и 2 бары... А когда дошли до 998 надо проверить 999 и 1000 а его уже нет. Соответственно если брать в расчёт 3 бара ошибка выскочит уже на 997м баре.

 Алексей, у меня позиция такова, что индикатор нужен только в случае прибавки производительности работы системы в целом. Если пересчёт всех данных будет на каждом баре, то это не есть адекватно, на мой взгляд. Тоже самое можно рализовать в эксперте. Тогда какой резон вообще от индикатора?

Как я понимаю, назначение индикатора запоминать ситуацию на предыдущих барах (либо в буфер, либо в переменные), и досчитывать не обработанные бары. Но никак не пересчитывать всё...

Я понимаю, что, конечно, это не весь график, а лишь пересчёт на последней итерации в пределах от нулевого или первого бара до limit, но всё же.. 

Наверное ты не так понял... Пересчёт на каждом баре не означает пересчёт всей истории. Вся история пересчитывается 1 раз при запуске индикатора, а дальше только нулевой...

shanty:

 Да, в данном методе нужно только один входной параметр.. кол-во проеряемых баров. Больше ничего. Это ж вполне очевидно.

Так именно это я и предложил последним предложением

построить цикл от i-того бара до i+n где и проверять соответствие условию...



input n = 2;
int i, limit = rates_total-prev_calculated; // Если это запуск индикатора, то prev_calculated = 0, соответственно limit = rates_total
   while(rates_total - limit < n)                // Цикл выполняется пока ... сам знаешь
    {
     limit--;
    }
    for(i = limit; i >= 0; i--)                // А теперь цикл от rates_total-n до нулевого бара... 
     {
      for(int k = i+1; k <= i+n; k++)
       {
        \\ тут определяем условие. Если выполнено рисуем стрелку... Нет - продолжаем внешний цикл.
       }
     }


Вот и получается, что в зависимости от n начало будет от n-ного с конца бара... если баров 1000, то начинаем от 997-го, проверяем 998 и 999. На следующем 997 и 998 и т.д. на нулевом первый и второй...

 
AlexeyVik:

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

Так зачем такой пример где 1000 и 100? Достаточно того,что на графике 1000 баров... Проверяем на 0... соответственно надопосчитать 1 и 2 бары... А когда дошли до 998 надо проверить 999 и 1000 аего уже нет. Соответственно если брать в расчёт 3 бара ошибка выскочитуже на 997м баре.

Наверное ты не так понял... Пересчёт на каждом баре не означает пересчёт всей истории. Вся история пересчитывается 1 раз при запуске индикатора, а дальше только нулевой...

 Алексей, возможно я объяснил не совсем доходчиво, что думаю, либо Вы меня не верно поняли. Суть вот в чём:

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

input n = 2;
int i, limit = rates_total-prev_calculated; // Если это запуск индикатора, то prev_calculated = 0, соответственно limit = rates_total
   while(rates_total - limit < n)                // Цикл выполняется пока ... сам знаешь
    {
     limit--;
    }
    for(i = limit; i >= 0; i--)                // А теперь цикл от rates_total-n до нулевого бара... 
     {
      for(int k = i+1; k <= i+n; k++)
       {
        \\ тут определяем условие. Если выполнено рисуем стрелку... Нет - продолжаем внешний цикл.
       }
     }

 В поле:

for(i = limit; i >= 0; i--)  

 Мы производим расчёты на барах, которые не просчитаны. Тут всё очевидно. А вот в поле:

for(int k = i+1; k <= i+n; k++)

 Происходит пересчёт "состояния" на всех барах, которых ровно столько сколько в вводном параметре n. Вообще странно, что на барах, которые расчитываются нужно расчитывать все бары n. Я же предложил другой вариант. При проходе по истории, ровно как и при расчётах баров, которые не досчитаны расчитывать не всех n баров, а лишь последний. Понимаете?

 Т.е. теоритически, будет так:

1-ый расчёт, сравниваем текущий бар с индексов [i] с предыдущим [i+1]. Добавили к счётчику 1.

2-ой расчёт, сдвинулись в историю на 1. Сравниваем снова бары [i] и [i+1]. Добавили к счётчику 1.

3-ий расчёт, сдвинулись в историю на 1. Сравниваем снова бары [i] и [i+1]. Добавили к счётчику 1.

Если на каком-то расчёте не соблюдается условие, то счётчик обнуляем и начинается на следующем расчёте всё с начала.

Но такой вариант не работает вообще адекватно. Стрелки рисуются не там где нужно. Почему? 

 

Ну так в твоём примере примерно то-же самое. Посмотри комментарии в коде.

bool ExistencePositiveSequence (int fi_Index, int bars)// bars получили 3
{
//---
   int cx = 0;
//---
   if (High[fi_Index] > High[fi_Index + 1])
   {
      cx++;
      
      while (High[fi_Index + cx] > High[fi_Index + cx + 1]){// цикл от i-того... тоесть от нулевого после пересчёта всей истории???
         cx++;
         if (cx >= bars) return true;// и тут выход, если баров с заданным условием = 3
      }
   }
   return (false);
}
shanty:

 Т.е. теоритически, будет так:

1-ый расчёт, сравниваем текущий бар с индексов [i] с предыдущим [i+1]. Добавили к счётчику 1.

2-ой расчёт, сдвинулись в историю на 1. Сравниваем снова бары [i] и [i+1]. Добавили к счётчику 1.

3-ий расчёт, сдвинулись в историю на 1. Сравниваем снова бары [i] и [i+1]. Добавили к счётчику 1.

Если на каком-то расчёте не соблюдается условие, то счётчик обнуляем и начинается на следующем расчёте всё с начала.

Но такой вариант не работает вообще адекватно. Стрелки рисуются не там где нужно. Почему?

А в принципе и такой метод должен работать. Только надо вовремя обнулить счётчик.

А ещё... не получается-ли у тебя так, что на трёх тиках проверяется одна пара баров и рисует стрелку где попало? Для такого индикатора надо сделать пересчёт только один раз на баре.

 

Всё-то, конечно, хорошо, но, на данный момент, вопрос не решён. Написал без каких-либо классов, самым обычным способом:

 Что не так? Индикатор в пару строк...

#property strict

#property indicator_chart_window            // Индикатор выводится в окне графика
#property indicator_buffers 1               // Используется 2 буфера индикатора
//#property indicator_color1 clrBlack         // Цвет отображения данных 1-го буфера

input int countCamparedBars = 3;            // Количество объёма определённого признака в последовательности
double   MaxValue[];                        // Буфер максимальных значение хая за N-баров

//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                             Custom indicator initialization function                                                  |
//+---------------------------------------------------------------------------------------------------------------------------------------+
int OnInit()
{
   IndicatorBuffers(1);
   
   // Связывание буфферов с индексами и определение стилей
   SetIndexBuffer (0, MaxValue);
   SetIndexStyle (0,  DRAW_ARROW, 0, 3, clrBlack);
   SetIndexArrow (0, 241);
//---
   return (INIT_SUCCEEDED);
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                     Определение значение положительной дельты ClusterDelta_Delta                                      |
//+---------------------------------------------------------------------------------------------------------------------------------------+
bool ExistencePositiveSequence (int fi_Index, int fi_CountCamparedBars)
{
//   if (ClusterDelta::cdVolume (fi_Index) > ClusterDelta::cdVolume (fi_Index + 1))
   int cnt = 0;

   for (int i = fi_Index; i < fi_Index + fi_CountCamparedBars; i++)
   {
      if (High[i] > High[i + 1])
        cnt++;
      
      if (cnt == fi_CountCamparedBars)
     return (true);
   }
   return (false);
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                               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 limit = rates_total - prev_calculated;
   
   while ( (rates_total - limit ) < countCamparedBars)
   {
      limit--;
   }
/*   if (prev_calculated == 0) limit--;
   else limit++;
*/   
   for (int i = limit; i >= 0; i--)
   {
      if (ExistencePositiveSequence (i, countCamparedBars) == true)
      {
         MaxValue[i] = High[i];
      }
   }
   
//--- return value of prev_calculated for next call
   return (rates_total);
}
//+---------------------------------------------------------------------------------------------------------------------------------------+

 Ещё раз повторю. Задача такая: нужно нарисовать стрелку вверх, если хаи баров повышаются на fi_CountCamparedBars баров, и стрелку вниз, если хай баров понижаются на протяжении fi_CountCamparedBars баров.

 
А на прошлой странице мы разве эту задачу не решили уже, ведь всё верно находило ?
 

Не совсем. Вот переделка с вариантом, который предложен Вами:

#property indicator_chart_window            // Индикатор выводится в окне графика
#property indicator_buffers 2               // Используется 2 буфера индикатора

input int countCamparedBars = 3;            // Количество объёма определённого признака в последовательности
double   highestValue[];                    // Буфер максимальных значение хая за N-баров
double   lowestValue[];                     // Буфер максимальных значение хая за N-баров

//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                                                OnInit()                                                               |
//+---------------------------------------------------------------------------------------------------------------------------------------+
int OnInit()
{
   IndicatorBuffers(2);
   
   // Связывание 1-го буффера с соответствующим массивом и определение его свойств
   SetIndexBuffer (0, highestValue);
   SetIndexStyle (0,  DRAW_ARROW, 0, 3, clrBlack);
   SetIndexArrow (0, 241);
   
   // Связывание 2-го буффера с соответствующим массивом и определение его свойств
   SetIndexBuffer (1, lowestValue);
   SetIndexStyle (1,  DRAW_ARROW, 0, 3, clrRed);
   SetIndexArrow (1, 242);
//---
   return (INIT_SUCCEEDED);
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                     Возвращаем флаг наличия возрастающей последовательности хаёв                                      |
//+---------------------------------------------------------------------------------------------------------------------------------------+
int ExistencePositiveSequence (int fi_Index, int fi_CountCamparedBars)
{
   int cx = 0;
   
   if (High[fi_Index] > High[fi_Index + 1])
   {
      cx++;
      
      while (High[fi_Index + cx] > High[fi_Index + cx + 1]){
         cx++;
         if (cx >= fi_CountCamparedBars) return 0;
         
      }
   }
   else if (High[fi_Index] < High[fi_Index + 1])
   {
      cx++;
      
      while (High[fi_Index + cx] < High[fi_Index + cx + 1]){
         cx++;
         if (cx >= fi_CountCamparedBars) return 1;
         
      }
   }
   return (2);
}
//+---------------------------------------------------------------------------------------------------------------------------------------+
//|                                                             OnCalculate()                                                             |
//+---------------------------------------------------------------------------------------------------------------------------------------+
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 limit = rates_total - prev_calculated;
   
   while ( (rates_total - limit ) < countCamparedBars)
   {
      limit--;
   }
   
   for (int i = limit; i >= 0; i--)
   {
      if (ExistencePositiveSequence (i, countCamparedBars) == 0)
      {
         highestValue[i] = High[i];
      }
      else if (ExistencePositiveSequence (i, countCamparedBars) == 1)
      {
         lowestValue[i] = low[i];
      }
   }
   
//--- return value of prev_calculated for next call
   return (rates_total);
}

 Если параметр вводной переменной равен 3, то индюк работает корректно. А если ставлю 2, то выход за пределы массива. Не понятно как такое может быть!

Пишет, что мол:

2015.09.29 22:50:30.301 HighestBarOfTheSequence AUDJPY,M1: array out of range in 'HighestBarOfTheSequence.mq4' (46,40)
Причина обращения: