Array out of range !? why

 
//+------------------------------------------------------------------+
//|                                                        HighLow.mq4 |
//|                        Copyright 2024, MetaQuotes Software Corp |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Software Corp"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

#property indicator_buffers 2
#property indicator_color1 clrGreen  // Color for the high line
#property indicator_color2 clrRed    // Color for the low line

// Input for the number of bars to look back for high/low
input int Nbars = 11;  // Number of bars to look back

// Declare global variables to store arrow names and line names
string arrowHighName = "ArrowHigh";
string arrowLowName = "ArrowLow";
string lineHighName = "LineHigh";
string lineLowName = "LineLow";

// Buffers for the horizontal lines
double LineHighBuffer[];
double LineLowBuffer[];

// Variable to store the timestamp of the last processed bar
datetime lastBarTime = 0;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   lastBarTime = Time[0];  // Initialize the lastBarTime to the first bar on the chart
   SetIndexBuffer(0, LineHighBuffer);  // Set buffer for high line
   SetIndexBuffer(1, LineLowBuffer);   // Set buffer for low line

   // Ensure buffers are set as series arrays (latest bar is index 0)
   ArraySetAsSeries(LineHighBuffer, true);
   ArraySetAsSeries(LineLowBuffer, true);

   SetIndexLabel(0, "HighLine");
   SetIndexLabel(1, "LowLine");

   DrawHighLow();          // Draw initial high/low lines and arrows for the last Nbars
   return INIT_SUCCEEDED;
}

//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Delete the arrows and lines when the indicator is removed
   ObjectDelete(arrowHighName);
   ObjectDelete(arrowLowName);
   ObjectDelete(lineHighName);
   ObjectDelete(lineLowName);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   // Ensure there are enough bars to calculate the high and low
   if (rates_total < Nbars) return rates_total;

   // Resize buffers to the number of bars available
   ArrayResize(LineHighBuffer, rates_total);
   ArrayResize(LineLowBuffer, rates_total);

   // Check if a new bar has opened (compare current bar time with lastBarTime)
   if (time[0] != lastBarTime)
   {
      lastBarTime = time[0];  // Update the last bar time to the current bar
      DrawHighLow();           // Update high/low lines and arrows on the new bar
   }

   return rates_total;
}

//+------------------------------------------------------------------+
//| Function to draw the high/low lines and arrows for the last Nbars |
//+------------------------------------------------------------------+
void DrawHighLow()
{
   string symbol = Symbol();
   int timeframe = Period();

   // Ensure there are enough bars to calculate high/low
   int rates_total = Bars;  // Total number of bars on the chart
   if (rates_total < Nbars) return;  // Avoid calculation if not enough bars

   // Find the highest high and lowest low in the last Nbars
   int highestIndex = iHighest(symbol, timeframe, MODE_HIGH, Nbars, 0);
   int lowestIndex = iLowest(symbol, timeframe, MODE_LOW, Nbars, 0);

   // Safety check: Ensure valid indices are returned
   if (highestIndex == -1 || lowestIndex == -1)
   {
      Print("Error: Unable to find the highest or lowest index.");
      return;
   }

   double highestHigh = iHigh(symbol, timeframe, highestIndex);
   double lowestLow = iLow(symbol, timeframe, lowestIndex);

   // Normalize prices for a 5-digit broker
   highestHigh = NormalizeDouble(highestHigh, MarketInfo(symbol, MODE_DIGITS));
   lowestLow = NormalizeDouble(lowestLow, MarketInfo(symbol, MODE_DIGITS));

   datetime highestTime = iTime(symbol, timeframe, highestIndex);
   datetime lowestTime = iTime(symbol, timeframe, lowestIndex);

   // Delete any existing objects first
   ObjectDelete(arrowHighName);
   ObjectDelete(arrowLowName);
   ObjectDelete(lineHighName);
   ObjectDelete(lineLowName);

   // Draw an arrow at the highest point of the last Nbars
   if (!ObjectCreate(0, arrowHighName, OBJ_ARROW, 0, highestTime, highestHigh))
   {
      Print("Error creating ArrowHigh: ", GetLastError());
      return;
   }
   ObjectSetInteger(0, arrowHighName, OBJPROP_ARROWCODE, 234);   // Set arrow symbol (234 is an up arrow)
   ObjectSetInteger(0, arrowHighName, OBJPROP_COLOR, clrGreen);   // Set color to green

   // Draw an arrow at the lowest point of the last Nbars
   if (!ObjectCreate(0, arrowLowName, OBJ_ARROW, 0, lowestTime, lowestLow))
   {
      Print("Error creating ArrowLow: ", GetLastError());
      return;
   }
   ObjectSetInteger(0, arrowLowName, OBJPROP_ARROWCODE, 233);    // Set arrow symbol (233 is a down arrow)
   ObjectSetInteger(0, arrowLowName, OBJPROP_COLOR, clrRed);     // Set color to red

   // Draw horizontal lines at the highest high and lowest low
   if (!ObjectCreate(0, lineHighName, OBJ_HLINE, 0, 0, highestHigh))
   {
      Print("Error creating LineHigh: ", GetLastError());
      return;
   }
   ObjectSetInteger(0, lineHighName, OBJPROP_COLOR, clrGreen);    // Set color to green

   if (!ObjectCreate(0, lineLowName, OBJ_HLINE, 0, 0, lowestLow))
   {
      Print("Error creating LineLow: ", GetLastError());
      return;
   }
   ObjectSetInteger(0, lineLowName, OBJPROP_COLOR, clrRed);       // Set color to red

   // Set buffer values to the appropriate lines
   LineHighBuffer[0] = highestHigh;  // Set the buffer value for the high line
   LineLowBuffer[0] = lowestLow;     // Set the buffer value for the low line
}

Why i get : Array out of range on the highlighted code  ( LineHighBuffer [0] ?




 
sere8: Why i get : Array out of range on the highlighted code  ( LineHighBuffer [0] ?

First, don't resize the buffers. That is done by the system. You should not be messing with it. Remove the following ...

   // Resize buffers to the number of bars available
   ArrayResize(LineHighBuffer, rates_total);
   ArrayResize(LineLowBuffer, rates_total);

Second, you should be using the "rates_total" provided by the OnCalculate() handler, not using "Bars".

You should also be testing if "rates_total" is greater than 0, to prevent working with an empty array.

So fix the following accordingly ...

   // Ensure there are enough bars to calculate high/low
   int rates_total = Bars;  // Total number of bars on the chart
   if (rates_total < Nbars) return;  // Avoid calculation if not enough bars


 
Your topic has been moved to the section: MQL4 and MetaTrader 4
Please consider which section is most appropriate — https://www.mql5.com/en/forum/172166/page6#comment_49114893
 
Fernando Carreiro #:

First, don't resize the buffers. That is done by the system. You should not be messing with it. Remove the following ...

Second, you should be using the "rates_total" provided by the OnCalculate() handler, not using "Bars".

You should also be testing if "rates_total" is greater than 0, to prevent working with an empty array.

So fix the following accordingly ...


 // Ensure there are enough bars to calculate high/low
   int rates_total;  // Total number of bars on the chart
   if (rates_total <= 0) return;  // Avoid calculation if not enough bars

i did this and array out of range is gone but now my indicator is not plotting arrows and horizontal lines ! 
 
sere8 #: i did this and array out of range is gone but now my indicator is not plotting arrows and horizontal lines ! 

When you make changes to your code, think of the consequences. Don't just blindly do things without taking the time to understand the reason.

Pass the "rates_total" variable as a parameter to the function ...

   // Check if a new bar has opened (compare current bar time with lastBarTime)
   if (time[0] != lastBarTime)
   {
      lastBarTime = time[0];  // Update the last bar time to the current bar
      DrawHighLow( rates_total );  // Update high/low lines and arrows on the new bar
   }
void DrawHighLow( double rates_total )
{
   ...
   
   // Ensure there are enough bars to calculate high/low
                                      
   if (rates_total <= 0) return;  // Avoid calculation if not enough bars
I've used the same variable name in both cases to reduce the number of changes, but you should actually use different names to prevent confusion in your code.
 

Also as I good practice, you should not be using iHighest() or iLowest(), or iHigh() or iLow() ...

   double highestHigh = iHigh(symbol, timeframe, highestIndex);
   double lowestLow = iLow(symbol, timeframe, lowestIndex);

You should in fact be using the the ArrayMaximum() and ArrayMinimum() on the high[] and low[] arrays passed the OnCalculate() handler to guarantee that you are using the proper data in a synchronised manner.

 

You do not need to normalise the existing quote data. They are already normalised. Remove the following. It is unnecessary.

   // Normalize prices for a 5-digit broker
   highestHigh = NormalizeDouble(highestHigh, MarketInfo(symbol, MODE_DIGITS));
   lowestLow = NormalizeDouble(lowestLow, MarketInfo(symbol, MODE_DIGITS));
 

Use the passed parameters in your calculations to guarantee that you are using the proper data in a synchronised manner.

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])

Don'tuse iHigh(), iLow() or iTime(), etc.

 
Thank you so much all good now :)