problem with NormalizeDouble

 

Hi

I have this code 

   double result = NormalizeDouble(Current_Balance/20000,_Digits);

 When the balance is 200 $, the result is really 0.016 but the output is  0.02 !!

I know that MT5 doesn't accept 0.016 as a certain volume so I'd like to set the "result" to 0.01 not 0.02.

Please help me with the problem .

 
_Digits
is the number of digits of the symbol and not a currency value. Place the cursor on _Digits, press F1 and start reading,
 
Carl Schreiber #:
is the number of digits of the symbol and not a currency value. Place the cursor on _Digits, press F1 and start reading,

OK ,I put 3 instead of _digits , now it's 0.016 .

I want to change it to 0.01 , how ???

 
saeed Golshenas #:

OK ,I put 3 instead of _digits , now it's 0.016 .

I want to change it to 0.01 , how ???

   double result = NormalizeDouble(Current_Balance/20000,2);
 
Ryan L Johnson #:

i think that that would make 0.016 to round up, correct?

 
saeed Golshenas When the balance is 200 $, the result is really 0.016 but the output is  0.02 !! I know that MT5 doesn't accept 0.016 as a certain volume so I'd like to set the "result" to 0.01 not 0.02.

Use the "floor" function.

double result = MathFloor( Current_Balance / 200 ) * 0.01;

However, that is not the correct way to adjust the volume, nor is it the correct way to adjust for the stop-loss risk.

For the correct way to handle the volume, read the following ...

For calculating the Risk for the Stop-Loss size, and adjust the volume ...

Forum on trading, automated trading systems and testing trading strategies

SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE) sometimes zero

Fernando Carreiro, 2022.08.23 17:41

You can! These are the steps I take. I supply the function with a lot size equal to the “Max Lot Size” allowed for the symbol in question, then calculate the ratio needed to achieve the fractional risk that I wish to apply, to get the correct volume for the order. I then align that with the “Lot Step” and finally check it against both the maximum and minimum allowed lots for the symbol.

The reason I use the “maximum” lots instead of just “1.0” lots as a reference value is because there is no guarantee that the value of 1.0 is within the minimum and maximum values allowed. Given that using 1.0, or the maximum, gives equivalent results anyway (by using the ratio method), I choose to use the “max lots” as the reference point which also offers the most precision for the calculation.

Something like this ...

// This code will not compile. It is only a example reference

if( OrderCalcProfit( eOrderType, _Symbol, dbLotsMax, dbPriceOpen, dbPriceStopLoss, dbProfit ) )
{
   dbOrderLots = fmin( fmax( round( dbRiskMax * dbLotsMax / ( -dbProfit * dbLotsStep ) )
               * dbLotsStep, dbLotsMin ), dbLotsMax ); 
      
   // the rest of the code ...
};

Forum on trading, automated trading systems and testing trading strategies

How to calculate lots using multiplier according to number of opened orders?

Fernando Carreiro, 2017.09.01 21:57

Don't use NormalizeDouble(). Here is some guidance (code is untested, just serves as example):

// Variables for Symbol Volume Conditions
double
   dblLotsMinimum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MIN  ),
   dblLotsMaximum = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_MAX  ),
   dblLotsStep    = SymbolInfoDouble( _Symbol, SYMBOL_VOLUME_STEP );
   
// Variables for Geometric Progression
double
   dblGeoRatio = 2.8,
   dblGeoInit  = dblLotsMinimum;
   
// Calculate Next Geometric Element
double
   dblGeoNext  = dblGeoInit * pow( dblGeoRatio, intOrderCount + 1 );
   
// Adjust Volume for allowable conditions
double
   dblLotsNext = fmin( dblLotsMaximum,                                     // Prevent too greater volume
                   fmax( dblLotsMinimum,                                   // Prevent too smaller volume
                     round( dblGeoNext / dblLotsStep ) * dblLotsStep ) );  // Align to Step value

Forum on trading, automated trading systems and testing trading strategies

Complete formula for calculating forex pip value for XAUUSD with account funded in euros

Fernando Carreiro, 2022.08.26 15:53

I suggest you look at it again. If you trying to calculate your order volume for a specific stop-loss risk, then use the order_calc_profit as described in my previous post.

Please note however, that stop-loss risk and appropriate volume for it has nothing to do with leverage or margin. That is something completely separate, which you can obtain using order_calc_margin.

If however, you just need the tick value, or point value just use the python equivalent of the following ...

The checks a trading robot must pass before publication in the Market
The checks a trading robot must pass before publication in the Market
  • www.mql5.com
Before any product is published in the Market, it must undergo compulsory preliminary checks in order to ensure a uniform quality standard. This article considers the most frequent errors made by developers in their technical indicators and trading robots. An also shows how to self-test a product before sending it to the Market.
 
Michael Charles Schefe #:

i think that that would make 0.016 to round up, correct?

Indeed, you are correct. My bad.🙃

Here's some straight truncate code that breaks down a double and reassembles it without rounding:

   double number = 123.456;
   string snumber = DoubleToString(number, 0);
   
   double fraction = number - double(int(number));

   int ndigits = GetDigits(number);
   
   int fpower = pow(10, ndigits);
   
   int ifraction = fraction * fpower;
   
   string sfraction = IntegerToString(ifraction);
   
   string subfractionA = StringSubstr(sfraction, 0, 2);
   
   string cstring = snumber + "." + subfractionA;
   
   double dstring = DoubleToString(cstring, 2); // ==> 123.45
    
  }
//+------------------------------------------------------------------+

   int GetDigits(const double val)              https://www.mql5.com/en/forum/156865/page2#comment_52768102
    {
     int digits = 0;
     for(double pwr = 1; digits < 308 && MathRound(val * pwr) / pwr != val; pwr *= 10)
        digits++;
     return digits;
    }    
 
@Ryan L Johnson #: Indeed, you are correct. My bad.🙃 Here's some straight truncate code that breaks down a double and reassembles it without rounding:

Why are you proposing such a convoluted "stringy" method when there is already a maths function for it?

It is called "floor", just as there is also "ceiling" and "rounding"—basic maths!

See my previous post #5.

Documentation on MQL5: Math Functions
Documentation on MQL5: Math Functions
  • www.mql5.com
A set of mathematical and trigonometric functions. Math functions were originally designed to perform relevant operations on scalar values. From...
 
Fernando Carreiro #:

Why are you proposing such a convoluted "stringy" method when there is already a maths function for it?

It is called "floor", just as there is also "ceiling" and "rounding"—basic maths!

See my previous post #5.

  1. I started working on a truncating substitution for NormalizeDouble when I read Michael's previous Post #4.
  2. I was unable to put a double into the single line floor code that you posted.
  3. If I were to edit a simple input into my code, e.g., TruncateDigits, the code would have the same input of NormalizeDouble.
  4. Upon rereading your post, I see that your code uses a hard coded value substitution of _Point.
  5. I was unable to find a way to use floor in a way that would allow me the option to edit in the aforementioned TruncateDigits input without going "stringy."
problem with NormalizeDouble
problem with NormalizeDouble
  • 2024.12.18
  • saeed Golshenas
  • www.mql5.com
Hi I have this code When the balance is 200 $, the result is really 0.016 but the output is 0.02 !! I know that MT5 doesn't accept 0...
 
@Ryan L Johnson #: I was unable to put a double into the single line floor code that you posted.

"Floor" returns an integer, so you simply scale it (and typecast it). Examples ...

double floor2digits = MathFloor( value * 100  ) * 0.01;  // returns floor for 2 digits
double floor3digits = MathFloor( value * 1000 ) * 0.001; // returns floor for 3 digits
Ryan L Johnson #: Upon rereading your post, I see that your code uses a hard coded value substitution of _Point. I was unable to find a way to use floor in a way that would allow me the option to edit in the aforementioned TruncateDigits input without going "stringy."

I was just answering the OP with the same "hardcoded" values they used as the reference. You can easily make it depend on variables instead.

double floorPrice = MathFloor( price / _Point ) * _Point;  // returns floor for price in points
 
Fernando Carreiro #:

"Floor" returns an integer, so you simply scale it (and typecast it). Examples ...

I was just answering the OP with the same "hardcoded" values they used as the reference. You can easily make it depend on variables instead.

Thanks, Fernando. I actually really want to use floor to make my code more efficient.

I think that I'm struggling to technically communicate a bit here. When I said, "hard coded value substitution of _Point," what I meant is that I need custom _Point-like data that can be auto-detected from any double, and not only from symbol related doubles. Similarly, my code retrieves custom digits in lieu of _Digits. This is the part where I don't see a way to avoid using MQL5 string functions. In other words, my code is ready to be put into a custom function that could be a truncating version of NormalizeDouble(double,digits) such as TruncateDouble(double,digits).