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
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() { }
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!
William Roeder #:
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
Congratulations. Great solution.
Hello dear William Roeder ,
This code you wrote is very useful and practical for me
But I don't know how to use it
Sorry I'm a newbie in MQL4
I want to delete the first element of the array.
Thanks for your Attention
//+------------------------------------------------------------------+ //| Variables | //+------------------------------------------------------------------+ int myarray[4] = {0,1,2,3}; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { remove_first_elements(T& myarray[],1); Print(" myarray[4] = "+myarray[0]); //I was expecting the output to be {1,2,3} :( return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Template | //+------------------------------------------------------------------+ 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 }

- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
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?