How to code a Dynamic Array? (coding my first EA)

 

I'm fairly new to coding mql4. Currently coding my first EA and just learnt about Arrays. I was wondering, how to code a dynamic array?

What I'm trying to do is when my EA is initialized, for the past 100 bars, find out the Highest 50 bars and save and name them accordingly, then out of the 50 bars, find out the top 10 with the Highest Trading Volume and save them and name them again. I'm thinking using dynamic array to save the bars but I don't know how to do it. Can someone please help me. 

Much appreciated.  

 
jim_2002:

I'm fairly new to coding mql4. Currently coding my first EA and just learnt about Arrays. I was wondering, how to code a dynamic array?

What I'm trying to do is when my EA is initialized, for the past 100 bars, find out the Highest 50 bars and save and name them accordingly, then out of the 50 bars, find out the top 10 with the Highest Trading Volume and save them and name them again. I'm thinking using dynamic array to save the bars but I don't know how to do it. Can someone please help me. 

I wouldn't personally use a "dynamic array" for this. My own approach would be as follows:

  • Use CopyRates to get the last 100 bars into a MqlRates[] array
  • Sort the whole array by high price, in descending order
  • And then sort the first 50 items (only) by volume, in descending order

The first 10 items in the array are then the 10 bars with the highest volume out of the 50 which have the highest highs. 

 
jjc:

My own approach would be as follows: [...]

Specifically...

#property strict

[...]

// Array of bar data; dynamic, populated by CopyRates()
MqlRates arrBars[];

// Note: following not required. We don't care whether most recent 
// bar is [0] or [99] because we are going to sort the array
// ArraySetAsSeries(arrBars, true);

// Get the 100 most recent bars into the array, checking how many we have
int ct = CopyRates(Symbol(), Period(), 0, 100, arrBars);
if (ct < 100) {/* Too few bars */ return;}   

// Sort whole array in descending order of high price 
for (int i = 1; i < ct; i++) {
   MqlRates x = arrBars[i];
   int j = i - 1;
   while (j >= 0 && arrBars[j].high < x.high) {
      arrBars[j + 1] = arrBars[j];
      j = j - 1;
   }
   arrBars[j + 1] = x;
}

// Sort first 50 items by descending order of tick volume
for (int i = 1; i < 50; i++) {
   MqlRates x = arrBars[i];
   int j = i - 1;
   while (j >= 0 && arrBars[j].tick_volume < x.tick_volume) {
      arrBars[j + 1] = arrBars[j];
      j = j - 1;
   }
   arrBars[j + 1] = x;
}

// First 10 items are now in descending order of tick volume,
// out of the half of the array with the highest high prices
for (int i = 0; i < 10; i++) {
   Print("#", i , ": " , TimeToString(arrBars[i].time), ", vol: " , arrBars[i].tick_volume);
}
 
jjc: Specifically...
Or use a generic equivalent, template insertion sort, Array or not to array (Mike Tanton) - MQL4 forum - Page 2 #4
#include "insertion_sort.mqh"
///////////
class ByHighDescending{ public:                                  // Non-default ordering
  bool is_before(const MqlRates& lhs, const MqlRates& rhs){ return lhs.high > rhs.high; }
};
class ByVolumeDescending{ public:                                // Non-default ordering
  bool is_before(const MqlRates& lhs, const MqlRates& rhs){ return lhs.tick_volume > rhs.tick_volume; }
};

int ct = CopyRates(Symbol(), Period(), 0, 100, arrBars);
ByHighDescending   bhd; insertion_sort(arrBars, 0 , 100, bhd); // sort by high
ByVolumeDescending bvd; insertion_sort(arrBars, 0 ,  50, bvd); // sort by volume
 
WHRoeder:
Or use a generic equivalent, template insertion sort, Array or not to array (Mike Tanton) - MQL4 forum - Page 2 #4
[ Sorting is obviously trivial on 100 items, and the algorithm doesn't matter. If we are going to start introducing external libraries, then... If the data size is increased, e.g. to 10000 bars, then I find that on this real-life data something like MarcoNeri's implementation of quicksort is very much faster than any insertion sort, including yours. ]
 
jjc:

Specifically...

 

Hi jjc thanks very much for showing me your own approach. They are very helpful. I need them in timeseries order though.

How do I achieve this? Do i need to sort them back and forth?

The below are the steps I can think of. 

// Get the 100 most recent bars into A-array

// refine the A-array to 50 bars with the Highest Price in time series order(from old to new bar) , and place into B-array

// refine the B-array again to 10 bars with the Highest tick volume in time series order(from old to new bar).

Also, when a new bar is created, will the array be updated and still keep 100 bars in the array?

 
jim_2002:

Also, when a new bar is created, will the array be updated and still keep 100 bars in the array? 

I'll start with your last question, because we may be on the cusp of a major misunderstanding here.

The only arrays to which new items will ever be added automatically are MQL4's built-in arrays such as High[], and the similar arrays which are passed to OnCalculate() in an indicator.

If you create your own array then, no, you need to maintain and update it whenever is applicable for what you want to do. For example: whenever a new bar starts, you re-do the calculation of the 10 most-recent bars with the highest volumes.

 

jim_2002:

I need them in timeseries order though.

I'm not sure what this means. If you are sorting the data by high price, or volume, or both, then by definition it's no longer in timeseries order.

If you need access to two lists, one in timeseries order and one sorted by high/volume, then you need two arrays. But MT4 will always provide you with the data in timeseries order via the built-in arrays such as High[].

 
jjc:

I'll start with your last question, because we may be on the cusp of a major misunderstanding here.

The only arrays to which new items will ever be added automatically are MQL4's built-in arrays such as High[], and the similar arrays which are passed to OnCalculate() in an indicator.

If you create your own array then, no, you need to maintain and update it whenever is applicable for what you want to do. For example: whenever a new bar starts, you re-do the calculation of the 10 most-recent bars with the highest volumes.

 

I'm not sure what this means. If you are sorting the data by high price, or volume, or both, then by definition it's no longer in timeseries order.

If you need access to two lists, one in timeseries order and one sorted by high/volume, then you need two arrays. But MT4 will always provide you with the data in timeseries order via the built-in arrays such as High[].

Oh I see. I probably need to use the built-in arrays such as High[] then. How do I put built-in array inside my own array? eg:

for (int i = 1; i < 4; i++) {
 High[i];
}   // this will give me High[1], High[2], High[3] , how do I then put High[1], High[2], High[3] into my own array H[] ? So when I called H[1] returns High[1] ? 
 
jim_2002: How do I put built-in array inside my own array? eg:
  1. How do you think you do?
    for (int i = 1; i < 4; i++) {
      H[i] = High[i];
    } 
  2. learn to code it, or pay someone. We're not going to code it FOR you.
    We are willing to HELP you when you post your attempt (using SRC) and the nature of your problem.
Reason: