How To Get Lot Size Base On Money Amount, Open Price And Stop Loss

 

Hi, I have an ideal that I can get lot size by amount of money at risk. But MQL5 doesn't have a default function to do that.

So I create a function like:

double GetLot(ENUM_ORDER_TYPE type, double SL, double openPrice, double moneyAmount) {
  if(moneyAmount == 0 || SL == 0 || openPrice == 0) return NULL;

  double lotSize1 = 0.01;
  double lotSize2 = 0.02;
  while(lotSize2 <= 100) {
      double lose1;
      double lose2;
      
      if(!OrderCalcProfit(type, _Symbol, lotSize1, openPrice, SL, lose1)) return NULL;
      if(!OrderCalcProfit(type, _Symbol, lotSize2, openPrice, SL, lose2)) return NULL;
      if((lose2 < moneyAmount && lose1 > moneyAmount) || (lose1 <= moneyAmount)) return lotSize1;
      
      lotSize1 += 0.01;
      lotSize2 += 0.01;
  }
  return NULL;
}

I know this method is quite ineffective, do you have any more promising and optimal ideas?

Happy weekend!

 

You are using the correct function but applying it incorrectly ...

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 ...
};
 
I have optimized it, thank you for the guidance
 
It is a good habit to use OrderCalcProfit() (rather than SYMBOL_TRADE_TICK_VALUE) to get lot size. As it also works correctly for commodities like gold .

You need to round the returned lotsize to lot steps, and adjust to broker limits. Also, you need to check calculated lotsize against the free margin in the account.
 
double GetLot(ENUM_ORDER_TYPE type, double SL, double openPrice, double moneyAmount) {
  if(moneyAmount == 0 || SL == 0 || openPrice == 0) return 0;

  //--- Adjust volume to broker limits.
  double minvol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
  double maxvol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
  double stepvol =SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

  double lotSize1 = maxvol;
  double lose1 = 0;

  while(lotSize1 >= minvol) {

      if(!OrderCalcProfit(type, _Symbol, lotSize1, openPrice, SL, lose1) || (lose1 >= 0)) return NULL;
      if(MathAbs(lose1) <= moneyAmount) return lotSize1;

      //--- round the lotsize to lot steps
      lotSize1 = MathRound(lotSize1/stepvol-1)*stepvol;
  }
  return NULL; // not taking this trade
}

This is an optimized version of your function.

However, it is not the most efficient way to use OrderCalcProfit(), as the while loop body has to execute for many times.

Reason: