How to calculate lot size based on a given USD amount

 

I am MQL5 beginner, and wonder if I can get an expert feedback on something. I found several codes that calculate lot size based on risk amount, etc. I want to create a simpler function to calculate the lot size in any given currency pair, given a USD amount. I created the function below, which works, but I wonder if there is a simpler way to do this?


CalculateLotSize(string PairName, double USDAmount)
{
double LotSize;
double ToUSDExchRate; //variable holds exchange rate of base currency to USD
string PrimaryCurrency   =StringSubstr(PairName, 0,3); //Base currency
string SecundaryCurrency =StringSubstr(PairName, 3,6); //Quote currency

string PrimaryCurrencyToUSd;     //holder for name of pair that exchanges to USD
string SecundaryCurrencyToUSd;   //Same as above but in case broker only provides the reverse forex pair to USD.


bool IsMetal =( PairName=="XAGUSD" || PairName=="XAUUSD"); // make differrent calculations for this metals.

if(IsMetal==false)
{
   if (PrimaryCurrency=="USD")
      {
         ToUSDExchRate=1;
      } else{
      //find exchange rate of primary currency to USD. 
      PrimaryCurrencyToUSd   = PrimaryCurrency +"USD";
      SecundaryCurrencyToUSd ="USD"+ PrimaryCurrency;
      
      ToUSDExchRate =  iClose(PrimaryCurrencyToUSd,PERIOD_M1,0);
      if(!ToUSDExchRate) {ToUSDExchRate =  1/iClose(SecundaryCurrencyToUSd,PERIOD_M1,0);}//Becuase CHFUSD is not available but the reverse USDCHF.
      
   }
LotSize=USDAmount/ToUSDExchRate/100000 ; 

} else {

   double Metalprice= iClose(PairName,PERIOD_M1,0);
   double SharesToBuy  =  USDAmount/Metalprice;
   LotSize  = SharesToBuy*0.01;
   if(PairName=="XAGUSD"){LotSize=SharesToBuy*0.01/50;} //in silver a lot is 50 times more than in gold
   
}   

//Trim lot size to digits of minimum lot required by the broker.
   LotSize= LotSize*100;
   string sLotSize=DoubleToString(LotSize,8);
   string vals[2] = {"", ""};
   StringSplit(sLotSize, '.', vals);
   LotSize=StringToDouble(vals[0])/100;


return(LotSize);

}
 

what about using a risk percentage instead of USD amount? For example, 100% would be the full account equity

Calculation of lot size has to be at least based on something like risk percentage of account equity (or else something like a minimum volume or maximum volume), otherwise it's not really making much sense what kind of lot size you're trying to obtain

double LotsizeCalculate(double riskPercentage, double limit){

    double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
    double marginRequired = SymbolInfoDouble(Symbol(), SYMBOL_MARGIN_INITIAL);
    long currentLeverage = AccountInfoInteger(ACCOUNT_LEVERAGE);

    // Calculate the lot size based on equity, risk percentage, and margin requirement
    double maxLoss = riskPercentage / 100.0 * currentEquity; 
    double volume_calculation = maxLoss / (marginRequired / currentLeverage);       
    double vol = MathMin(NormalizeDouble(volume_calculation, 2), limit);
        
    return vol;
}


so for the maximum lot size, that would be 100% risk and you would call this function like this:

LotsizeCalculate(100, 10.0);

For minimal risk you might just risk 2% of the account

LotsizeCalculate(2, 10.0);

this second argument where I put 10.0 is a maximum allowed lot size which is yet another risk management feature you could use with it

 
Camilo Mora:

I am MQL5 beginner, and wonder if I can get an expert feedback on something. I found several codes that calculate lot size based on risk amount, etc. I want to create a simpler function to calculate the lot size in any given currency pair, given a USD amount. I created the function below, which works, but I wonder if there is a simpler way to do this?


Consult the functions in the file they will give you a general idea .

In the examples wont be referring to the $ as "USD Amount " but "Deposit Currency Amount"

If you want to use the Deposit Currency Amount for margin then you query the margin for one lot required

double margin_for_one_lot=0.0;
if(get_margin_for_one_lot(string symbol,ENUM_ORDER_TYPE type,margin_for_one_lot)){
double lots_possible=amount_in_deposit_currency/margin_for_one_lot;
//then check lot against limits of the symbol , and check its digits 
}

If you want to use the Deposit Currency Amount for risk , i.e. the amount you want to lose with a stop loss

double tick_value_for_one_lot=0.0;
if(get_tick_value_for_one_lot(string symbol,ENUM_ORDER_TYPE type,tick_value_for_one_lot)){
//multiply by your sl size in ticks
tick_value_for_one_lot*=((double)SLTicks);
//now you know what the SL costs for 1Lot so if you divide the amount willing to lose by that you get the lot size
double possible_lot=amount_in_deposit_currency/tick_value_for_one_lot;
//check against lot limits and digits of symbol
}
bool get_tick_value_for_one_lot(string symbol,
                                ENUM_ORDER_TYPE type,
                                double &result){
//result will be in account currency !
  result=0.0;
  int errors=0;
  ResetLastError();
//first get the price 
  double price=0.0;
  if(type==ORDER_TYPE_BUY){
  price=(double)SymbolInfoDouble(symbol,SYMBOL_ASK);
  errors+=GetLastError();ResetLastError();
  }else if(type==ORDER_TYPE_SELL){
  price=(double)SymbolInfoDouble(symbol,SYMBOL_BID);
  errors+=GetLastError();ResetLastError();
  }else{errors=1;}
  //if no errors
  if(errors==0){
  double point=(double)SymbolInfoDouble(symbol,SYMBOL_POINT);errors+=GetLastError();ResetLastError();
  double close_price=price;
  if(type==ORDER_TYPE_BUY){close_price=price+point;}
  else if(type==ORDER_TYPE_SELL){close_price=price-point;}
  if(errors==0){
  if(OrderCalcProfit(type,symbol,1.0,price,close_price,result)){
    return(true);
    }
  }
  }
return(false);                            
}
bool get_margin_for_one_lot(string symbol,
                            ENUM_ORDER_TYPE type,
                            double &result){
//result will be in account currency
  result=0.0;
  int errors=0;
  ResetLastError();
//first get the price 
  double price=0.0;
  if(type==ORDER_TYPE_BUY){
  price=(double)SymbolInfoDouble(symbol,SYMBOL_ASK);
  errors+=GetLastError();ResetLastError();
  }else if(type==ORDER_TYPE_SELL){
  price=(double)SymbolInfoDouble(symbol,SYMBOL_BID);
  errors+=GetLastError();ResetLastError();
  }else{errors=1;}
  //if no errors
  if(errors==0){
  if(OrderCalcMargin(type,symbol,1.0,price,result)){
    return(true);
    }
  }
return(false);                            
}
Files:
 
Camilo Mora:

I am MQL5 beginner, and wonder if I can get an expert feedback on something. I found several codes that calculate lot size based on risk amount, etc. I want to create a simpler function to calculate the lot size in any given currency pair, given a USD amount. I created the function below, which works, but I wonder if there is a simpler way to do this?


In the example below, MinimumBalance means the USD amount for every 0.01 Lots or the smallest lot value for that currency pair. The EA user should be able to set this amount(in case they expect the EA to AutoCalculateLots)

And then we proceed like this:

input bool AutoCalculateLots=true;
input double FixedLots=0.1;//FixedLots(in case AutoCalculateLots=false)
input double MinimumBalance=100;//MinimumBalance(Bal for every 0.01 Lots)
//-----------------------------------------------------------------------------------

double Lots=NULL;

void OnTick(){
if(!AutoCalculateLots){
Lots=FixedLots;//Hope we are together here
}
else{
double MaxLots=SymbolInfoDouble(NULL,SYMBOL_VOLUME_MAX), MinLots=SymbolInfoDouble(NULL,SYMBOL_VOLUME_MIN);
double Volume=NormalizeDouble((AccountInfoDouble(ACCOUNT_BALANCE)*MinLots/MinimumBalance), 2);// 2 means the max decimal places in the Lot value eg 0.55 Lots

if(Lots<Volume)//Remember Lots was initialized as NULL
Lots=Volume;
if(Lots<MinLots)
Lots=MinLots;
if(Lots>MaxLots)
Lots=MaxLots;
}

}

We could as well use percentageRiskPerTrade to calculate the Lots. Lets begin on this above.