Learning Center

Risk-based position sizing in MQL5: from percent risk to lots

Convert Pine strategy.percent_of_equity and fixed-risk sizing into a lot size that respects the broker volume step and limits.

Why sizing does not translate directly

Pine sizes orders in contracts, units or a percent of equity, and the emulator accepts fractional quantities. MetaTrader sizes in lots, and every symbol has a minimum volume, a maximum and a step (often 0.01). The value of one point also depends on the symbol and account currency.

Typical Pine input

Risking 1% of equity with a stop distance in price terms:

Pine Script

//@version=5
strategy("Sized", overlay=true)
riskPct = input.float(1.0)
stopDist = ta.atr(14) * 2
qty = (strategy.equity * riskPct / 100) / stopDist
if ta.crossover(close, ta.sma(close, 50))
    strategy.entry("L", strategy.long, qty=qty)
    strategy.exit("X", "L", stop=close - stopDist)

The MQL5 lot calculation

Use SYMBOL_TRADE_TICK_VALUE and SYMBOL_TRADE_TICK_SIZE to find how much money one lot gains or loses per price unit, then round down to the volume step so you never exceed the intended risk.

MQL5

double LotsForRisk(double riskPct, double stopDistancePrice){
   double equity   = AccountInfoDouble(ACCOUNT_EQUITY);
   double riskCash = equity * riskPct / 100.0;
   double tickVal  = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   if(tickVal <= 0 || tickSize <= 0 || stopDistancePrice <= 0) return 0;
   double lossPerLot = stopDistancePrice / tickSize * tickVal;
   double lots = riskCash / lossPerLot;
   double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double minV = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxV = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   lots = MathFloor(lots / step) * step;
   if(lots < minV) return 0;          // risk too small for this account: skip the trade
   return MathMin(lots, maxV);
}

Common mistakes

Rounding up to the minimum lot silently increases risk; returning 0 and skipping the trade is safer. Tick value is quoted in the account currency and can change with exchange rates, so calculate it at order time, not once in OnInit. Check margin with OrderCalcMargin before sending large orders.

Always confirm the result in the Strategy Tester journal: print the lot size and the stop distance for the first few trades and check the money at risk by hand.

Related code snippets