Обсуждение статьи "Рецепты MQL5 - Создаем кольцевой буфер для быстрого расчета индикаторов в скользящем окне" - страница 4

 
Otto Pauser:

Отличная статья, человек умеет программировать!

Если бы только немецкий перевод не был таким ужасным!!!!!

Здравствуйте,

Большое спасибо за подсказку. Перевод был исправлен.

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

 

Доброго времени суток, Vasiliy Sokolov!

Ваши индикаторы созданные при помощи кольцевого буфера показывают как то не внятно, походу метод ChangeValue не работает, или может я что-то не так понял? 

 
Savio Araujo:

Я видел это. Я проверил приведенные вами примеры. Они показывают ту же проблему, что и у меня, когда я имею дело с обновлением значений во время работы рынка. Проверьте предоставленный вами Stochastic. Добавление нового значения не является проблемой, но когда мы пытаемся использовать Stoch.ChangeLast() или OnChangeValue() в классе CRiMaxMin, это не работает. Он не изменяет значение соответствующим образом. Если бы вы могли проверить это или прислать пример рабочего кода, это было бы очень здорово.

Спасибо.

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

int RingBuffer::iToRealInd(int iIndex)

{

   if(iIndex >= iNumElements() || iIndex < 0)

      return iBufferSize-1; //previous bug was caused by no -1 here

...

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

 
Почему в CRiStoch нет метода ChangeValue?
 
brisully:

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

int RingBuffer::iToRealInd(int iIndex)

{

   if(iIndex >= iNumElements() || iIndex < 0)

      return iBufferSize-1; //previous bug was caused by no -1 here

...

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

Я попробовал ваше исправление, но оно все еще не обновляется правильно. Кажется, что чего-то не хватает, и я не могу найти проблему при попытке запустить кольцевой буфер при формировании нового бара. Когда рынок работает, линии High/Low полностью перепутываются. Код работает очень хорошо и быстро при обработке старых данных, но с новыми данными, поступающими во время формирования нового бара, он просто не работает для меня.

 
Василий, спасибо за код! Очень выручает.
Если позволите, такие замечания:

1. В классе void CRiMaxMin::OnChangeValue(int index, double del_value, double new_value),в методе  " OnChangeValue" в строке 
if(m_min_ind >= 0 && new_value >= GetValue(m_min_ind))
      m_min_ind = index;

Картинка: опечатка?


опечатка - знак "меньше или равно".

2.При поиске Min и Max элементов массива, если использовать именно как кольцевой буфер (когда новые элементы начинают писаться в начало массива), min и мах определяются неправильно. Минимум больше максимума. В одном массиве. Стандартными методами (ArrayMinimum и ArrayMaximum) все работает.
Картинка: Минимум больше Максимума

Где-то сбивается индексация. Починить сам не могу. Если кто починит, будет здорово. Проверочный советник прикрепил.

#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include  <RingBuffer\RiMaxMin.mqh>

input group "Проверка через кольцевой буфер - true"
input bool ringBuffer=true;


input group "Размер буфера"
input int pTest=10;

double minValue,maxValue;
int minIndex,maxIndex,lastIndex,indArr;

double arr[];

CRiMaxMin minMaxTest;

int OnInit()
  { 
   if(ringBuffer)minMaxTest.SetMaxTotal(pTest);
   else  
      {
      indArr=-1;
      lastIndex=pTest-1;
      ArraySetAsSeries(arr,true);
      ArrayResize(arr,pTest);
      }
   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   
   
  }

void OnTick()
  {
   if(ringBuffer)
      {
      minMaxTest.AddValue(rand());
      minIndex=minMaxTest.MinIndex();
      minValue=minMaxTest.GetValue(minIndex);
      //minValue=minMaxTest.MinValue();
      maxIndex=minMaxTest.MaxIndex();
      maxValue=minMaxTest.GetValue(maxIndex);
      //maxValue=minMaxTest.MaxValue();
      }
   else
      {
      //arr[0]=rand();
      //ArrayCopy(arr,arr,1,0,lastIndex);
      indArr++;
      if(indArr>lastIndex)indArr=0;
      arr[indArr]=rand();
      minIndex=ArrayMinimum(arr,0,pTest);
      minValue=arr[minIndex];
      //minValue=arr[ArrayMinimum(arr,0,pTest)];
      maxIndex=ArrayMaximum(arr,0,pTest);
      maxValue=arr[maxIndex]; 
      //maxValue=arr[ArrayMaximum(arr,0,pTest)];
      }  
   Alert("minValue ",DoubleToString(minValue)," --  maxValue ",DoubleToString(maxValue));
   if(minValue>maxValue)
      {
      Alert("Мин  > Mакс !!!");
      Print("Мин  > Mакс !!!");
      ExpertRemove();
      }
  }
Файлы:
 
Извиняюсь. Min и Max считает правильно. Сам я перемудрил.
 
Это, как раз, то, что мне нужно. Спасибо за код и такую подробную статью. Идея с оптимизацией поиска экстремумов - здорово придумано!
 

У Вас там ошибочка закралась в ToRealInd(int index).

Должно быть:
   if(index >= GetTotal() || index < 0)
      return m_max_total-1;