Dynamic minimum lot size digit accuracy

 

Hello.  I'm working to have code to be able to dynamically determine the digit accuracy of the minimum lot size.  After getting this number without errors, I will use it with the NormalizeDouble function to determine my correct number of lots for my order.  

The end pseudo-code will be double Lots = NormalizeDouble(lots_calculation,minimum_lot_digit_calculation);

If the minimum lot size is 1, I need the result to be NormalizeDouble(lots,0) and if the minimum lot size is .01 I need the result to be NormalizeDouble(lots,2) or minimum lot size of .1 to be NormalizeDouble(lots,1) 

I have explored code like this:

double min_lot = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
int round_value = 0;
if(StringFind(min_lot,".",0) < 0)
  { round_value = 0; }
else { round_value = ( StringLen(min_lot) - (StringFind(min_lot,".",0) + 1) ); }

double lots = NormalizeDouble(_lotcalculation,round_value);

This code gets my number but it gives multiple implicit conversion from 'number' to 'string' errors which I would like to eliminate.  If I convert _min_lot to a string, it ends up converting 0.01 over as 0.01000000 and then my calculations with StringLen don't work anymore.

How can I improve this to eliminate the compile warnings?  What other functions can I look at?

Thanks

Documentation on MQL5: Conversion Functions / NormalizeDouble
Documentation on MQL5: Conversion Functions / NormalizeDouble
  • www.mql5.com
Conversion Functions / NormalizeDouble - Documentation on MQL5
 
tfworks.com:

Hello.  I'm working to have code to be able to dynamically determine the digit accuracy of the minimum lot size.  After getting this number without errors, I will use it with the NormalizeDouble function to determine my correct number of lots for my order.  

The end pseudo-code will be double Lots = NormalizeDouble(lots_calculation,minimum_lot_digit_calculation);

If the minimum lot size is 1, I need the result to be NormalizeDouble(lots,0) and if the minimum lot size is .01 I need the result to be NormalizeDouble(lots,2) or minimum lot size of .1 to be NormalizeDouble(lots,1) 

I have explored code like this:

This code gets my number but it gives multiple implicit conversion from 'number' to 'string' errors which I would like to eliminate.  If I convert _min_lot to a string, it ends up converting 0.01 over as 0.01000000 and then my calculations with StringLen don't work anymore.

How can I improve this to eliminate the compile warnings?  What other functions can I look at?

Thanks

1. Use Conversion Functions DoubleToString and StringToDouble
 

tfworks.com:

...

double   min_lot     = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
double   max_lot     = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
int      lotdigits   = (int) - MathLog(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP));
double   lots        = NormalizeDouble(_lotcalculation, lotdigits);
if (lots < min_lot) lots = min_lot;
if (lots > max_lot) lots = max_lot;
 

Thank you for the reply phi.nuts however If I convert _min_lot to a string (using DoubleToString), it ends up converting 0.01 over as 0.01000000 and then my calculations with StringLen don't work anymore.

 

angevoyageur, this seems to work well when the lot mins and steps are 1,.1,.01, etc but if the min lot is .5 and lot steps are .5, the MathLog function would still need some help.

 

For different step values, I know I can try MathMod() or maybe get the absolute value after dividing by the step value. I'm trying to make the EA robust enough to easily test across instruments without separate settings for anything that's different (now with forex across different leverage or future when other instruments are added).

 

Thanks 

 
tfworks.com:

...

 

angevoyageur, this seems to work well when the lot mins and steps are 1,.1,.01, etc but if the min lot is .5 and lot steps are .5, the MathLog function would still need some help.

 

For different step values, I know I can try MathMod() or maybe get the absolute value after dividing by the step value. I'm trying to make the EA robust enough to easily test across instruments without separate settings for anything that's different (now with forex across different leverage or future when other instruments are added).

 

Thanks 

You are right about lotstep like .5, but I never seen a lotstep which is not a power of ten in forex. You can add a test to check that. You can also see https://www.mql5.com/en/forum/112782 for another solution.
Calculation on Leverage & MM together in Expert Advisors. - MQL4 forum
  • www.mql5.com
Calculation on Leverage & MM together in Expert Advisors. - MQL4 forum
 

Ok, I got it all worked out.  This keeps the lot size in line with the lot step increments and rounds down to stay within my risk per position percentage.

 

double _lots_part1   = /* volatility adjusted position sizing calculation here */double _lot_step     = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);      
double _lots         = _lots_part1 - MathMod(_lots_part1,_lot_step);  

 

 

 

1. If you want to use String Operation to normalize double, then use StringFind and find the second digit after decimal point in minimum lot. If it's zero, then you have minimum lot with one digit after decimal point and so if it's not zero the you have minimum lot with two digit after decimal point.

2. That's not how to use lot step. Click here for an example, the example does not use Normalize double, but it's show how to use lot step.

 
phi.nuts:

1. If you want to use String Operation to normalize double, then use StringFind and find the second digit after decimal point in minimum lot. If it's zero, then you have minimum lot with one digit after decimal point and so if it's not zero the you have minimum lot with two digit after decimal point.

2. That's not how to use lot step. Click here for an example, the example does not use Normalize double, but it's show how to use lot step.

phi.nuts, I'm no longer using the string conversion functions as they are not the best way in this situation.  For your number 2, I'm not following how my use is not how to use lot step.  That link isn't doing the same thing as what I'm trying to do and I'm not sure if you mean the original code or the comments saying the code is all wrong.  

The last code I posted gets the result I'm looking for.  I've tested and verified my results and it gets my normalized lot size and strips away the unnecessary digits in my lot size calculation. 

 
tfworks.com:

phi.nuts, I'm no longer using the string conversion functions as they are not the best way in this situation.  For your number 2, I'm not following how my use is not how to use lot step.  That link isn't doing the same thing as what I'm trying to do and I'm not sure if you mean the original code or the comments saying the code is all wrong.  

The last code I posted gets the result I'm looking for.  I've tested and verified my results and it gets my normalized lot size and strips away the unnecessary digits in my lot size calculation. 

Alright, as long you're not MathMod the lot step like your last code. Angevoyageur use MathLog while you use MathMod and you both are wrong.

Why don't you print it and see the result

    Print ("symbol info ",SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP));
    Print ("Math Mod ", MathMod(SymbolInfoDouble (_Symbol, SYMBOL_VOLUME_MIN), SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP)));
    Print ("Math Log", MathLog(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP)));

In my MT it printed,

Symbol Info 0.01

MathMod 0.0

MathLog -4.605170185988091


 

Hope that was a scary typo there :(.

 
phi.nuts:

Alright, as long you're not MathMod the lot step like your last code. Angevoyageur use MathLog while you use MathMod and you both are wrong.

Why don't you print it and see the result

In my MT it printed,

Symbol Info 0.01

MathMod 0.0

MathLog -4.605170185988091


 

Hope that was a scary typo there :(.

1° Ok, I make a typo, my use of Mathlog is :

int      lotdigits   = (int) - MathLog10(SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP));
double   lots        = NormalizeDouble(_lotcalculation, lotdigits);

With MQL4, which has not a MathLog10 function, I use :

int lotdigits     = - MathRound(MathLog(MarketInfo(Symbol(),MODE_LOTSTEP)) / MathLog(10.0));


2° tfworks.com use :

MathMod(_lots_part1,_lot_step)

and not 

MathMod(_lots_min,_lot_step)

3° So...

    double lots      = 1.47;
    double lotstep   = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
    int lotdigits    = (int) - MathLog10(lotstep);
    double lotsdiff  = MathMod(lots, lotstep);

    Print ("Lots : ", DoubleToString(lots, 2));
    Print ("Symbol info lotstep : ", lotstep);

    Print ("Math Mod ", lotsdiff);
    Print ("Lots (mathmod) : ", lots - lotsdiff);

    Print ("Math Log - lotdigits : ", lotdigits);
    Print ("Lots (mathlog) : ", DoubleToString(lots, lotdigits));

Results

My method is better because tfworks.com use double arthmetic which is not always accurate. Mathlog only works if SYMBOL_VOLUME_STEP is a power of ten (never see this as not true).

4° I agree that method presented in your link is more generic. In the future I will use this one, thanks.



 

was not going to be a necroposter but i think it may be useful :)

int LotDigits(int str = 0)
{
    int digits = 0;
    double v = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    
    if (str)
    {
        string parts[];
        int count = StringSplit(string(v), '.', parts);
        digits = count == 2 ? StringLen(parts[1]) : 0;
    }
    else
    {
        for (int k = 1; k < 100 && MathFloor(v * k) == 0; k *= 10, digits++);
    }
    
    return(digits);
}

so, here are 2 ways to identify how many digits to use to normalize position volume :

1. if you want to rely on default MQL string formatter then simply use LotDigits(1)

2. if you want to loop through minimal allowed volume and find how many zeros you need to pass by then simply use LotDigits()

P.S. Tested with 0.01 / 0.5 / 5 - works fine, if anyone has more elegant solution - shout :)

Reason: