Discussion of article "MQL5 Cookbook - Creating a ring buffer for fast calculation of indicators in a sliding window" - page 4

 
Otto Pauser:

A great article, the man can programme!

If only the German translation wasn't so horrible!!!!!

Hello,

Many thanks for the tip. The translation has been corrected.

Best regards

 

Good day, Vasiliy Sokolov!

Your indicators created with the help of ring buffer show something unclear, I guess the ChangeValue method doesn't work, or maybe I misunderstood something?

 
Savio Araujo:

I have seen it. As I have checked the examples you provided. They show the same problem I had when dealing with updating the values while the market is running. Check the Stochastic you provided. Adding a new value is not a problem, but when we try to use Stoch.ChangeLast() or OnChangeValue() in CRiMaxMin class, it does not work. It does not change the value accordingly. If you could check it or send an example of a working code, that would be very nice.

Thank you.

Great work here, many thanks to the author. Perhaps the bug you're seeing, Savio, is here:

int RingBuffer::iToRealInd(int iIndex)

{

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

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

...

I added the -1 on the last quoted line; it wasn't there before and would cause an improper index to be returned. Note that I changed variable/method names to my style of programming but it's the same idea.

 
Why does not CRiStoch have a method called ChangeValue?
 
brisully:

Great work here, many thanks to the author. Perhaps the bug you're seeing, Savio, is here:

int RingBuffer::iToRealInd(int iIndex)

{

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

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

...

I added the -1 on the last quoted line; it wasn't there before and would cause an improper index to be returned. Note that I changed variable/method names to my style of programming but it's the same idea

I tried your correction, but it still does not update right. It seems there is something missing and I can't find the problem when trying to run the ring buffer in the formation of a new bar. When the market is running, the High/Low lines get completly mixed up. The code works very well and very quick while processing old data, but with new data arriving during the formation of a new bar, it simply does not work for me.

 
Vasily, thanks for the code! It helps a lot.
If I may make some comments:

1. In the class void CRiMaxMin::OnChangeValue(int index, double del_value, double new_value), in the method " OnChangeValue" in the line
.
if(m_min_ind >= 0 && new_value >= GetValue(m_min_ind))
      m_min_ind = index;

Picture: typo?


typo - sign "less than or equal to".

2.When searching for Min and Max elements of an array, if used exactly as a ring buffer (when new elements start to be written to the beginning of the array), min and mah are defined incorrectly. The minimum is greater than the maximum. In one array. Everything works using standard methods (ArrayMinimum and ArrayMaximum).
Picture: Minimum is greater than Maximum

Somewhere indexing is going astray. I can't fix it myself. If someone can fix it, it would be great. I have attached a test advisor.

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

#include  <RingBuffer\RiMaxMin.mqh>

input group "Checking through ring buffer is true."
input bool ringBuffer=true;


input group "Buffer size."
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("Min > Max !!!");
      Print("Min > Max !!!");
      ExpertRemove();
      }
  }
Files:
 
I apologise. Min and Max are correct. I was overthinking it myself.
 
This is exactly what I need. Thanks for the code and such a detailed article. The idea of optimising the search for extrema is great!
 

You have a mistake in ToRealInd(int index).

It should be:
if(index >= GetTotal() || index < 0 )
return m_max_total-1;