Normalizing doubles

 

Hello! I believe that this topic has been discussed. Kindly advise where to find the answer.

I would like to convert doubles(price) to integers, work with them, and then convert them back to prices before using them in a OrderSend() / OrderModify() functions.

I used this functions:

int GetPriceToInt (double price)
{
int integer=0;

integer=(int)(round((price*MathPow(10,_Digits))));
return(integer);
}

and then:

double GetIntToPrice(int point)
{
double price=0;
return(price = point/MathPow(10,5));
}

But Still if Ask/Bid prices somtimes are 0.1234000000000001, when I converted to integer it will be 12340, but when I change back to double it will be again  0.1234000000000001

I have tried this approach with coverting the price to string, split the string , and then converted back:

  string  a= StringSubstr(DoubleToStr(Ask,_Digits),0,_Digits+2);
  
  int b=StringToDouble(a);

Still not working. Still when change back to double, it will still be 0.123400000000001.

Kindly advise why?

 
DannyBass:

Hello! I believe that this topic has been discussed. Kindly advise where to find the answer.

I would like to convert doubles(price) to integers, work with them, and then convert them back to prices before using them in a OrderSend() / OrderModify() functions.

I used this functions:

and then:

But Still if Ask/Bid prices somtimes are 0.1234000000000001, when I converted to integer it will be 12340, but when I change back to double it will be again  0.1234000000000001

I have tried this approach with coverting the price to string, split the string , and then converted back:

Still not working. Still when change back to double, it will still be 0.123400000000001.

Kindly advise why?


Because of how doubles work..

See this thread:



 
Thanks! Understand how doubles work. What I don’t understand, is why after convert them to string , and split the string , it will still show all the characters 
 
DannyBass #:
Thanks! Understand how doubles work. What I don’t understand, is why after convert them to string , and split the string , it will still show all the characters 
Maybe you could share the code.


 
Dominik Christian Egert #:
Maybe you could share the code.


I did post the code… those functions I am talking about … not yet included in my include trade functions, since is not working as I think it should… what I want is to replace NormalizeDouble() function with a better version … I keep reading posts, where experienced coders say that NormalizeDouble() not working every time. 
 
DannyBass #: Thanks! Understand how doubles work. What I don’t understand, is why after convert them to string , and split the string , it will still show all the characters 

I think that maybe you don't fully understand how floating point numbers are stored. Even if you convert them into Integers for easier manipulation and then later back into floating point, you can not get around the limitations of floating point numbers not being able to store every single number exactly. It is after all a limited discreet binary representation of real world numbers (see next post).

Also, there is no need to use "MathPow(10,_Digits)". Just use "_Point".

int PriceToPoints( double price )
{
   return (int) round( price / _Point );
};

double PointsToPrice( int points )
{
   return points * _Point;
};
 

Forum on trading, automated trading systems and testing trading strategies

MathRound fails for one particular number

Fernando Carreiro, 2018.01.01 22:08

He means that the value "0.69" cannot be exactly represented given the way a floating point number works (based on binary and not decimal representation) - hence, why the value gets represented as "0.68999999..." (see below).

You can never really "normalize" it and it is the main reason why both @whroeder1 and myself contest the use of the NormalizeDouble() function. It should in the very least be renamed to something like "RoundDigits()" because it is more of a "rounding" function and does not "normalize" in any way or fashion.


https://www.h-schmidt.net/FloatConverter/IEEE754.html

EDIT: Please note that the above images are for examples of representation in the 4-byte "float", and not the 8-byte "double" which offers more precision but still cannot represent the value "0.69" exactly due to the "binary" nature of the format.

EDIT2: For future readers that have difficulty understanding (or accepting) this concept, of decimal values not having an exact representation with a "float" or a "double", here is an article worth reading:

 

Also, instead of points, try to use "tick size" instead, as that will make prices always align properly with the symbol's pricing levels.

Forum on trading, automated trading systems and testing trading strategies

Symbol Point Value

Fernando Carreiro, 2022.06.02 01:14

Here are two examples from AMP Global (Europe):

  • Micro E-mini S&P 500 (Futures): point size = 0.01, tick size = 0.25, tick value = $1.25
  • EURO STOXX Banks (Stock Index): point size = 0.01, tick size = 0.05, tick value = €2.50

Forum on trading, automated trading systems and testing trading strategies

NormalizeDouble not "working"

Fernando Carreiro, 2017.09.23 00:41

Just as a side note.

Initially, when I started with MQL, I would manipulate prices as "doubles". Nowadays, especially in the more complex EA's, I manipulate prices as "ints". At the very first opportunity, I convert a price into ticks:

int priceTicks = (int) round( price / tickSize );

From then on, all my calculations and manipulations are done with "ints". Not only is it more memory compact and much faster, but comparisons are much easier to handle.  Doing a "priceA == priceB" for "doubles" is quite problematic, but not for "ints" because it gives exact matches. Not to mention, that in this way prices, stop sizes, etc. are ALWAYS aligned.

Then, just before I have to place or modify an order, I then convert it back:

priceTicks * tickSize
EDIT: I do the same for volume/lots by using the broker's Lot-Step.
 
this shall work
NormalizeDouble((int)(value/tickSize)*tickSize,_Digits);
 

Samuel Manoel De Souza #: this shall work

NormalizeDouble((int)(value/tickSize)*tickSize,_Digits);
  • Type-casting a floating point to an integer will result in truncation which causes an incorrect value to be obtained. For example let say that (value/ticksize) gives a result of 12344.999, which will result in 12344 instead of the correct 12345. So, always use rounding before type-casting, as mentioned in the documentation.
"As a result of converting floating point values to integer type, the fractional part is always deleted. If you want to round off a float to the nearest whole number (which in many cases is more useful), you should use MathRound()."
  • There is no need for using "NormalizeDouble" after converting back. The price is already properly aligned in the previous steps. No further rounding or normalisation is required.
Reason: