Comparison of Moving Average (and any other indicators) and error

 

Hi all!

I'm writing an EA based on SMA crossing (or rather I thought I already did, because it seems to be simple). But... I have faced a problem. The Expert Advisor works by the following principle: when a new bar appears, it analyzes the SMA values for the last two bars, not counting the last one I have just appeared (the penultimate and the pre-previous one). I compare values seemingly correctly as described here. The only exception is that iMA is called with last parameter (offset in bars) 1 and 2 respectively. Approximately like this (if the code is rewritten by analogy with the cited):

// берем два соседних значения Быстрой МА
double fast0=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 1);
double fast1=iMA(Symbol(), Period(), 10, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// берем два значения Медленной МА
double slow0=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 1);
double slow1=iMA(Symbol(), Period(), 20, 0, MODE_SMA, PRICE_CLOSE, 2);
 
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>slow1) Print("Пересечение ВНИЗ");

The Expert Advisor functions in a primitive form in the presence of a crossing signal on the principle of close the previous trade - open a new one. Of course, if all crossovers are detected, then trades will always be executed one after another (SELL - BUY - SELL - BUY - ...). That is, the Expert Advisor has only one open trade at any moment (well, except for the moment before entering the very first trade). So here's the crux of the problem... For the minute timeframe and SMA periods 5 and 34 for Close in the strategy tester in the bar of 17.02.2015 at 01:24 I caught an interesting situation. Muvings with these characteristics neatly cross directly at bar close. Here is the picture:

17.02.2015 01:24

For debugging purposes, I output the information. The correspondence in the log compared to the given code is as follows:

SMAFastCurrent =fast0

SMASlowCurrent =slow0

SMAFastPrevious =fast1

SMASlowPrevious=slow1 and

SMACurDifference = SMAFastCurrent - SMASlowCurrent

SMAPrevDifference = SMAFastPrevious - SMASlowPreviousc (i.e. the difference betweenfast0,slow0 andfast1,slow1 respectively).

So when these differences change sign, it means that this is a signal for a Mooving crossing. But in this particular example the check for more or less does not work. The values of these differences are displayed in the log. The red rectangle shows values of differences on the next bar after the problem (at 1:25), orange - on the next one (at 1:26). And it is clear, that SMACurDifference values on the previous bar and SMAPrevDifference on the current bar must be equal (the current bar becomes the previous one and the new bar takes its place). So, since the Mooving crossing occurs at the close of the problem bar at 1:24, on the next bar (at 1:25) SMAFastCurrent and SMASlowCurrent values are equal (approximately). The debugger prints them generally equal to within 5 digits (SMAFastCurrent = 1.13371 SMASlowCurrent = 1.13371 see figure). Their difference is infinitesimal but not 0 (SMACurDifference = 2.220446049250313e-016). On the next bar their difference at the same exact values becomes exactly zero (compare SMACurDifference in red and SMAPrevDifference in orange rectangles). Actually it is not clear then how to cut off these errors, if even seemingly identical values give different difference. Hence two questions:

1. Why is the difference of the same muvings just counted at the moment of alternate occurrence of two adjacent bars, gives a different result?

2. I was thinking of introducing some epsilon and comparing with it, rather than with zero. But it is usually done for comparing an infinitesimal with 0. What about the case when I need to determine a sign change of this infinitesimal?

Of course I can analyze three adjacent bars, but it's still theoretically possible that at the prices of their closures the muvings will touch each other at an infinitesimal distance. I realize that such a situation rarely occurs (especially if we take a larger timeframe), but it still may occur. And it should be caught somehow and the crossing of Mouveins should be detected in this case as well.

Thanks in advance for any help!

Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
  • www.mql5.com
Навигатор по форуму и ответы на часто задаваемые вопросы. Настоятельно Рекомендуется к Прочтению! - MQL4 форум
 

Try normalisation and comparison.

The MQL4 Reference Manual (and it's the same for MQL5) says, open on"Real Types (double, float)":

"...You cannot compare two real numbers for equality to each other. In most cases, two seemingly identical numbers may turn out to be unequal because of the difference of 15 decimal places. To compare two real numbers correctly, you must compare the normalised difference of those numbers to a zero value...."

"... it is strongly discouraged to compare two real numbers to each other for equality, as such a comparison is not correct.

..............


If, however, it is necessary to compare two real numbers for equality, it can be done in two different ways. The first way is to compare the difference between the two numbers with some small value that defines the accuracy of the comparison.

.............


The second method involves comparing the normalized difference of two real numbers with a zero value. It is useless to compare the difference of normalized numbers to zero, because any mathematical operation with normalized numbers results in a non-normalized result.

...."

 
rosomah:

Try normalisation and comparison.

The MQL4 Reference Manual (and it's the same for MQL5) says, open on"Real Types (double, float)":

"...You cannot compare two real numbers for equality to each other. In most cases, two seemingly identical numbers may turn out to be unequal because of the difference of 15 decimal places. To compare two real numbers correctly, you must compare the normalised difference of those numbers to a zero value...."

"It' s categorically not recommended to compare two real numbers to each other for equality, since this comparison is not valid.

..............


If, however, it is necessary to compare two real numbers for equality, it can be done in two different ways. The first way is to compare the difference between the two numbers with some small value that defines the accuracy of the comparison.

.............


The second way is to compare the normalized difference of two real numbers with zero. It is useless to compare the difference of normalized numbers to zero, because any mathematical operation with normalized numbers results in a non-normalized result.

...."

I am well aware that comparing real numbers for equality is not possible. There are no equality comparisons in the code I cited. And there's no need in it either. What we have here is a situation where we need to catch changes of an infinitesimal sign that might well hit 0. Simply comparing everything to more or equal with 0 is dangerous in this case too. And normalization can be even more dangerous here... The initial values of MA are normalized to an unknown number (the smaller is the timeframe, the smaller is the value of MA). If normalization to a constant digit after the decimal point is applied, it may result in that all values of MA will be exactly 0. To be honest, I don't really understand what the difference of two MA values will be...

 

gammaray:

I'm well aware that comparing real numbers on equality is not possible. In the code I cited, there are no equality comparisons. And there's no need in it either. What we have here is a situation where we need to catch changes of an infinitesimal sign which can well hit 0. Simply comparing everything to more or equal with 0 is dangerous in this case too. And normalization can be even more dangerous here... The initial values of MA are normalized to an unknown number (the smaller is the timeframe, the smaller is the value of MA). If normalization to a constant digit after the decimal point is applied, it may result in that all values of MA will be exactly 0. To be honest, I don't really understand what the difference between two MA values will be...

Why is normalization more dangerous?

So:

...

If you do need to compare two real numbers for equality, you can do it in two different ways. The first way is to compare the difference between the two numbers with some small value that sets the accuracy of the comparison.

...

The second way involves comparing the normalised difference of two real numbers to a zero value. Comparing the difference of the normalised numbers to zero is useless, since any mathematical operation with normalised numbers results in an un-normalised result.

Example:

bool CompareDoubles(double number1,double number2)
  {
   if(NormalizeDouble(number1-number2,8)==0) return(true);
   else return(false);
  }
void OnStart()
  {
   double d_val=0.3;
   float  f_val=0.3;
   if(CompareDoubles(d_val,f_val)) Print(d_val,"equals",f_val);
   else Print("Different: d_val = ",DoubleToString(d_val,16),
              "  f_val = ",DoubleToString(f_val,16));
// Результат: Different: d_val= 0.3000000000000000   f_val= 0.3000000119209290
  }
  • And my personal practical experience (to put it modestly, it is not small in terms of number of meticulous checks of program operation, where I applied and still apply to compare numbers with double, in terms of correctness of conditions triggering on the basis of such comparisons),
This allows me to consider such comparisons to be not only non-threatening:
if(NormalizeDouble(number1-number2,dig)==0)
if(NormalizeDouble(number1-number2,dig)>0)
if(NormalizeDouble(number1-number2,dig)<0)

// dig=Digits();

but, conversely, a variation of one of the two ways which can, as the Documentation says, be applied to comparisons of double numbers.

Because:

You cannot compare two real numbers for equality to each other. In most cases, two seemingly identical numbers may turn out to be unequal because of a difference in value of 15 decimal places. To compare two real numbers correctly, the normalized difference of these numbers must be compared to zero.



P./S.: It so happened, that the first method from the Documentation was less convenient for me to use, also on the basis of tasks, which, as a rule, I solve for myself. Consequently I don't have a lot of experience with the first way.

But when using second way (i.e. comparing normalized difference of two real numbers with zero value in conditional operator's expression), no problems occurred.

But if I did a comparison of non-normalized numbers (here I mean, including, what I did without using the first method), then yes, there was, that I found incorrect triggering of conditions on the basis of comparisons of numbers of type double.

 
gammaray:

These are the phrases from the Documentation:

The second method involves comparing the normalized difference of two real numbers to zero. Comparing the difference of normalised numbers to zero is useless, because any mathematical operation with normalised numbers results in an un-normalised result.

For me it is perceived that, in simplistic terms, in mathematical operations (and including various transformations) one should not do something like this:

// dig=Digits();

double delta=NormalizeDouble(number1-number2,dig);

if (delta>0)


I.e., in the previous post above I gave examples of comparisons of the normalised difference of two real numbers with a zero value. And in this post, comparing the difference of the normalized numbers to zero (in my understanding of the text of the phrases above from the Documentation).

That's about it, in a nutshell.

 

gammaray:

...

What the normalisation of the difference between the two MA values will do, to be honest, I don't really understand

P./S.: On this point, you can just put Print() in your code for a while to see what will be output on large amount of data. In Print print print non-normalized and normalized (up to some decimal place, including larger than on the chart where you will do the experiments) values obtained from mathematical operations. Including simply non-normalized and normalized iMA values, because they are formed on the basis of mathematical operations.

Just in case, let me also specify that when printing non-normalized and normalized values of double type, they should be additionally converted, of course, from numeric value to text value using DoubleToString (and in DoubleToString experiment with the number of decimal places).

 
gammaray:

P./S.: I also want to add that I think that in examples of any schemes written for MQL4 programmers, the normalization of mathematical calculations values may not be prescribed or/and not expressly stated:

  • for ease of understanding of schemes of forming any conditions;
  • Not always and/or not everywhere normalization may be required (including that it may be assumed to apply for different by tasks levels of tolerable errors and, accordingly, different further normalization (or lack of it) of results of mathematical operations on the number of decimal places for some individual tasks);
  • and/or, most likely, it is assumed that a developer is familiar with the Documentation and/or read it, in order to clarify their questions.
Something like this.
 
It's more accurate.
// сравниваем значения и определяем направление пересечения
if (fast0>slow0 && fast1<=slow1) Print("Пересечение ВВЕРХ");
if (fast0<slow0 && fast1>=slow1) Print("Пересечение ВНИЗ");

I mean, it didn't take into account that the ma values could also be equal.

сравнивать вещественные числа на равенство нельзя

slightly different.
 
Aleksey Lebedev:
A little about something else.

It depends on what you have in mind and for what tasks/objectives.

So, in writing the posts in this thread, I'm basing it on:

  • The screenshot and questions in the first post;
  • the second post of the author of the thread (about the dangers of normalisation),

and, accordingly, from here and, to put it briefly, the meaning of my posts above:

With the help of normalization possibility to set/adjust required level of accuracy of comparisons (and/or output values) and/or tolerable for some tasks and goals errors, which in turn allows triggering of program conditions exactly where and how it was intended when prescribing specific conditions in code. And comparison of normalized difference with zero, allows to adjust/adjust not only for comparisons using relations operation: "==".


P./S.: Thus on any case I shall specify once again, that comparison of real numbers by the first way from two listed here, due to comparison of a difference of numbers with any small value, I cannot name worse, than application of normalization, when it is necessary to adjust level of comparisons (including, as for me the second way appeared more convenient, the first and did not consider for itself more detailed for the practical application).


 

This has nothing to do with mql in principle. Let's take an abstract programming language. In this particular example that I have given, the main problem is that the values for the difference of muwings in one and the same bar are not equal (2e-16 in the first calculation and exactly 0 in the second). In this case, this intersection may not be determined in any way. If we return to mql, normalization implies rounding the number (or rather, simply dropping all the numbers after a certain sign, like in the Sish function floor, but to a certain decimal place). So how do I know which digit to normalize to? If the wrong digit is chosen, all values may ALWAYS be rounded to exactly 0. So normalisation is dangerous here and generally does not solve the problem.

As for what Alexey Lebedev wrote. Yes, I was thinking in this direction. But if we compare both differences by more or equal to 0, there is a probability of getting a false signal (for example, the theoretically possible situation when muwings between neighboring bars have exactly the same values). Then their difference does not change the sign (there is no crossover), but the signal for crossover will be determined programmatically. You could put only one comparison on more or equal, as you suggested. But then the problem is that in calculation in this situation first it will not be equal to 0 (2e-16), and on the next bar it will be exactly 0 but it will be a strict comparison.

It is important to understand why the same difference, when calculated on different bars, produces NOT the same result. If the result were the same, the problem would always be solved by introducing one non-strict comparison

 

gammaray:

But then the problem is that the calculation in this situation firstly will not equal 0 (2e-16), and on the next bar it will already be exactly 0, but there will be a strict comparison.

It is important to understand why the same difference, when calculated on different bars, produces NOT the same result. If the result were the same, the problem would always be solved by introducing one non-strict comparison

Most likely the calculation of the iMA function is optimised. First value = sum(close)/N, second = previous value of MA+(new close-old close)/N.

Reason: