Discussion of article "MQL5 Programming Basics: Arrays"

 

New article MQL5 Programming Basics: Arrays is published:

Arrays are an integral part of almost any programming language along with variables and functions. Many novice programmers are often afraid of arrays. It sounds strange but it is true! I can assure you that they are not scary at all. In fact, arrays are similar to regular variables.

Multidimensional array

Is it possible that the reason why arrays are seen as something complicated is somehow related to the use of "[" and "]"? These symbols are rarely used anywhere other than in programming when working with arrays, so their location on the keyboard can fade from one's memory and cause discomfort. While in fact, you can easily remember where they are - these two keys are situated next to "Enter" in a logical order: the opening bracket is followed by the closing bracket.

Author: Dmitry Fedoseev

 

Very good article, for absolute beginner, but also for experimented programmer new to MT5. Only last section "Creating Multidimensional Arrays Using OOP" is of least interest.

Altough, a little error :

Array indexing order can be determined using the ArrayIsSeries() function:

bool series=ArrayIsSeries(ar);

If the array is indexed in reverse order, the function will return true.

This is false. Function to use to know indexing order of an array is ArrayGetAsSeries().

ArrayIsSeries() is used to determine if an array is a TimeSeries.

 

There is only one method that allows you to do a search in an unsorted array

This is not strictly true, have a look at Hash Based Searching Algorithm. But this algorithm is  probably not applicable to trading.

 
A very helpful well-explained article, thankyou Dmitry Fedoseev.
 
MetaQuotes Software Corp.:

New article MQL5 Programming Basics: Arrays is published:

Author: Dmitry Fedoseev

1 Question:

#define SIZE_X 3;

(...)

int ArrayName[SIZE_X];

Compiler forbids such construction. Why?

 
Many thanks for this extended review
 

ok lets try the english version of MQL.


Thanks for your code post. It saved me time. I tried using the MQL arrays and they were confusing. I then was very depressed that I need to once again need to write basic structures that was supposed to be there BUT then I found your code that saved me some research time on arrays and how to make them grow\increase dynamically. AWESOME thanks.

I hope i can give back to you! the code below works for all data types. It will work on objects too but the Contains (search) method might not work. I only tested it on types (double, int, bool). String might give you problem as well and the code might need to be extended.


//+------------------------------------------------------------------+
//|                                                CDynamicArray.mqh |
//|                                                          Integer |
//|                          https://login.mql5.com/ru/users/Integer |
//+------------------------------------------------------------------+
#property copyright "Integer"
#property link "https://login.mql5.com/ru/users/Integer"
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
template <typename T>
class CDynamicArray
  {
private:
   int               m_ChunkSize;    // Chunk size
   int               m_ReservedSize; // Actual size of the array
   int               m_Size;         // Number of active elements in the array
public:
   T                 Element[];      // The array proper. It is located in the public section, 
                                     // so that we can use it directly, if necessary
   //+------------------------------------------------------------------+
   //|   Constructor                                                    |
   //+------------------------------------------------------------------+
   void CDynamicArray(int ChunkSize=1024)
     {
      m_Size=0;                            // Number of active elements
      m_ChunkSize=ChunkSize;               // Chunk size
      m_ReservedSize=ChunkSize;            // Actual size of the array
      ArrayResize(Element,m_ReservedSize); // Prepare the array
     }
   //+------------------------------------------------------------------+
   //|   Function for adding an element at the end of array             |
   //+------------------------------------------------------------------+
   void Add(T Value)
     {
      m_Size++; // Increase the number of active elements
      if(m_Size>m_ReservedSize)
        { // The required number is bigger than the actual array size
         m_ReservedSize+=m_ChunkSize; // Calculate the new array size
         ArrayResize(Element,m_ReservedSize); // Increase the actual array size
        }
      Element[m_Size-1]=Value; // Add the value
     }
     
     void Set(int index, T Value)
     {
      m_Size++; // Increase the number of active elements
      if(m_Size<index)
        { 
         return;
        }
      Element[index]=Value; // Add the value
     }
   //+------------------------------------------------------------------+
   //|   Function for getting the number of active elements in the array|
   //+------------------------------------------------------------------+
   int Count()
     {
      return(m_Size);
     }
   
   T operator[](const int index) const { return Element[index]; }
   
   bool Contains(T itemToFind)
   {
      for(int i=0;i<Count();i++)
        {
            if(Element[i] == itemToFind)
            {
               return true;
            }
        }
        
      return false;
   }
   
   int IndexOf(T itemToFind)
   {
      for(int i=0;i<Count();i++)
        {
            if(Element[i] == itemToFind)
            {
               return i;
            }
        }
        
      return -1;
   }
  };
//+------------------------------------------------------------------+


Then you can declare it for all types you need like so:


//i declared them in my class like so
   CDynamicArray<int> *Tickets;
   CDynamicArray<bool> *FixedSLUsed;
   CDynamicArray<bool> *PrevBarSLUsed;


// Then I declared them in my class methods like so

   Tickets = new CDynamicArray<int>();
   FixedSLUsed = new CDynamicArray<bool>();
   PrevBarSLUsed = new CDynamicArray<bool>();

// and i used them in my class methods like so:
      int ticket = PositionGetInteger(POSITION_TICKET);
      int index;
      if(!Tickets.Contains(ticket))
      {
         Tickets.Add(ticket);
         FixedSLUsed.Add(false);
         PrevBarSLUsed.Add(false);
      }
      
      index = Tickets.IndexOf(ticket);  
//more code was removed



hope this helps anyone

 
Ernie Gunning:

ok lets try the english version of MQL.


Thanks for your code post. It saved me time. I tried using the MQL arrays and they were confusing. I then was very depressed that I need to once again need to write basic structures that was supposed to be there BUT then I found your code that saved me some research time on arrays and how to make them grow\increase dynamically. AWESOME thanks.

I hope i can give back to you! the code below works for all data types. It will work on objects too but the Contains (search) method might not work. I only tested it on types (double, int, bool). String might give you problem as well and the code might need to be extended.



Then you can declare it for all types you need like so:




hope this helps anyone


Please disregard my suggestion above to use the Dynamic array for any data type. There is already a generic CArrayList declared. please use this. I encountered a problem using objects that was resolved on this thread: https://www.mql5.com/en/forum/358432

Using CArrayList gives error
Using CArrayList gives error
  • 2020.12.20
  • www.mql5.com
Hi Guys, Thanks for your time. I'm struggling to use the CArrayList in the generics folder. Are these interfaces and classes complete...
 

It seems a error in the function arrayResize(), in the example the content of the array is 1, 1, 3 in normal indexing not 1, 2, 3. See this example: 

//+------------------------------------------------------------------+
//|                                                        false.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   double ar[]; // Array
ArrayResize(ar,2); // Prepare the array
ar[0]=1; // Set the values
ar[1]=2; 
ArraySetAsSeries(ar,true); // Change the indexing order
ArrayResize(ar,3); // Increase the array size
ar[0]=3; // Set the value for the new array element
Alert(ar[0]," ",ar[1]," ",ar[2]); // Print array values
ArraySetAsSeries(ar,false);
Alert("Normal indexing: ", ar[0]," ",ar[1]," ",ar[2]); // Print array values
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
In added the function arraySetAsSeries() it seems be affected by function arrayresieze, se this example: 
//+------------------------------------------------------------------+
//|                                                   errorindex.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   double ar[]; // Array
ArrayResize(ar,2); // Prepare the array
ar[0]=9; // Set the values
ar[1]=8; 
ArrayResize(ar,6); // Increase the array size
Alert("Normal resize: ", ar[0]," ",ar[1]," ",ar[2]," ", ar[3], " ", ar[4], " ", ar[5]);
ArraySetAsSeries(ar,true); // Change the indexing order
ArrayResize(ar,4); // Increase the array size
ArraySetAsSeries(ar, false);
Alert("See the random element added: ", ar[0]," ",ar[1]," ",ar[2]," ", ar[3]);
ArraySetAsSeries(ar,true); // Change the indexing order 0
ar[0]=8; // Set the value for the new array element
Alert("Modify the first as serlies: ", ar[0]," ",ar[1]," ",ar[2]," ", ar[3]); // Print array values
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Steps:

1. ar = {}
2. ar = {9, 8}

3. ar = {9, 8, 0, 8, 0, 0} 

4. Set as series true:

ar = {0, 0, 8, 0, 8, 9}

5. Resize to 4

ar = {0, 0, 8, 0}

6. Set as series false:

ar = {0, 8, 0, 0}

7. Set as series true:

ar = {0, 0, 8, 0}

8. Modify the first element a[0]

ar = {8, 0, 8, 0}


I don't know what array resize (3 -5) takes the values and copy in the new positions, 6 in forward takes random values, I think. I prefer resize() first and then setasseries() like this: 

//+------------------------------------------------------------------+
//|                                            indexingarraytest.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   double ar[]; // Array
ArrayResize(ar,2); // Prepare the array
ar[0]=1; // Set the values
ar[1]=2;
ArrayResize(ar,3); // Increase the array size
Alert("Redimension to 3 normal: ", ar[0], " ", ar[1], " ", ar[2]); 
ArraySetAsSeries(ar,true); // Change the indexing order
Alert("Redimension to 3 series: ", ar[0], " ", ar[1], " ", ar[2]); 
ar[0]=8; // Set the value for the new array element
Alert("Change the first element: ", ar[0]," ",ar[1]," ",ar[2]); // Print array values
ArraySetAsSeries(ar, false);
Alert("Normal renew: ", ar[0]," ",ar[1]," ",ar[2]); // Print array values
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
Reason: