Array Out of Range error

 

Hello forum, good day.

I need help identifying why am I getting an Array Out of Range error so I can solve this. What I'm trying to do is to move right and left 'N' number of bars from a certain point in a Moving Average. The problem occurs 10 bars or so after starting the Strategy Tester. I have tested the code that moves to the right from a certain point in the MA(7) (commented the code that moves to the left) and the Strategy Tester runs without any problem, but when I test the code that moves to the left is when the error happens. Your help will be much appreciated.

 

The coloured line is the one that triggers the Array Out of Range error. So far, I assume that the error has to do with the limit I'm setting for that loop. Here is the code:

input int                Waves       = 5;
input int                Threshold   = 5;
input int                MA_1_Period = 7;
input ENUM_MA_METHOD     MA_1_Method = MODE_SMA;
input ENUM_APPLIED_PRICE MA_1_Price  = PRICE_CLOSE;
input int                MA_1_Shift  = 0;

int                      PipFactor   = 1;
double                   Valley[];
datetime                 Valley_Time[];

void fnGetMAWaves()
  {
    int i, j, k,
        i_valley   = 0,
        wave_count = 0,
        limit      = MathMin( 100, iBars( NULL, 0 ) );

    double MA_Value[];  ArrayResize( MA_Value, limit );  ArrayInitialize( MA_Value, 0 );
    double MA_Valley[]; ArrayResize( MA_Valley, limit ); ArrayInitialize( MA_Valley, EMPTY_VALUE );

    ArrayResize( Valley, Waves ); ArrayResize( Valley_Time, Waves );

    for ( i = 0; i < limit; i++ )
      {
        // Get MA(7) values
        MA_Value[i] = iMA( NULL, 0, MA_1_Period, MA_1_Shift, MA_1_Method, MA_1_Price, i );
      }

    for ( i = 2; i < limit - 1; i++ )
      {
        // Wave valley
        if ( MA_Value[i] <= MA_Value[i - 1] && MA_Value[i] < MA_Value[i + 1] )
          {
            MA_Valley[i] = MA_Value[i];
            i_valley     = i;
            wave_count++;

            if ( MA_Valley[i_valley] != EMPTY_VALUE )
              {
                int    wave_limit = MathMin( i_valley, iBars( NULL, 0 ) ) + 20;
                double Range_Left, Range_Right;

                // Move left from the valley
                for ( j = i_valley; j < wave_limit; j++ )
                  {
                    Range_Left = NormalizeDouble( ( MA_Value[j] - MA_Valley[i_valley] ) / Point, Digits ) / PipFactor;

                    // Print( "i: ", i, ". j: ", j );
                    // Print( "Range Left: ", Range_Left );

                    if ( Range_Left >= Threshold )
                      {
                        fnDrawDot( "Wave range left " + j, Time[j], MA_Value[j], 159, 20, "Wingdings", clrBlack );
                        break;
                      }
                  }

                // Move right from the valley
                for ( k = i_valley; ( k <= i_valley && k >= i_valley - 20 ) && k > 0; k-- )
                  {
                    Range_Right = NormalizeDouble( ( MA_Value[k] - MA_Valley[i_valley] ) / Point, Digits ) / PipFactor;

                    // Print( "i: ", i, ". k: ", k );
                    // Print( "Range Right: ", Range_Right );

                    if ( Range_Right >= Threshold )
                      {
                        fnDrawDot( "Wave range right " + k, Time[k], MA_Value[k], 159, 20, "Wingdings", clrBlack );
                        break;
                      }
                  }
              }
          }

        if ( wave_count > Waves - 1 ) break;
      }

    // Draw a dot on each valley
    int counter = 0;
    for ( i = 2; i < limit - 1; i++ )
      {
        if ( MA_Valley[i] != EMPTY_VALUE )
          {
            Valley[counter]      = MA_Valley[i];
            Valley_Time[counter] = Time[i];
            fnDrawDot( "Wave valley " + counter, Valley_Time[counter], Valley[counter], 159, 20, "Wingdings", clrRed );
            counter++;
          }

        if ( counter >= Waves ) break;
      }
  } //--- end fnGetMAWaves()

int fnDrawDot( string obj_name, datetime obj_time, double obj_level, uchar obj_char_code, int obj_font_size, string obj_font, color obj_color )
  {
    ObjectCreate( 0, obj_name, OBJ_TEXT, 0, 0, 0 );
    ObjectSetInteger( 0, obj_name, OBJPROP_TIME1, obj_time );
    ObjectSetDouble( 0, obj_name, OBJPROP_PRICE1, obj_level );
    ObjectSetText( obj_name, CharToStr( obj_char_code ), obj_font_size, obj_font, obj_color );
    return( 0 );
  } //--- end fnDrawDot()

int OnInit()
  {
    //---
    if ( Digits == 3 || Digits == 5 ) PipFactor = 10;

    //---
    return( INIT_SUCCEEDED );
  } //--- end OnInit()

void OnTick()
  {
    //---
    fnGetMAWaves();
  } //--- end OnTick()

//+------------------------------------------------------------------+


Best regards and thank you in advance, 

Gerardo

 
Gerardo Bustos:

Hello forum, good day.

I need help identifying why am I getting an Array Out of Range error so I can solve this. What I'm trying to do is to move right and left 'N' number of bars from a certain point in a Moving Average. The problem occurs 10 bars or so after starting the Strategy Tester. I have tested the code that moves to the right from a certain point in the MA(7) (commented the code that moves to the left) and the Strategy Tester runs without any problem, but when I test the code that moves to the left is when the error happens. Your help will be much appreciated.

 

The coloured line is the one that triggers the Array Out of Range error. So far, I assume that the error has to do with the limit I'm setting for that loop. Here is the code:


Best regards and thank you in advance, 

Gerardo

Try using MathAbs() function to eliminate the possibility of a minus value.
 
Marco vd Heijden:

I always solve these things like so:


But you might want to re write some stuff in a way that you have two blocks that cover two directions in stead of trying to use one block to cover two directions.

Thanks a lot for the tips Marco, I'll give it a try.

Best regards, 
Gerardo
 
Gerardo Bustos:
Thanks a lot for the tips Marco, I'll give it a try.

Best regards, 
Gerardo

Well i removed it since it was not the correct solution it will still first hit the out of range and then try to reset the value so that does not work it only works for counts without array.

You could at least try

ArrayResize( MA_Value, Bars);

But if it is trying to read negative value it will still give the error so you have to make sure the value exists before trying to read it.

 
                // Move left from the valley
                for ( j = i_valley; j < wave_limit; j++ )
                  {
                    if(j<0){j=0;}if(i_valley<0){i_valley=0;}
                    Range_Left = NormalizeDouble( ( MA_Value[j] - MA_Valley[i_valley] ) / Point, Digits ) / PipFactor;

                    // Print( "i: ", i, ". j: ", j );
                    // Print( "Range Left: ", Range_Left );

                    if ( Range_Left >= Threshold )
                      {
                        fnDrawDot( "Wave range left " + j, Time[j], MA_Value[j], 159, 20, "Wingdings", clrBlack );
                        break;
                      }
                  }

But that also can not work since you are using j in a loop... so if you modify j you infect the loop.

 
An array index has to be 2 things.  An integer, and if something other than zero, a positive number.  Anything that changes it to something other than those will most likely give your program fits.  Using your for loop values like you are, you have to be very careful that you do not inadvertently do that.