easiest way to remove first element and at one element at the end

 

Hello,

i do my first steps in mql, so sorry for my simple question.

I have a array with prices. I want to updates this array with a new price, so the oldest one must delete and the new price add to the array. The index value are represent the order of the prices 0=the oldest, 3=the newest.

//1 start with this
prices[0]=1.01
prices[1]=1.02
prices[2]=1.05
prices[3]=1.03

//2 add new price
prices[4]=1.09

//3 remove first (oldest) element
prices[0]=1.02
prices[1]=1.05
prices[2]=1.03
prices[3]=1.09

For this i can add a new price with
prices[4]=1.09

After that i can remove the first object
ArrayRemove( prices,0,1);

At least i should re-index the array, but wich function can do this?

I also aks myself if there is a much more simple way to do this job?

 

Hi,

the most natural way is to use a queue. Please see this script:


#include <Generic/Queue.mqh>
void Show (CQueue<double> &q) {
   string out="";
   double arr[];
   ArrayFree (arr);
   q.CopyTo(arr);
   int size=ArraySize(arr);
   for (int i=0;i<size;i++) {
      out += StringFormat("%5.2f ", arr[i]);
   }
   Print (out);
}
void OnStart() {
   CQueue<double> queue;
   //1 start with this
   queue.Enqueue(1.01);
   queue.Enqueue(1.02);
   queue.Enqueue(1.05);
   queue.Enqueue(1.03);
   Print ("1 start with this");
   Show (queue);
   
   //2 add new price
   queue.Enqueue(1.09);
   Print ("2 add new price");
   Show (queue);
   
   //3 remove first (oldest) element
   queue.Dequeue();
   Print ("3 remove first (oldest) element");
   Show (queue);
}


Output:

2022.12.27 13:49:42.955 queue (.DE40Cash,M15)   1 start with this
2022.12.27 13:49:42.955 queue (.DE40Cash,M15)    1.01  1.02  1.05  1.03 
2022.12.27 13:49:42.955 queue (.DE40Cash,M15)   2 add new price
2022.12.27 13:49:42.955 queue (.DE40Cash,M15)    1.01  1.02  1.05  1.03  1.09 
2022.12.27 13:49:42.955 queue (.DE40Cash,M15)   3 remove first (oldest) element
2022.12.27 13:49:42.955 queue (.DE40Cash,M15)    1.02  1.05  1.03  1.09 


Adapt it for your special needs.

Matthias

 
ReLor2:

Hello,

i do my first steps in mql, so sorry for my simple question.

I have a array with prices. I want to updates this array with a new price, so the oldest one must delete and the new price add to the array. The index value are represent the order of the prices 0=the oldest, 3=the newest.

For this i can add a new price with
prices[4]=1.09

After that i can remove the first object
ArrayRemove( prices,0,1);

At least i should re-index the array, but wich function can do this?

I also aks myself if there is a much more simple way to do this job?

simply you can shift the values to the old side. The older one goes away and newer values come in.

price[0]=price[1]

price[1]=price[2]

price[2]=price[3]

price[3]=new_value

 

You can also use a shiftless array , the articles here have given it a different name though.

The premise of the shiftless array is that you are going around on a circle and never resize the array itself , and , you gain speed .

Heres an example :

#property version   "1.00"
/*
let's build the custom structure that will manage the shiftless array
we will start with an integer type for ease of demonstration
*/
struct shiftless_array{
//this is where we will store our data , a normal array
int items[];
/*
now the array needs a custom internal index which points at the newest element but here is the catch
the element next to the latest will be the first ! if we have completed a revolution 
So , we need an indication we have entered shiftless mode 
easy , a boolean 
*/
bool shiftless_mode;
/*
then we will need our counter which is our pointer to the latest item as well 
*/
int latest_item;
//and we will need a maximum to know when this turns around to the beggining
int max_items;
//we have everything we need 
               shiftless_array(void){reset();}//constructor ignore for now
              ~shiftless_array(void){reset();}//destructor ignore for now 
               //the reset function 
          void reset(){
               //which does what ? empties the array 
                 ArrayFree(items);
               //resets the shiftless indication
                 shiftless_mode=false;
               //and sets items to 0
                 latest_item=0;
                 max_items=0;
               }
               //what else might we need ? a setup of course 
          void setup(int _max_items){//where we send the maximum number of items for the shiftless mode
               max_items=_max_items;
               //and of course , resize the array , once 
               ArrayResize(items,max_items,0);
               }
               /*
               we will also need the ability to move the pointer up and manage 
               the shiftless mode 
               so : increase of the latest item pointer
               it returns an integer which points to the [] of the latest , the literal address
               */
           int increase(){
               //it does what ? 
                 latest_item++;
               //and it checks against the ...
                 if(latest_item>max_items){
                 //if its greater than the max , i.e. if its 6 and max is 5 then the pointer goes back to 1
                 //remember this pointer starts from 1 and ends in max 
                   latest_item-=max_items;
                 //and what else ? we have completed a revolution so we light up the shiftless indication
                   shiftless_mode=true;
                 }
               //and we return the literal position in the array 
                 return(latest_item-1);
               }
               //then we will need to add items 
           int add(int _data){
               //we increase the pointer 
                 int ix=increase();
               //and we add the new piece of data there 
                 items[ix]=_data;
               return(ix);
               }
               /* and now we need to do a little packaging so that the end user 
                  does not notice , that much
                  First thing we will need is to turn an index into an adress in the items array
                  For instance if i want item [0] and in my setup [0] is the oldest item then 
                  we will calculate where that lies within our revolving array and return an index
                  Similarly if i want item [0] and in my setup [0] is the newest item then 
                  we will calculate again bla bla bla etc
                  You see where this is headed :)
                  So we are going to call the mode where [0] is the oldest NonSeries
                  and                     the mode where [0] is the newest AsSeries
                  And we will ask the question "IsSeries?" and then do calc stuff
                  so we return an integer
                */
            int find_index(int ix,//this would be the 0 being sent in the examples above 
                           bool is_series){//and the is series question 
                //note the is series only concerns the "idea" the user has in their head about how to 
                //access his(or hers) arrays our little revolver does not care
                  //first lets contain the ix to be between 0 and max-1 (otherwise we would return the same items over and over)
                    if(ix<0){ix=0;}else if(ix>=max_items){ix=max_items-1;}
                  /*so if the access is as series meaning the [0] would be at the most recent item
                    that would place the oldest item at max-1 
                    and if we received [1] it would mean we want the item with offset 1 from the newest 
                    that means we can go ahead and subtract the index from the latest item index we already have
                    and then turn that to a literal address , easier than it sounds so 
                    if is series
                  */
                    if(is_series){
                    ix=latest_item-ix;
                    //check for breaching 1 (which is the lowest the latest items can go !)
                    if(ix<1){ix=max_items+ix;}//we then bring it on the other end , and why do we add ? because its probably already negative!
                    //and this is not a literal adress so 
                    ix--;//now it is
                    }
                  /* if the access is as non series , meaning the [0] would be at the oldest item (or the first in our case)
                     that means we can go to the item after latest and add the index to that 
                  */
                    else if(!is_series){
                    ix=latest_item+1+ix;
                    //and check for breaching the max
                      if(ix>max_items){ix-=max_items;}
                    //and turn to literal address
                      ix--;
                    } 
                //and return the address 
                  return(ix);  
                }
                /* cool but why did we do that ? well we will beautify this a bit 
                   and instruct the code to directly access the proper item and return its value 
                   without the user having to care about increasing and limits and so on 
                   we want the user to call array[0] and we will do the rest
                   and this is how this instruction looks .
                   It looks hard but it is not 
                   We return what ? the value of the arrays which is an integer
                */
            int operator[](int ix){
                /*
                what are we catching here is this 
                If this structure is called with brackets containing one number (ix) in them
                we will do the following :
                */
                //find the literal index 
                  ix=find_index(ix,true);//im setting this as series , you can add it as a parameter on setup later
                //and what do we do with the index ? we return the value 
                  return(items[ix]);
                }//how cool is that ?
                /*
                the only issue is we have given away the brackets to reading so we cannot use them for setting a value 
                so for that we need to have a set function
                */
           void set(int ix,//again the index as perceived by the user 
                    bool is_series,//and if its series 
                    int value){//and the new value
                //! caution this CHANGES a value it does not ADD a new item ,you will rarely use it if your 
                //  system requires a shiftless array
                //  so find the literal index 
                    ix=find_index(ix,is_series);
                //  and adjust that value 
                    items[ix]=value;
                }
                /* and for just educational puproses let's try and do a custom way to add items to this 
                   structure 
                   lets use << 
                   so this returns void because we return nothing 
                */
           void operator<<(int value){
                //in other words when the structure is followed by << and an integer value 
                  add(value);//add the value to the array as a new item , the rest happens automatically
                //that is it , let's test it
                } 
           
};
int OnInit()
  {
  //we create the structure 
    shiftless_array MY_ARRAY;
    //we set it up 
    MY_ARRAY.setup(10);//for 10 items max
    //we add 15 numbers
    for(int i=1;i<=15;i++){
    MY_ARRAY<<i;//this means add i to the array 
    }
    //and since we configured it for series (meaning the last will be at [0])
    //lets print it the way we perceive it , we expect to get [0]15,[1]14,[2]13, etc
    //and if correct our last item [9] will have a value of 6
    for(int i=0;i<10;i++){
    Print("["+IntegerToString(i)+"]="+IntegerToString(MY_ARRAY[i]));
    }
    
  return(INIT_SUCCEEDED);
  }

void OnTick()
  {  
  }


 

 
ReLor2: I also aks myself if there is a much more simple way to do this job?
template <typename T>
void remove_first_elements(T& array[], int n=1){
    int   size = ArraySize(array);
    bool order = ArrayGetAsSeries(array); // Array has 0,1,2,3,4
    ArraySetAsSeries(array, !order);      // Array has 4,3,2,1,0
    ArrayResize(size-n);                  // Array has 4,3,2,1
    ArraySetAsSeries(array, order);       // Array has 1,2,3,4
}
 

I would use a ring buffer which is just an array and moving pointer [i] to the most recent entry and [i-1] pointing to the oldest value. Her my solution that stores the ticks that an EA gets:

/* vvvvvvvvvvvv ring buffer circle array vvvvvvvvvvvvvvvvvv */

enum €RingBuffTicks {
   €getOldest,    // mgTick(€getOldest)
   €getOldestTme, // mgTick(€getOldestTme)  _t2All(aTcks[0].time) uint: 0-4 294 967 295 => 4 294 967,295
   €getIdxVal,
   €getIdxTme,
   €putNew,
   €setSize,
   €getSize,
   €getLast,      // mgTick(€getLast)
   €getLastTme,   // mgTick(€getLastTme)
};


double mgTick(€RingBuffTicks todo, const double val=0, const int i=0){
   static int szRB=0, iRB=-1, full=0;
   struct __RB {
      double   t; // msec/1000.0
      double   p;
   };

   static __RB RB[];
   if (szRB==0 )
      if ( todo != €setSize) return(0.0);
      else {   szRB=ArrayResize(RB,(int)val); 
               ZeroMemory(RB); iRB=0; 
               return(szRB); 
      }
      #ifdef _DEBUG 
         Print(__LINE__," ",ArraySize(RB),"  ",_a2STR(szRB),_a2STR(iRB),_a2STR((iRB+1)%szRB),"  sTC ",string(GetTickCount64()) );
      #endif 
   
   if ( (int)todo < (int)€getIdxTme && RB[ (iRB+1)%szRB].p == 0.0 ) return(-1.);
   switch (todo) {
      case €getOldest:     return(RB[ (iRB+1)%szRB].p );
      case €getOldestTme:  return((double)RB[ (iRB+1)%szRB].t );
      case €getIdxVal:     return( RB[(i%szRB)].p );
      case €getIdxTme:     return( RB[(i%szRB)].t );
      case €putNew:        iRB=(iRB+1)%szRB;RB[iRB].p = val; RB[iRB].t = 0.0001*GetTickCount64(); full++; break;
      case €setSize:       szRB=ArrayResize(RB,(int)val); ZeroMemory(RB); iRB=0; return(szRB); 
      case €getSize:       return(szRB); 
      case €getLast:       return(RB[iRB].p); 
      case €getLastTme:    return( (double) RB[iRB].t); 
   }
   #ifdef _DEBUG 
      Comment(__LINE__," ",ArraySize(RB),"  ",_a2STR(full),"  ",_a2STR(szRB),_a2STR(iRB),_a2STR((iRB+1)%szRB),
           "\n old[",(iRB+1)%szRB,"] ",_d23(RB[(iRB+1)%szRB].t),": ",_d2D(RB[(iRB+1)%szRB].p),
           "\nlast[",iRB,"] ",_d23(RB[iRB].t),": ",_d2D(RB[iRB].p),"  sTC ",_d23(0.0001*GetTickCount64()) );
   //if (full>szRB) DebugBreak();
   #endif
   return(RB[iRB].p);
}
/* usage:
OnInit() { ...  mgTick(€setSize,100); ..} // 100 elements

OnTick(){ 
   ...
   double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID), tick = mgTick( €putNew, bid );
   if (mgTick( €getOldest ) < _Point) { 
      return;  // return if not full
   }
...
}
// ^^^^^^^^^^^^^^^^^^ ring buffer ^^^^^^^^^^^^^^^^^^^ */

not yet expensively tested - on you own risk!

Reason: