How to Calculate Lot Size by Risk Percentage in MQL5 (EA Code + Real Backtest)

Published 2026-10-24 · Ranar Algo

To calculate lot size by risk percentage in MQL5, take the money you are willing to lose (balance × risk %), divide it by the loss one full lot would take between entry and stop loss (get that from OrderCalcProfit), then round the result down to the symbol's SYMBOL_VOLUME_STEP and clamp it between SYMBOL_VOLUME_MIN and SYMBOL_VOLUME_MAX. If the rounded volume is below the minimum, skip the trade.

Why fixed lots are a problem

Most beginner EAs trade a hard-coded 0.10 lots. That means a 200-point stop and a 900-point stop risk very different amounts of money, and the risk does not shrink when the account shrinks. Risk-based sizing fixes both: every trade risks the same share of the account, whatever the stop distance.

The usual hand-rolled formula is lots = risk / (stopPoints × tickValue). It works on EURUSD and quietly breaks elsewhere: tick value is quoted per tick size, not per point (gold, indices and many CFDs have a tick size larger than _Point), and on cross pairs the tick value moves with the exchange rate. You can do it correctly with SYMBOL_TRADE_TICK_VALUE_LOSS and SYMBOL_TRADE_TICK_SIZE, but there is a simpler route.

Let the terminal do the money maths: OrderCalcProfit

OrderCalcProfit(action, symbol, volume, price_open, price_close, profit) returns, in account currency, the profit of a trade from price_open to price_close. Ask it for 1.0 lot from your entry to your stop and you get the exact loss per lot, with contract size, tick size and currency conversion already handled. The value is negative for a losing move, so take MathAbs.

// Lots so that hitting the stop loses InpRiskPct % of balance.
double CalcLots(ENUM_ORDER_TYPE type, double entry, double sl)
  {
   if(sl <= 0.0 || InpRiskPct <= 0.0)
      return(0.0);
   double riskMoney = AccountInfoDouble(ACCOUNT_BALANCE) * InpRiskPct / 100.0;
   double lossPerLot = 0.0;
   if(!OrderCalcProfit(type, _Symbol, 1.0, entry, sl, lossPerLot) || lossPerLot >= 0.0)
     {
      Print("OrderCalcProfit failed, err=", GetLastError());
      return(0.0);
     }
   double lots = riskMoney / MathAbs(lossPerLot);
   double step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double vmin = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double vmax = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   lots = MathFloor(lots / step) * step;   // round DOWN so risk never exceeds target
   if(lots < vmin)
      return(0.0);                          // stop too wide for this balance: skip trade
   return(NormalizeDouble(MathMin(lots, vmax), 2));
  }

Three details matter here:

Using it in an EA

Compute the stop first, then the volume, then send the order:

double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double sl  = NormalizeDouble(ask - InpStopLossPts * _Point, _Digits);
double tp  = NormalizeDouble(ask + InpTakeProfPts * _Point, _Digits);
double lots = CalcLots(ORDER_TYPE_BUY, ask, sl);
if(lots > 0.0)
   c_Trade.Buy(lots, _Symbol, ask, sl, tp);

InpRiskPct is an input (1.0 = 1% per trade). Use ACCOUNT_BALANCE if you want risk to stay constant while trades are open; switch to ACCOUNT_EQUITY if you want it to shrink with floating losses. One limitation: NormalizeDouble(..., 2) assumes a volume step of 0.01 or coarser, which covers almost every forex and CFD symbol; if your broker uses 0.001 steps, normalise to 3 digits instead.

Real backtest of the example EA

We dropped CalcLots into a simple RSI(14) reversal EA (buy on a cross up through 30, sell on a cross down through 70, exit at 50, 500-point SL, 900-point TP, 1% risk per trade) and ran it in the MetaTrader 5 Strategy Tester:

The point of the test is the sizing, not the signal: with a 1% risk cap the drawdown stays small even across losing streaks. Six months on one pair is a tiny sample and says nothing about other periods or symbols. Past performance does not guarantee future results.

Skip the boilerplate

If you would rather describe the rule than write it, Ranar Algo takes a plain-English strategy ("RSI 14 reversal on EURUSD H1, risk 1% per trade, 500-point stop"), generates the MQL5 Expert Advisor, compiles it, and runs a real MT5 backtest so you see the numbers before you trust the code. You get the source and you keep your IP. It is still improving, so feedback on anything it gets wrong is welcome.

Summary

Risk-based lot sizing in MQL5 is four steps: risk money from balance, loss per lot from OrderCalcProfit, round down to the volume step, clamp to min/max and skip if too small. It is a few lines, it works on every symbol your broker offers, and it is the single change that does most to keep an EA's drawdown under control.

Build & backtest your own EA free →

Ranar Algo turns a plain-English strategy into a compiled MQL5 Expert Advisor with a real MetaTrader 5 backtest. You keep your IP. Past performance does not guarantee future results.