Strategy Test become drastically slow (Visual Mode) after adding this indicator class to my strategy

 

Hello Friends

I have created CiZigZag.mqh indicator class to get Major/Minor High/Low values. However after adding this class to my strategy, the tester speed has drastically reduced. Now even after I have removed this class, the tester has not restored to the earlier speed and still slow.

I hope the gurus here will help me out.

Attached are relevant files to run the class. 

#include "../../Includes/Base/BaseIndicator.mqh"

                struct SZigZag {
                        int      idx;
                        double price;
                };

#define bufferMajorLO 0
#define bufferMajorHI 1
#define bufferMinorLO 2
#define bufferMinorHI 3
//+-----------------------------------------------------------------------------------------------------------------------------+
//| CLASS:        CiZigZag.mqh
//| APPLICATION:  RETURNS CUSTOM INDICATOR ZigZag.mq5 VALUES
//+-----------------------------------------------------------------------------------------------------------------------------+
class CiZigZag final : public CBaseIndicator {

public:

          CiZigZag() : CBaseIndicator(_Symbol,PERIOD_CURRENT) { }

          CiZigZag(string pSymbol,ENUM_TIMEFRAMES pTimeFrame,int pZZSlowPeriod,int pZZFastPeriod)
                : CBaseIndicator(pSymbol,pTimeFrame) {
                        Init(pZZSlowPeriod,pZZFastPeriod);
                }
         ~CiZigZag() { IndicatorRelease(mHandleZZ); }

private:
          void      Init(int pZZSlowPeriod,int pZZFastPeriod);

private:

          int                                   mHandleZZ;
          int           mSlowPeriod;                    // ZIG ZAG SLOW PERIOD (MAJOR SWING)
          int           mFastPeriod;                    // ZIG ZAG FAST PERIOD (MINOR SWING)
          int           mBarStart;
          int           mLookBackMax;     // lookback Maximum No of Bars to find High/Low Index/Value
          int           mMaxIndex;        // lookback Major/Minor No of Index/Values
          int                                   mSize;            // Array size

  // MEMBER METHODS FOR INTERNAL CALCULATIONS
          void        GetMajorLO(SZigZag &pMajorLO[]);
          void        GetMajorHI(SZigZag &pMajorHI[]);
          void        GetMinorLO(SZigZag &pMinorLO[]);
          void        GetMinorHI(SZigZag &pMinorHI[]);
          double      GetIndexZZ(int pBufferNo,int pIndex);

public:

                void                            GetArrayZZAll(SZigZag &pMajorLO[],SZigZag &pMajorHI[],SZigZag &pMinorLO[],SZigZag &pMinorHI[]);
                void                            GetArrayMajor(SZigZag &pMajorLO[],SZigZag &pMajorHI[]);
                void                            GetArrayMinor(SZigZag &pMinorLO[],SZigZag &pMinorHI[]);

}; // END Of Class Definition

void CiZigZag::Init(int pZZSlowPeriod,int pZZFastPeriod) {

                // ASSIGN OR SET ZigZag INDICATOR PARAMETERS
          mSlowPeriod  = pZZSlowPeriod;
          mFastPeriod  = pZZFastPeriod;
          mBarStart    = 0;               // SET AT 'Zero' TO ENABLE RETURNING ACTUAL BAR INDEX OF CHART WITH CounterHI/LO
          mLookBackMax = 500;                   // MAXIMUM BARS TO LOOK BACK
          mMaxIndex    = 5;                                     // LOOK FOR MAXIMUM OF 'n' ZigZag HIGH / LOW VALUES
          mSize        = mMaxIndex + 1;   // ALLOW ONE EXTRA ARRAY ELEMENT SPACE FOR INDEX[0]

                // DECLARE AND CHECK VALIDITY ON HANDLE
          TesterHideIndicators(true);
          //mHandleZZ = iCustom(mSymbol,mTimeFrame,"::" + iZigZagPath,mSlowPeriod,mFastPeriod);
          mHandleZZ = iCustom(mSymbol,mTimeFrame,"Indicators\\BNB\\Trend\\iZigZag",mSlowPeriod,mFastPeriod);
          if(mHandleZZ == INVALID_HANDLE) {
                        ResetLastError();
            PrintFormat("%s: Error[%i] creating handle for iZigZag",string(__FUNCTION__),GetLastError());
          }
          TesterHideIndicators(false);

                //return(INIT_SUCCEEDED);

} // END Of method Init()

void CiZigZag::GetArrayZZAll(SZigZag &pMajorLO[],SZigZag &pMajorHI[],SZigZag &pMinorLO[],SZigZag &pMinorHI[]) {

          GetMajorLO(pMajorLO);
          GetMajorHI(pMajorHI);

          GetMinorLO(pMinorLO);
          GetMinorHI(pMinorHI);

} // END Of method GetArrayZZAll()

void CiZigZag::GetArrayMajor(SZigZag &pMajorLO[],SZigZag &pMajorHI[]) {

          GetMajorLO(pMajorLO);
          GetMajorHI(pMajorHI);

} // END Of method GetArrayMajor()

void CiZigZag::GetArrayMinor(SZigZag &pMinorLO[],SZigZag &pMinorHI[]) {

          GetMinorLO(pMinorLO);
          GetMinorHI(pMinorHI);

} // END Of method GetArrayZZAll()

void CiZigZag::GetMajorLO(SZigZag &pMajorLO[]) {

                // CHECK HANDLE IS VALID, ELSE INITIALZE AGAIN
          if(mHandleZZ == INVALID_HANDLE)                                                                                                                                                       Init(mFastPeriod,mSlowPeriod);

                // PREPARE THE PASSED IN ARRAY
                ArraySetAsSeries(pMajorLO,true);
                ArrayResize(pMajorLO,mSize);

                // ARRAY INDEX[0] INTIALIZED WITH NULL VALUES TO MATCH MajorLO[1] WITH ARRAY INDEX[1]
                pMajorLO[0].idx         = 0;
                pMajorLO[0].price = 0.00;

                // LOOP UNTIL FOUND REQUIRED NUMBER OF MajorLO VALUES
                int      count   = 0;
                double priceZZ = 0.00;

                for(int i = mBarStart; i < mLookBackMax; i++) {

            priceZZ = GetIndexZZ(bufferMajorLO,i);                                                                                                                      // GET ZigZag[i] VALUE FOR bufferMajorLO
                        if(priceZZ <= 0.00)                     continue;                                                                                                                                               // CONTINUE TO NEXT INDEX IN LOOP

            if(count <= mMaxIndex) {                                                                                                                                                                    // ADD VALUE TO pMajorLO ARRAY
              pMajorLO[count+1].idx     = i;                                                                                                                                                    // ON FIRST MajorLO, count = 0 + 1 FOR INDEX[1]
              pMajorLO[count+1].price = priceZZ;
              count++;
            }

            if(count >= mMaxIndex)      return;                                                                                                                 // EXIT, IF REQUIRED mMaxIndex VALUES ARE FOUND
          }

} // END Of method GetMajorLO()

void CiZigZag::GetMajorHI(SZigZag &pMajorHI[]) {

                // CHECK HANDLE IS VALID, ELSE INITIALZE AGAIN
          if(mHandleZZ == INVALID_HANDLE)                                                                                                                                                       Init(mFastPeriod,mSlowPeriod);

                // PREPARE THE PASSED IN ARRAY
                ArraySetAsSeries(pMajorHI,true);
                ArrayResize(pMajorHI,mSize);

                // ARRAY INDEX[0] INTIALIZED WITH NULL VALUES TO MATCH MajorHI[1] WITH ARRAY INDEX[1]
                pMajorHI[0].idx         = 0;
                pMajorHI[0].price = 0.00;

                // LOOP UNTIL FOUND REQUIRED NUMBER OF MajorHI VALUES
                int      count   = 0;
                double priceZZ = 0.00;

          for(int i = mBarStart; i < mLookBackMax; i++) {

            priceZZ = GetIndexZZ(bufferMajorHI,i);                                                                                                                      // GET ZigZag[i] VALUE FOR bufferMajorHI
                        if(priceZZ <= 0.00)                     continue;                                                                                                                                               // CONTINUE TO NEXT INDEX IN LOOP

            if(count <= mMaxIndex) {                                                                                                                                                                    // ADD VALUE TO pMajorLO ARRAY
              pMajorHI[count+1].idx     = i;                                                                                                                                                    // ON FIRST MajorHI, count = 0 + 1 FOR INDEX[1]
              pMajorHI[count+1].price = priceZZ;
              count++;
            }

        if(count >= mMaxIndex)   return;                                                                                                                // EXIT, IF REQUIRED mMaxIndex VALUES ARE FOUND
        }

} // END Of method GetMajorHI()

void CiZigZag::GetMinorLO(SZigZag &pMinorLO[]) {

                // CHECK HANDLE IS VALID, ELSE INITIALZE AGAIN
          if(mHandleZZ == INVALID_HANDLE)                                                                                                                                                       Init(mFastPeriod,mSlowPeriod);

                // PREPARE THE PASSED IN ARRAY
                ArraySetAsSeries(pMinorLO,true);
                ArrayResize(pMinorLO,mSize);

                // ARRAY INDEX[0] INTIALIZED WITH NULL VALUES TO MATCH MinorLO[1] WITH ARRAY INDEX[1]
                pMinorLO[0].idx         = 0;
                pMinorLO[0].price = 0.00;

                // LOOP UNTIL FOUND REQUIRED NUMBER OF MinorLO VALUES
                int      count   = 0;
                double priceZZ = 0.00;

          for(int i = mBarStart; i < mLookBackMax; i++) {

            priceZZ = GetIndexZZ(bufferMinorLO,i);                                                                                                                      // GET ZigZag[i] VALUE FOR bufferMinorLO
                        if(priceZZ <= 0.00)                     continue;                                                                                                                                               // CONTINUE TO NEXT INDEX IN LOOP

            if(count <= mMaxIndex) {                                                                                                                                                                    // ADD VALUE TO pMinorLO ARRAY
              pMinorLO[count+1].idx     = i;                                                                                                                                                    // ON FIRST MinorLO, count = 0 + 1 FOR INDEX[1]
              pMinorLO[count+1].price = priceZZ;
              count++;
            }

            if(count >= mMaxIndex)   return;                                                                                                            // EXIT, IF REQUIRED mMaxIndex VALUES ARE FOUND
          }

} // END Of method GetMinorLO()

void CiZigZag::GetMinorHI(SZigZag &pMinorHI[]) {

                // CHECK HANDLE IS VALID, ELSE INITIALZE AGAIN
          if(mHandleZZ == INVALID_HANDLE)                                                                                                                                                       Init(mFastPeriod,mSlowPeriod);

                // PREPARE THE PASSED IN ARRAY
                ArraySetAsSeries(pMinorHI,true);
                ArrayResize(pMinorHI,mSize);

                // ARRAY INDEX[0] INTIALIZED WITH NULL VALUES TO MATCH MinorHI[1] WITH ARRAY INDEX[1]
                pMinorHI[0].idx         = 0;
                pMinorHI[0].price = 0.00;

                // LOOP UNTIL FOUND REQUIRED NUMBER OF MinorHI VALUES
                int      count   = 0;
                double priceZZ = 0.00;

        for(int i = mBarStart; i < mLookBackMax; i++) {

            priceZZ = GetIndexZZ(bufferMinorHI,i);                                                                                                                      // GET ZigZag[i] VALUE FOR bufferMinorHI
                        if(priceZZ <= 0.00)                     continue;                                                                                                                                               // CONTINUE TO NEXT INDEX IN LOOP

            if(count <= mMaxIndex) {                                                                                                                                                                    // ADD VALUE TO pMinorLO ARRAY
              pMinorHI[count+1].idx     = i;                                                                                                                                                    // ON FIRST MinorHI, count = 0 + 1 FOR INDEX[1]
              pMinorHI[count+1].price = priceZZ;
              count++;
            }

            if(count >= mMaxIndex)   return;                                                                                                            // EXIT, IF REQUIRED mMaxIndex VALUES ARE FOUND
          }

} // END Of method GetMinorHI()

double CiZigZag::GetIndexZZ(int pBufferNo,int pIndex) {

        double bufferData[1];                                                                                                                                                                                                   // DEFINE LOCAL SINGLE ELEMENT STATIC BUFFER

          if(CopyBuffer(mHandleZZ,pBufferNo,pIndex,1,bufferData) < 1) {
                        ResetLastError();
            PrintFormat("%s: Copy data Error[%i] iZigZag Buffer#[%i] Index[%i]",string(__FUNCTION__),GetLastError(),pBufferNo,pIndex);
            return(0.0);
          }

          return(bufferData[0]);

} // END Of method GetIndexZZ()

Files:
iZigZag.mqh  13 kb
iZigZag.ex5  13 kb
iZigZag.mq5  19 kb
 

Haven't tried to load and run this code, because it somewhat feels tedious to be honest.

But, read the indicator main file, it seems to me the limit calculation is responsible to one of the faults.

Maybe try to replace it with

limit  = MathMin(rates_total-prev_calculated,min_rates_total);
 
Anil Varma: after I have removed this class, the tester has not restored to the earlier speed and still slow.

Then your problem is not the class. It must be your code, or your tester speed setting.

 
Amir Yacoby #:

Haven't tried to load and run this code, because it somewhat feels tedious to be honest.

But, read the indicator main file, it seems to me the limit calculation is responsible to one of the faults.

Maybe try to replace it with

@Amir Yacoby Thanks for reply.

With the change suggested, it does not find correct ZigZag points, as I got result Index as zero in my strategy.

 
William Roeder #:

Then your problem is not the class. It must be your code, or your tester speed setting.

@William Roeder thanks for reply.

I did not change anything in the code. Just added this class (before that tester was working and lighting speed !)) and found tester is working slow, so removed the class but still tester is slow.

I did check the tester speed, earlier at quarter of speed it was flying but now at full speed too it is dam slow. 

Is there any way I can found if the code has problem ?

Also my work station has 8 cores but tester uses only Core 1, is there any setting need to be done to use all the cores ?

 
Anil Varma #:

@Amir Yacoby Thanks for reply.

With the change suggested, it does not find correct ZigZag points, as I got result Index as zero in my strategy.

try

limit  = MathMin(rates_total-prev_calculated,min_rates_total+1);

Because you clculate all the bars on each tick, so just check the minimum bars needed to calculate for correct zigzag logic, which should be in direct relation with min_rates_total

 
Amir Yacoby #:

try

Because you clculate all the bars on each tick, so just check the minimum bars needed to calculate for correct zigzag logic, which should be in direct relation with min_rates_total

@Amir Yacoby

Hi Amir

Thanks for taking off your time to review my post.

However, I am of the opinion that the problem is in Indicator Class (not indicator) as it loops to find non zero values from indicator buffer.

I would be thankful, if you can spare some time to review the indicator class and see if my code does take too much resources.

Regards 

 
Anil Varma #:

@Amir Yacoby

Hi Amir

Thanks for taking off your time to review my post.

However, I am of the opinion that the problem is in Indicator Class (not indicator) as it loops to find non zero values from indicator buffer.

I would be thankful, if you can spare some time to review the indicator class and see if my code does take too much resources.

Regards 

So how do you explain that without the class it's still not solved? And why the indicator needs to loop all bars on each tick? If you just place the indicator alone on a chart, like now it's weekend but you can place it on like BTCUSD which has ticks on weekends and  see in the resources if it is heavy when standalone. 

Or just test it alone with strategy tester
 
Anil Varma #:

@Amir Yacoby

Hi Amir

Thanks for taking off your time to review my post.

However, I am of the opinion that the problem is in Indicator Class (not indicator) as it loops to find non zero values from indicator buffer.

I would be thankful, if you can spare some time to review the indicator class and see if my code does take too much resources.

Regards 

Try with first limit calculation before first loop:

limit  = MathMax((int)(rates_total-prev_calculated-SlowLength-1),(int)(SlowLength+1));

And second limit calculation before second loop 

  //+--------------------------------------------------------------------------------------------------------+
  //| Calculate 'Minor' Swing High/Low
  //+--------------------------------------------------------------------------------------------------------+
    
    limit  = MathMax((int)(rates_total-prev_calculated-FastLength-1),(int)(FastLength+1));
    Swing   = 0;
...
 
Anil Varma #: I did not change anything in the code.
Really? You previously posted:
Anil Varma: after I have removed this class, the tester has not restored to the earlier speed and still slow.
and now have removed that.
 
William Roeder #:
Really? You previously posted: and now have removed that.

@William Roeder

Hi William

What I mean to say after I added this class and related logic, the tester become very slow.

So I removed this class and related logic, but then the tester continued to be slow. Though before the first step of adding class, the tester was working very well.

There was no other changes.

Hope you got what I mean to say!!!