Thank you for sharing this very nice indicator code.
I have performed some minor improvements concerning speed, memory (and numerical errors) while not changing the behavior:
** In the class CHull I use circular buffers in order to have constant (non increasing) memory usage (at least in this class)
** I made the initialization also recursive (when the number of available bars is less than m_fullPeriod) in order to increase initialization speed when m_fullPeriod is large.
** At least theoretically numerical errors accumulate in the course of time (although nobody of us will live anymore until errors would be large enough to be a problem).
For the sake of some perfectionism I programmed a mechanism to avoid accumulation of numerical errors.
The execution speed gets only negligibly slower.

- dict.leo.org
Nice work. Thanks
PS: since it was only yesterday that I claimed that circular / ring buffers code is (in my opinion) over-complicated in almost all cases, here is my implementation that can show one possible different way that it really does not need to be complicated at all
You are right, your code with a circular buffer is really much simpler than mine.
Because I do not use an array for the wsum and lsum at all, I must restore the old values in a complicated way
if the new "value" is not for a new bar but replaces just the last bar's value.
But some of my lengthly code comes from the faster initialization and the avoiding of numerical error accumulation.
Sorry, but I fail to see how this :
bool init(int period, double divisor) { m_fullPeriod = (int)(period>1 ? period : 1); m_halfPeriod = (int)(m_fullPeriod>1 ? m_fullPeriod/(divisor>1 ? divisor : 1) : 1); m_sqrtPeriod = (int) MathSqrt(m_fullPeriod); m_weight1 = m_weight2 = m_weight3 = 1; m_arraySize = ArrayResize(m_array,m_fullPeriod+1); return(m_arraySize==(m_fullPeriod+1)); }
is slower than this :
bool init(int period, double divisor) { m_fullPeriod = (int)(period>1 ? period : 1); m_halfPeriod = (int)(m_fullPeriod>1 ? m_fullPeriod/(divisor>1 ? divisor : 1) : 1); m_sqrtPeriod = (int) sqrt(m_fullPeriod); _2invWeight1 = 4.0 / (m_halfPeriod*(m_halfPeriod+1)); invWeight2 = 2.0 / (m_fullPeriod*(m_fullPeriod+1)); invWeight3 = 2.0 / (m_sqrtPeriod*(m_sqrtPeriod+1)); lsum1 = lsum2 = lsum3 = wsum1 = wsum2 = wsum3 = 0; wsum1_recalc = wsum2_recalc = wsum3_recalc = 0; idxfull = 0; idxsqrt = 0; countfull = 0; countsqrt = 0; ArrayResize(value, m_fullPeriod); ArrayResize(value3, m_sqrtPeriod); int i; for(i=0; i<m_fullPeriod; i++) value[i] = 0; for(i=0; i<m_sqrtPeriod; i++) value3[i] = 0; nr_calculated = 0; recalc_period = 10 * m_fullPeriod; recalc_count = recalc_period; return(true); }
In any case, thanks for posting your code (it seems that these days we chronically lack code posters :))
Sorry, but I fail to see how this :
is slower than this :
In any case, thanks for posting your code (it seems that these days we chronically lack code posters :))
I expressed myself unclear. Of course, your init() function is faster.
But with "initialization" I meant the calculation of the first "m_fullPeriod" indicator values.
This is done only after attaching the indicator to the chart or after changing the parameters.
In your code for every indicator value (with i <= m_fullPeriod) the following two loops must
be executed:
for(int k=0, w1=m_halfPeriod, w2=m_fullPeriod; w2>0 && i>=k; k++, w1--, w2--)
.............
for(int k=0, w3=m_sqrtPeriod; w3>0 && i>=k; k++, w3--)
...............
In my code there is no loop in this "initialization" phase (for nr_calculated <= m_fullPeriod in my code)
and so only a constant amount of computation time is needed for every indicator value.
I expressed myself unclear. Of course, your init() function is faster.
But with "initialization" I meant the calculation of the first "m_fullPeriod" indicator values.
This is done only after attaching the indicator to the chart or after changing the parameters.
In your code for every indicator value (with i <= m_fullPeriod) the following two loops must
be executed:
for(int k=0, w1=m_halfPeriod, w2=m_fullPeriod; w2>0 && i>=k; k++, w1--, w2--)
.............
for(int k=0, w3=m_sqrtPeriod; w3>0 && i>=k; k++, w3--)
...............
In my code there is no loop in this "initialization" phase (for nr_calculated <= m_fullPeriod in my code)
and so only a constant amount of computation time is needed for every indicator value.
That (the initial summing) is done in a loop only for maximum hull period first bars - after that the calculation does all that without any loop and that can not be avoided (otherwise you are falling into initial values approximation)
In any case (since those are classes) it is easily portable to mt5 and then you can test it in profiler. The comparisons (both used on same sample data and same conditions) - you can easily do the same tests - quite frankly I find that tool quite good, since it does not depend on our subjective opinion but is cold blooded counter and timer :)
I rest my case now. The purpose of my posting was to post one very simple way of using circular / ring buffers. Since that is done and since it seems that we have explained all that can be explained regarding that now, I leave to you guys to decide what ways you want to use in your own coding
I have not claimed that my code is generally faster than yours.
I have only claimed that in the "initialization" phase it is. And I leave you the right to say that your code is a bit faster after the initialization phase.
What the initialization concerns: If you choose for some reason a high value for "period" then
you can see that your indicator needs some perceptible time to be uasble after attaching it to a chart or after changing the parameters.
But I have never claimed that your initialization code would be bad and mine would be good. The initialization time of your indicator
is tolerable even for "reasonable" high period values.
I think it's not worth further disputing about this.
I have hoped that the reader of my comments sees that the motivation for writing my version of the code is also a bit because of theoretical interest - e.g. I
have told that in this application the small accumulation of numerical errors are not really a problem even after a longer time.
But I wanted to investigate - at first for myself - if it is possible to avoid accumulation of numerical errors - to a price of increasing the computation time
by maximal a constant factor.
I have found a bug in my code. It only occurs if "period" is very large (e.g. 50000) (due to an integer overflow).
I have a corrected version in the attachment.
I have an EA that indeed uses both smaller and larger periods. You may call iCustom() with a timeframe that is bigger than the one the
EA is attached to if you do not need the indicator be drawn on the chart. Then the "period" parameter could be respectively smaller.
But I prefer to leave the user the freedom whether to do so or just use the indicator with a higher "period" parameter.
The original code of mladen takes several minutes longer at the begin of the test of the EA in the strategy tester if "period" is set high
(e.g. 50000).

- Free trading apps
- Over 8,000 signals for copying
- Economic news for exploring financial markets
You agree to website policy and terms of use
Hull moving average:
Hull moving average
Author: Mladen Rakic