How to calculate LOT SIZE on different symbols?

 
Hi, I have a problem calculating the lot size on different symbols. In this case I present the example between the symbol US500 and USDNOK. The target risk is 0.5% of the account balance. US500 meets that risk, but USDNOK it's risking 0.05% on my tests.

US500 information:
Tick Size: 0.01
Tick Value: 0.01

USDNOK information:
Tick Size: 0.00001
Tick Value: 1.0

The following code correctly calculates the lot size for the US500 symbol but incorrectly for the USDNOK:

Important info: ("Porcentaje_de_Riesgo" it's an input (0,5% of risk).

//////////////////////////////
//--- Calculos de lotaje ---//
//////////////////////////////

double CalculateLotSize(bool isLong) {
    double balance = AccountInfoDouble(ACCOUNT_BALANCE);
    double riskPerTrade = balance * Porcentaje_de_Riesgo / 100.0; //Porcentaje de riesgo = Risk Percentage in Spanish

    double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

    //--- Calculate the Stop Loss in points (difference between the entry price and the SL)
    double stopLossPrice = isLong ? Low[1] - ATR[1] * Multiplicador_ATR : High[1] + ATR[1] * Multiplicador_ATR;
    double stopLossDistance = isLong ? ask - stopLossPrice : stopLossPrice - bid;

    //--- Convert SL distance to account currency
    double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
    double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
    double pointValue = tickValue / tickSize;

    //--- Calculate lot size
    double lotSize = riskPerTrade / (stopLossDistance * pointValue);

    //--- Normalize lot size according to symbol parameters
    double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
    double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
    double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

    lotSize = MathMax(minLot, MathMin(maxLot, lotSize));
    lotSize = NormalizeDouble(lotSize / lotStep, 0) * lotStep;

    return lotSize;
}


If there's info missing let me know and I will provide it. Thanks for the help!

 

You making it complicated for yourself. Please read the following posts ...

Forum on trading, automated trading systems and testing trading strategies

How to properly calculate target price for a profit value`

Fernando Carreiro, 2024.12.13 13:53

For MQL5, just use the OrderCalcProfit()MQL5 Book: Trading automation / Creating Expert Advisors / Estimating the profit of a trading operation: OrderCalcProfit

For many symbols, the maths is usually as follows, but not always, so it is best to use OrderCalcProfit().

Forum on trading, automated trading systems and testing trading strategies

How to calculate take profit from currency

Fernando Carreiro, 2022.09.05 17:00

These are all the same equation written in different ways ...

[Volume]      = [Money Value] * [Tick Size] / ( [Tick Value] * [Stop Size] )
[Stop Size]   = [Money Value] * [Tick Size] / ( [Tick Value] * [Volume]    )
[Money Value] = [Volume]      * [Stop Size] * [Tick Value]   / [Tick Size]

[Volume] in lots
[Stop Size] in quote price change
[Money Value] in account currency

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 properly calculate target price for a profit value`

Fernando Carreiro, 2024.12.13 14:01

In case you are curious, the documentation describes the various calculations that OrderCalcProfit() and OrderCalcMargin() apply depending on the situation.

ENUM_SYMBOL_CALC_MODE

Identifier

Description

Formula

SYMBOL_CALC_MODE_FOREX

Forex mode - calculation of profit and margin for Forex

Margin:  Lots * Contract_Size / Leverage * Margin_Rate

 

Profit:   (close_price - open_price) * Contract_Size*Lots

SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE

Forex No Leverage mode – calculation of profit and margin for Forex symbols without taking into account the leverage

Margin:  Lots * Contract_Size * Margin_Rate

 

Profit:   (close_price - open_price) * Contract_Size * Lots

SYMBOL_CALC_MODE_FUTURES

Futures mode - calculation of margin and profit for futures

Margin: Lots * InitialMargin * Margin_Rate

 

Profit:  (close_price - open_price) * TickPrice / TickSize*Lots

SYMBOL_CALC_MODE_CFD

CFD mode - calculation of margin and profit for CFD

Margin: Lots * ContractSize * MarketPrice * Margin_Rate

 

Profit:  (close_price - open_price) * Contract_Size * Lots

SYMBOL_CALC_MODE_CFDINDEX

CFD index mode - calculation of margin and profit for CFD by indexes

Margin: (Lots * ContractSize * MarketPrice) * TickPrice / TickSize * Margin_Rate

 

Profit:  (close_price - open_price) * Contract_Size * Lots

SYMBOL_CALC_MODE_CFDLEVERAGE

CFD Leverage mode - calculation of margin and profit for CFD at leverage trading

Margin: (Lots * ContractSize * MarketPrice) / Leverage * Margin_Rate

 

Profit:  (close_price-open_price) * Contract_Size * Lots

SYMBOL_CALC_MODE_EXCH_STOCKS

Exchange mode – calculation of margin and profit for trading securities on a stock exchange

Margin: Lots * ContractSize * LastPrice * Margin_Rate

 

Profit:  (close_price - open_price) * Contract_Size * Lots

SYMBOL_CALC_MODE_EXCH_FUTURES

Futures mode –  calculation of margin and profit for trading futures contracts on a stock exchange

Margin: Lots * InitialMargin * Margin_Rate or Lots * MaintenanceMargin * Margin_Rate

 

Profit:  (close_price - open_price) * Lots * TickPrice / TickSize

SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS

FORTS Futures mode –  calculation of margin and profit for trading futures contracts on FORTS. The margin may be reduced by the amount of MarginDiscount deviation according to the following rules:

1. If the price of a long position (buy order) is less than the estimated price, MarginDiscount = Lots*((PriceSettle-PriceOrder)*TickPrice/TickSize)

2. If the price of a short position (sell order) exceeds the estimated price, MarginDiscount = Lots*((PriceOrder-PriceSettle)*TickPrice/TickSize)

where:

    • PriceSettle – estimated (clearing) price of the previous session;
    • PriceOrder – average weighted position price or open price set in the order (request);
    • TickPrice – tick price (cost of the price change by one point)
    • TickSize – tick size (minimum price change step)

Margin: Lots * InitialMargin * Margin_Rate or Lots * MaintenanceMargin * Margin_Rate

 

Profit:  (close_price - open_price) * Lots * TickPrice / TickSize

SYMBOL_CALC_MODE_EXCH_BONDS

Exchange Bonds mode – calculation of margin and profit for trading bonds on a stock exchange

Margin: Lots * ContractSize * FaceValue * open_price * /100

 

Profit:  Lots * close_price * FaceValue * Contract_Size  + AccruedInterest * Lots * ContractSize

SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX

Exchange MOEX Stocks mode – calculation of margin and profit for trading securities on MOEX

Margin: Lots * ContractSize * LastPrice * Margin_Rate

 

Profit:  (close_price - open_price) * Contract_Size * Lots

SYMBOL_CALC_MODE_EXCH_BONDS_MOEX

Exchange MOEX Bonds mode – calculation of margin and profit for trading bonds on MOEX

Margin: Lots * ContractSize * FaceValue * open_price * /100

 

Profit:  Lots * close_price * FaceValue * Contract_Size  + AccruedInterest * Lots * ContractSize

SYMBOL_CALC_MODE_SERV_COLLATERAL

Collateral mode - a symbol is used as a non-tradable asset on a trading account. The market value of an open position is calculated based on the volume, current market price, contract size and liquidity ratio. The value is included into Assets, which are added to Equity. Open positions of such symbols increase the Free Margin amount and are used as additional margin (collateral) for open positions of tradable instruments.

Margin: no

Profit:  no

 

Market Value: Lots*ContractSize*MarketPrice*LiqudityRate

 
Fernando Carreiro #:

You making it complicated for yourself. Please read the following posts ...

Hello, I've been trying to understand everything you sent but I arrive at the same point, I want to calculate the volume of my trades with consistency on every symbol and I'm not achieving it.

I always use the simple method of using tick value, tick size, lot step, balance and risk percent, but only works for USD symbols.

From what I understand OrderCalcProfit only works to calculate the expected benefit and not volume size, I'm I wrong? 

The actual code I'm using is this:

//////////////////////////////
//--- Calculos de lotaje ---//
//////////////////////////////

double CalculateLotSize(double riskPercent, double slDistance){
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   
   if(tickSize == 0 || tickValue == 0 || lotStep == 0){
      Print(__FUNCTION__," > LotSize cannot be calculated...");
      return 0;
   }
   
   double riskMoney = AccountInfoDouble(ACCOUNT_BALANCE) * riskPercent / 100;
   double moneyLotstep = (slDistance / tickSize) * tickValue * lotStep;
   
   if(moneyLotstep == 0){
      Print(__FUNCTION__," > Lotsize cannot be calculated...");
      return 0;
   }
   double lots = MathFloor(riskMoney / moneyLotstep) * lotStep;
   
   return lots;
}  
 
cangreburguer #: From what I understand OrderCalcProfit only works to calculate the expected benefit and not volume size, I'm I wrong? 

Seems you skipped some of the details I gave you ...

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 ...
};
 
cangreburguer #:

Hello, I've been trying to understand everything you sent but I arrive at the same point, I want to calculate the volume of my trades with consistency on every symbol and I'm not achieving it.

I always use the simple method of using tick value, tick size, lot step, balance and risk percent, but only works for USD symbols.

From what I understand OrderCalcProfit only works to calculate the expected benefit and not volume size, I'm I wrong? 

The actual code I'm using is this:

There should not be a problem with this function. It should work on all symbols. Make sure the  slDistance is in points (for the symbol). Better to convert to points automatically then to type in the point value. You are using SYMBOL_TRADE_TICK_SIZE and SYMBOL_TRADE_TICK_VALUE which is correct and important to get the correct lot size value (especially important to use both of these when calculating a lot size on assets outside of forex)