Экспотенциальные значения во фракталах

 

День добрый.

Имеется доработанный стандартный индикатор фракталов, в котором можно задавать значение  кол-ва свечек по обе стороны от фрактала.

В исходнике индикатора явно прописано в любые значения, кроме high/low вставлять EMPTY_VALUE (что свою очередь соответствует DBL_MAX=1.7976931348623158e+308)

if(UpFound) ExtUpperBuffer[i]=high[i];
      else ExtUpperBuffer[i]=EMPTY_VALUE;
      if(DownFound) ExtLowerBuffer[i]=low[i];
      else ExtLowerBuffer[i]=EMPTY_VALUE;

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

ArrayResize(LowFArray,needCountFractals); // ставим размер массивов = кол-во необходимых фракталов
   ArrayResize(UpFArray,needCountFractals);
   ArrayResize(LowFNumber,needCountFractals);
   ArrayResize(UpFNumber,needCountFractals);
   double copyBufferUp[],copyBufferLow[];
//скопировали массив верхних и нижних фракталов
   if(CopyBuffer(FHandle,0,start_pos,BarCount,copyBufferUp)==-1 || CopyBuffer(FHandle,1,start_pos,BarCount,copyBufferLow)==-1)
     {
      drop_message("Ошибка при копировании массивов фракталов");
      return false;
     }
   ArraySetAsSeries(copyBufferUp,true); // порядок как в таймериях. От нового к старому
   ArraySetAsSeries(copyBufferLow,true);
   int FromBarUp=start_pos;
   int FromBarLow=start_pos;
   for(int i=0;i<needCountFractals;i++)
     {
      for(int n=FromBarUp; n<BarCount; n++)
        {
         //--- если непустое значение, прерываем цикл
         if(copyBufferUp[n]!=EMPTY_VALUE && copyBufferUp[n]>0)
           {
            UpFArray[i]=copyBufferUp[n]; //запишем ценовое значение  фрактала в массив
            FromBarUp=n+1; //--- запишем новый стартовый индекс в переменную
            UpFNumber[i]=n; //записываем порядковый номер в массив
            break;
           }
        }
      for(int n=FromBarLow; n<BarCount; n++)
        {
         //--- если непустое значение, прерываем цикл
         if(copyBufferLow[n]!=EMPTY_VALUE && copyBufferLow[n]>0)
           {
            LowFArray[i]=copyBufferLow[n]; //запишем ценовое значение  фрактала в массив
            FromBarLow=n+1; //--- запишем новый стартовый индекс фрактала в переменную
            LowFNumber[i]=n; //записываем порядковый номер в массив
            break;
           }
        }
     }


Теперь собственно проблема. Не смотря на условия индикатора по записи EMPTY_VALUE , в советнике в буфер я периодически получаю значения экспотенциального вида (например, 3.3745345789435e-308, -9.43251234232-e309 и т.д.). Они проходят условия проверки (не являются EMPTY_VALUE и больше 0),советник думает, что это фрактал и пытается зайти в рынок. Данные значения никак не пересекаются с именованными константами.

Природа происхождения таких ситуаций непонятна. Находил подобную тему, но проблема раскрыта не была.

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

Помогите разобраться пожалуйста.

 

-9.xxx не больше нуля (минус же!)

3.3745345789435e-308 меньше DBL_EPSILON, я бы его тоже считал нулём.

вместо >0 попробуйте >DBL_EPSILON или >0.0001... В зависимости от ваших допусков. Обычно, вещественные числа строгими рамками не сравнивают.

Есть тут темка про число знаков после запятой - вопрос из той же серии. 

 

я пробывал нормализовывать вот таким образом

copyBufferLow[n]!=EMPTY_VALUE && NormalizeDouble(copyBufferLow)[n])>0

Большая часть экспотенциальных значений становится =0, но попадаются те, которые например стали =5 (хотя цена 60+ $). Сейчас пробую снова отловить такие моменты, чтобы понять какое экс число было.

Непонятно в принципе почему такое происходит вопреки логике индикатора.

 
Илья Ребенок:

В исходнике индикатора явно прописано в любые значения, кроме high/low вставлять EMPTY_VALUE (что свою очередь соответствует DBL_MAX=1.7976931348623158e+308)

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

Поэтому для начала нужно проверить наличие инициализации каждого элемента буфера индикатора.

 
Ihor Herasko:

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

Поэтому для начала нужно проверить наличие инициализации каждого элемента буфера индикатора.

Могло ли данное поведение быть связано с тем, что в индикаторе у меня инициализация буферов происходила таким образом
ArrayInitialize(ExtUpperBuffer,0); // инициализируем массивы
ArrayInitialize(ExtLowerBuffer,0);

При этом буферы типа double. По мне так в этом случае при инициализации массива могло записываться эксп число очень высокой точности, но при этом больше 0. Могла быть в этом причина?

Сейчас изменил на

ArrayInitialize(ExtUpperBuffer,EMPTY_VALUE); // инициализируем массивы
ArrayInitialize(ExtLowerBuffer,EMPTY_VALUE);

Буду проводить тесты.

 

хотя странно все равно получается.

При первичном запуске индикатора инициализируется общий массив без размера

ArrayInitialize(ExtUpperBuffer,EMPTY_VALUE); // инициализируем массивы
ArrayInitialize(ExtLowerBuffer,EMPTY_VALUE);

Новые элементы массива могут быть уже не EMPTY_VALUE, но ведь эти кодом мы им явно назначаем значение

if(UpFound) ExtUpperBuffer[i]=high[i];
else ExtUpperBuffer[i]=EMPTY_VALUE;
if(DownFound) ExtLowerBuffer[i]=low[i];
else ExtLowerBuffer[i]=EMPTY_VALUE;

Здесь мы явно указываем что и как, то есть неопределенных элементов быть не должно. Они либо EMPTY_VALUE, либо цена high/low.

Ihor Herasko, как считаете?

 
Илья Ребенок:
Могло ли данное поведение быть связано с тем, что в индикаторе у меня инициализация буферов происходила таким образом

При этом буферы типа double. По мне так в этом случае при инициализации массива могло записываться эксп число очень высокой точности, но при этом больше 0. Могла быть в этом причина?

Сейчас изменил на

Буду проводить тесты.

Я имею в виду немного другое. К примеру, на момент выполнения инициализации буферов индикатора размер этого массива составляет 1 000 баров. Затем образуется новый бар. Терминал изменяет размер массива (индикаторного буфера), добавляя еще один элемент. Теперь массив имеет 1 001 элемент, но инициализация всего массива ведь не происходила. Получаем, что в этом новом элементе содержится мусор.

Чтобы исправить ситуацию, нужно убедиться, что в момент появления нового бара значение нового элемента массива точно инициализируется. Самый простой способ проведения такой инициализации (если не хочется копаться в коде) - на каждом тике  при входе в OnCalculate() присваивать последнему элементу массива значение 0.0 или EMPTY_VALUE. Но правильнее, конечно, проверить логику кода и вставить инициализацию там, где она действительно нужна.

 

я к тому, что в индикаторе при инициализации нового элемента сразу присваивается значение. Вот тело  onCalculate.

int i,limit;
//---Если всего свечей меньше суммы левого, правого диапазона и центальной свечи, то ничего не делаем
   if(rates_total<LeftBars+RightBars+1)
      return(0);

   if(prev_calculated<1) 
     {
      limit=LeftBars;
      //--- clean up arrays
      ArrayInitialize(ExtUpperBuffer,EMPTY_VALUE); // инициализируем массивы
      ArrayInitialize(ExtLowerBuffer,EMPTY_VALUE);
     }
   else
      limit=rates_total-RightBars-2; 
   for(i=limit;i<rates_total-RightBars-1 && !IsStopped();i++) // от стартовой свечи до общего кол-ва свечей - правый диапазон
     {
      bool UpFound=true;
      bool DownFound=true;
      //циклами проходимся по свечам обоих диапазонов и сравниваем с центральной
      for(int j=1;j<=LeftBars;j++) 
        {
         if(high[i-j]>high[i]) UpFound=false;
         if(low[i-j]<low[i]) DownFound=false;
        }
      for(int j=1;j<=RightBars;j++)
        {
         if(high[i+j]>=high[i]) UpFound=false;
         if(low[i+j]<=low[i]) DownFound=false;
        }
      if(UpFound) ExtUpperBuffer[i]=high[i];
      else ExtUpperBuffer[i]=EMPTY_VALUE;
      if(DownFound) ExtLowerBuffer[i]=low[i];
      else ExtLowerBuffer[i]=EMPTY_VALUE;
     }
   return (rates_total); 

По идее элемент не может остаться не инициализированным при таком коде.

 
Илья Ребенок:

я к тому, что в индикаторе при инициализации нового элемента сразу присваивается значение. Вот тело  onCalculate.

По идее элемент не может остаться не инициализированным при таком коде.

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

 
Ihor Herasko:

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

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

В советнике в функции получения данных с этого индикатора после копирования в буфер применяю ArraySetAsSeries .

ArraySetAsSeries(copyBufferUp,true); // порядок как в таймериях. От нового к старому
ArraySetAsSeries(copyBufferLow,true);

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

 
Илья Ребенок:

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

Понятно. Тогда ответ тот, о котором я говорю с самого начала: цикл 

for(i=limit;i<rates_total-RightBars-1 && !IsStopped();i++)

обрабатывает не все бары.

Например, rates_total = 100, RightBars = 5 и это не первый вызов индикатора.

Тогда limit = 93, а цикл i обработает только один бар - 93. Остальные бары (94 - 99) останутся неинициализированными. Вот там и будет мусор. Нужно позаботиться об инициализации этих элементов массива сразу при появлении соответствующих баров.