LotSize Calculation adjusted for MarketInfo LOTSIZE & LOTSTEP?

 

Hi,

I'm very new to mql4 programming and I can't figure out how to adjust my lot sizes for different brokers that have different LOTSIZE and LOTSTEP values. The code below is an excerpt from an order script that calculates the lotsizes used for each trade based on inputs for my stop loss, spread and my chosen percentage of my account balance or equity. How can I add Lotsize and Lotstep to the code below to automatically adjust the final tradesize value for different brokers using different LOTSIZE and LOTSTEP values?


Thank you very much and I'm hoping to hear from someone soon.

Regards,
Peter

//set the default lot size here. set to 0 to use autorisk
extern double tradesize = 0.0;   
int LotDigits      = 1;
int Digit_Factor   = 1;
//How to use the Lotsize and Lotstep values below to adjust
//the tradesize for different brokers automatically?
double Lotsize = MarketInfo(Symbol(),MODE_LOTSIZE);

double Lotstep = MarketInfo(Symbol(),MODE_LOTSTEP);
//====================================================================================
//Gather broker trade details 2, 3, 4, 5, 6, 7 digits & volume information
   if(Digits == 2 || Digits == 4) Digit_Factor = 1;
   if(Digits == 3 || Digits == 5) Digit_Factor = 10;
   if(Digits == 6) Digit_Factor = 100;  

   if(Digits == 7) Digit_Factor = 1000;
   double One_Tick = MarketInfo(Symbol(),MODE_TICKVALUE) * Digit_Factor;
   double MaxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double MinLot = MarketInfo(Symbol(), MODE_MINLOT);
   if (Lotstep) == 0.01)LotDigits = 2;
//====================================================================================
//Calculate the trade volume based on the desired stoploss + spread & risk
   double Ask = MarketInfo(Symbol(), MODE_ASK); 
   double Bid = MarketInfo(Symbol(), MODE_BID);
   double spread = Ask - Bid;
   if (tradesize == 0){
   double Risk_In_Money = ((stoploss+spread)/Point/Digit_Factor) * One_Tick;
   // %risk = $ loss >>> SL = allowed volume
   //To use account balance replace AccountEquity() with  AccountBalance()
   tradesize = NormalizeDouble(((AccountEquity() * risk/100)/Risk_In_Money),LotDigits);
   }
   if (tradesize > MaxLot)tradesize = MaxLot;
   if (tradesize < MinLot)tradesize = MinLot;

//====================================================================================  
 
tradesize = NormalizeDouble(((AccountEquity() * risk/100)/Risk_In_Money),LotDigits); 

  1. For large amounts of code, attach it
  2. Never use NormalizeDouble EVER
  3. You are assumeing that lotstep is a multiple of 10. Never assume. See #2
  4. Don't use tick value by itself
    double DeltaValuePerLot(string pair=""){
        //{ Value in account currency of a Point of Symbol.
        // In tester I had a sale: open=1.35883 close=1.35736 (0.0147)
        // gain$=97.32/6.62 lots/147 points=$0.10/point or $1.00/pip.
        // IBFX demo/mini       EURUSD TICKVALUE=0.1 MAXLOT=50 LOTSIZE=10,000
        // IBFX demo/standard   EURUSD TICKVALUE=1.0 MAXLOT=50 LOTSIZE=100,000
        //                                  $1.00/point or $10.0/pip.
        //
        // https://forum.mql4.com/33975 CB: MODE_TICKSIZE will usually return the
        // same value as MODE_POINT (or Point for the current symbol), however, an
        // example of where to use MODE_TICKSIZE would be as part of a ratio with
        // MODE_TICKVALUE when performing money management calculations which need
        // to take account of the pair and the account currency. The reason I use
        // this ratio is that although TV and TS may constantly be returned as
        // something like 7.00 and 0.0001 respectively, I've seen this
        // (intermittently) change to 14.00 and 0.0002 respectively (just example
        // tick values to illustrate).
        // https://forum.mql4.com/43064#515262 zzuegg reports for non-currency DE30:
        // MarketInfo(chart.symbol,MODE_TICKSIZE) returns 0.5
        // MarketInfo(chart.symbol,MODE_DIGITS) return 1
        // Point = 0.1
        // Prices to open must be a multiple of ticksize
        //}
        if (pair == "") pair = Symbol();
        return(  MarketInfo(pair, MODE_TICKVALUE)
               / MarketInfo(pair, MODE_TICKSIZE) ); // Not Point.
    }
    
  5. You are not adjusting for free margin. Not just when you open, but at the most adverse excursion (for ALL open orders) i.e. at the stop loss. See my code.
 

Thank you RaptorUK and WHRoeder. I used the SRC button to fix my posted code and I replace NormalizeDouble with DeltaValuePerLot but I'm not sure if I did it correctly. I also looked at your Lot size computation code in WHRea.mq4 to figure out how you adjusted for free margin with your code quoted below but unfortunately I could not figure out how you calculated all the variables since they are dependent on many other implicit variables so I just used the simple AccountFreeMarginCheck code from https://docs.mql4.com/account/AccountFreeMarginCheck

double  AFMC    = AccountFreeMarginCheck(Symbol(), op.code, size),
        eRisk   = equity.at.risk + at.risk.new;
if (AFMC*0.99 <= eRisk){
    size *= 0.95;   status = "Free Margin";
    continue;   }   // Prevent margin call if new trade goes against us.

I'll really appreciate it if you can adjust my code below to properly do the AFMC as you did in your code, otherwise, could you just check whether my use of your DeltaValuePerLot and MathFloor, MathMax code is correct for calculating my final tradesize adjusted for brokers using different LOTSIZE and LOTSTEP values? And is MarketInfo Mode LOTSIZE needed at all?

Thanks again for all your help and here is my attempt at modifying my code.

//set the default lot size here. set to 0 to use autorisk
extern double tradesize = 0.0;

//set your risk in % here
extern double   risk    = 0.02;  
//int      LotDigits    = 1;
int      Digit_Factor   = 1;

double  DeltaValuePerLot(string pair=""){
    if (pair == "") pair = Symbol();
    return(  MarketInfo(pair, MODE_TICKVALUE)
           / MarketInfo(pair, MODE_TICKSIZE) ); // Not Point.
}

//How to use the Lotsize and Lotstep values below to adjust
//the tradesize for different brokers automatically?
double Lotsize = MarketInfo(Symbol(),MODE_LOTSIZE);
double Lotstep = MarketInfo(Symbol(),MODE_LOTSTEP);

//==================================================================================== 
//Gather broker trade details 2, 3, 4 or 5 digits & volume information

   if(Digits == 2 || Digits == 4) Digit_Factor = 1;
   if(Digits == 3 || Digits == 5) Digit_Factor = 10;
   if(Digits == 6) Digit_Factor = 100;   
   if(Digits == 7) Digit_Factor = 1000;
   
   if (Digits == 3 || Digits == 5)Digit_Factor = 10;
   double One_Tick = MarketInfo(Symbol(),MODE_TICKVALUE) * Digit_Factor;
   double MaxLot = MarketInfo(Symbol(), MODE_MAXLOT);
   double MinLot = MarketInfo(Symbol(), MODE_MINLOT);
   //if (MarketInfo(Symbol(),MODE_LOTSTEP) == 0.01)LotDigits = 2;
//==================================================================================== 
//Calculate the trade volume based on the desired stoploss + spread & risk
   double Ask = MarketInfo(Symbol(), MODE_ASK);  
   double Bid = MarketInfo(Symbol(), MODE_BID);
   double spread = Ask - Bid;
   if (tradesize == 0){
   double Risk_In_Money = ((stoploss+spread)/Point/Digit_Factor) * One_Tick;
   // %risk = $ loss >>> SL = allowed volume
   //To use account balance replace AccountEquity() with  AccountBalance()
   tradesize = ((AccountEquity() * risk/100)/Risk_In_Money) * DeltaValuePerLot;
   tradesize = MathFloor(MathMax(0,tradesize)/lotStep)*lotStep;

   //Check for FreeMargin
   if(AccountFreeMarginCheck(Symbol(),OP_BUY,tradesize)<=0 || GetLastError()==134){
      Alert("Not enough money");
      return(0);
   }
   if (tradesize > MaxLot)tradesize = MaxLot;
   if (tradesize < MinLot)tradesize = MinLot;
//====================================================================================  
Reason: