Find average value over number of bars?

 

I'm trying to write a custom indicator that relies on finding the average value over a past number of bars, but I'm having trouble figuring out how to write the function, although it should be simple, but I don't see an "average" function prebuilt into mql4 and I don't think I would need to save each value into it's own variable and divide by the number of variables manually. There has to be a better way than that. For instance, if I want to find the average value of the Close price minus the Open prices over the past x number of bars, how would I be able to do that? Any ideas on writing a simple script that doesn't make me save each bar value into it's own variable, which would be cumbersome if I had more than say 10 bars, and then manually divide by the number of bars?

 
MPW Capital: I'm trying to write a custom indicator that relies on finding the average value over a past number of bars, but I'm having trouble figuring out how to write the function, although it should be simple, but I don't see an "average" function prebuilt into mql4 and I don't think I would need to save each value into it's own variable and divide by the number of variables manually. There has to be a better way than that. For instance, if I want to find the average value of the Close price minus the Open prices over the past x number of bars, how would I be able to do that? Any ideas on writing a simple script that doesn't make me save each bar value into it's own variable, which would be cumbersome if I had more than say 10 bars, and then manually divide by the number of bars?

It's called a Simple Moving Average and is the most basic of indicators build into every platform I know (and that includes MetaTrader).

The MQL4 function for it (and several other types of moving averages) is "iMA()". If you need to apply it to custom data, then use "iMAOnArray()".

iMA - Technical Indicators - MQL4 Reference
iMA - Technical Indicators - MQL4 Reference
  • docs.mql4.com
iMA - Technical Indicators - MQL4 Reference
 
Here is what you need to calculate the mean of a series.

A variable to sum up the values.
An array with the length of the amount of values you want to consider.

Here is what you need to do:
You use the array as a ring buffer.

On a new value/period:
You push the pointer of your ring buffer by one.

You take the value stored at the ring buffers new position and subtract it from your sum variable.

You add the new value to your sum variable and store it in the ring buffer.

Note: you need to do this every time you >update< the value in case of a change. (Subtract, add, store)

To get your result, you divide your sum by the length of the ring buffer (elements in the buffer).

That will give you a concept where you can create any mean value from any input you want to feed into it. It's very efficient and has a deterministic calculation speed, no matter the length of your mean.

Hope this was understandable.
 
MPW Capital:

...I would need to save each value into it's own variable and divide by the number of variables manually. There has to be a better way than that....

I cannot comment on MQL4, but if you look in the MQL5 official library, you will see that's basically how they do it using an array and a loop.

So no harm in copying that way if there is no function in MQL4


 
MPW Capital:

I'm trying to write a custom indicator that relies on finding the average value over a past number of bars, but I'm having trouble figuring out how to write the function, although it should be simple, but I don't see an "average" function prebuilt into mql4 and I don't think I would need to save each value into it's own variable and divide by the number of variables manually. There has to be a better way than that. For instance, if I want to find the average value of the Close price minus the Open prices over the past x number of bars, how would I be able to do that? Any ideas on writing a simple script that doesn't make me save each bar value into it's own variable, which would be cumbersome if I had more than say 10 bars, and then manually divide by the number of bars?

ArraySetAsSeries(Buf_Par,true);

      double AveP = iMAOnArray(Buf_Par,0, 15, 0,MODE_SMA, i);

      Buf_AveP[i] = AveP;

 
You need to find out how for loops and arrays work or you leave the work to somebody else.

It is not hard if you know how but it is real work to find that out.
 

To close this topic, some code contribution for everyone:


    ///////////////////////////////////////
    //
    //  Mean series object
    //

        template <typename T>
        struct object_mean
        {
            private:
            // Local storage

                T       _ring_buffer[];
                T       _sum_value;
                int     ptr;
                int     _size;
                bool    is_full;


            public:
            // Constructors

                object_mean() :
                    _sum_value  (NULL),
                    ptr         (-1),
                    _size       (NULL),
                    is_full     (false)
                { };
    
                object_mean(const int size) :
                { reset(size); };
    
                object_mean(const object_mean& p_in)
                { operator=(p_in); };


            // Operators

                void operator=(const object_mean& p_in)
                {
                    _sum_value  = p_in._sum_value;
                    ptr         = p_in.ptr;
                    _size       = p_in._size;
                    is_full     = p_in.is_full;
                    ArrayCopy(_ring_buffer, p_in._ring_buffer);
                };

                const T operator[](const int p_in) const
                { return(_ring_buffer[p_in]); };


            // Buffer functions

                const bool reset(const int size)
                {
		    _sum_value	= NULL;
                    ptr     	= -1;
                    is_full 	= false;
                    _size   	= ArrayResize(_ring_buffer, size);
                    return(ArrayInitialize(_ring_buffer, NULL) == size);
                };


            // Mean functions
            
                void add(const T p_in)
                {
                    ptr++;
                    is_full |= (ptr == _size);
                    ptr = ptr % _size;
                    update(p_in);
                };

                void update(const T p_in)
                {
                    _sum_value += (p_in - _ring_buffer[ptr]);
                    _ring_buffer[ptr] = p_in;
                };

                const T get() const
                { return(_sum_value / ((is_full) ? _size : (ptr + 1))); };


            // Min/Max functions

                const int max() const
                { int idx = ptr; for(int cnt = (is_full) ? (_size - 1) : ptr; (cnt >= NULL) && !_StopFlag; cnt--) { idx = (_ring_buffer[idx] < _ring_buffer[cnt]) ? cnt : idx; } return(idx); };

                const int min() const
                { int idx = ptr; for(int cnt = (is_full) ? (_size - 1) : ptr; (cnt >= NULL) && !_StopFlag; cnt--) { idx = (_ring_buffer[idx] > _ring_buffer[cnt]) ? cnt : idx; } return(idx); };
        };

I am open to suggestions for improvements.

How to use:

object_mean<double> test;	// Default constructor, alternative use a specific constructor like this: object_mean<int> test(5);

test.reset(5);			// Set the length, if default constructor has been used, it is necessery to call this function before using the object.

test.add(1.0);			// Add some values
test.add(2.0);
test.add(3.0);
printf("%f", test.get());	// Get current mean

test.update(4.0);		// Update a value, not adding a new value to the mean array, but updating the last added value
printf("%f", test.get());	// Get current mean


test.add(3.0);			// Add more values
test.add(5.0);
printf("%f", test.get());	// Get current mean

// More than 5 values added, first value gets overwritten
test.add(6.0);
printf("%f", test.get());	// Get current mean



printf("Max: %f", test[test.max()]);		// Get the maximum value in the series, max() returns an index.
printf("Min: %f", test[test.min()]);		// Get the minimum value in the series, min() returns an index.

 
Dominik Christian Egert #: I am open to suggestions for improvements.
template<typename T> T array_mean(const T& arr[], int iBeg, int iEnd){
   return array_sum(arr, iBeg, iEnd) / (iEnd - iBeg);
}
template<typename T> T array_sum(const T& arr[], int iBeg, int iEnd){
   T sum=0; for(; iBeg < iEnd; ++iBeg) sum += arr[iBeg]; 
   return sum;
}
Simple code.
 
William Roeder #:
Simple code.
Oh, thank you. Yes, that's much easier.

But, your function has an unpredefined execution time.

The main idea was to have a deterministic execution time.

But I like your functions. It's nice code.




 
Dominik Christian Egert #:
Oh, thank you. Yes, that's much easier.

But, your function has an unpredefined execution time.

The main idea was to have a deterministic execution time.

But I like your functions. It's nice code.




What do you mean by "deterministic execution time" ?

 
R4tna C #: What do you mean by "deterministic execution time" ?

Mine is O(n), his is O(1)

Reason: