Position sizing is the most underestimated variable in forex EA performance. The same strategy with different position sizing rules produces dramatically different results — same entries, same exits, but one account survives drawdowns and compounds wealth while the other blows up. This guide covers how to implement position sizing correctly in MT5 Expert Advisors.
Risk warning: Incorrect position sizing is a leading cause of account losses in automated trading. See our risk disclosure before trading with real capital.
Why Position Sizing Matters More Than Entry Signals
Consider two traders running the same EUR/USD strategy with a 50% win rate and 2:1 reward-to-risk ratio:
- Trader A: Fixed 2% risk per trade, $10,000 account
- Trader B: Fixed 0.10 lot per trade, $10,000 account
After 20 consecutive losses (rare but possible with any strategy):
- Trader A has lost 33% of the account (each loss at 2% of diminishing equity)
- Trader B's loss depends entirely on where price went — could be 20% or 60%+
Trader A's strategy keeps position size proportional to account size. As the account shrinks during a drawdown, so does exposure. Trader B's fixed-lot strategy maintains the same nominal risk even as the account shrinks — creating accelerating losses.
This single difference — risk-proportional vs. fixed position sizing — is the difference between surviving drawdowns and not.
The Core Formula: Risk-Based Position Sizing
The professional standard for position sizing:
Lot Size = (Account Equity × Risk Per Trade %) / (Stop Loss in Pips × Pip Value)Components:
- Account Equity: Current account value (not balance — use equity to account for floating P&L)
- Risk Per Trade %: The percentage of equity you're willing to risk on this trade (typically 0.5–2%)
- Stop Loss in Pips: The distance from entry to stop loss
- Pip Value: The value of one pip for one lot of the instrument
Example:
- Account equity: $10,000
- Risk per trade: 1% = $100
- Stop loss: 25 pips
- EUR/USD pip value (1 standard lot): $10 per pip
Lot Size = $100 / (25 × $10) = $100 / $250 = 0.40 lotsThis position size means a 25-pip loss equals exactly $100 = 1% of the $10,000 account.
Implementing Position Sizing in MQL5
//+------------------------------------------------------------------+
//| Calculate lot size based on risk percentage |
//+------------------------------------------------------------------+
double CalculateLotSize(double riskPercent, double stopLossPips)
{
double accountEquity = AccountInfoDouble(ACCOUNT_EQUITY);
double riskAmount = accountEquity * (riskPercent / 100.0);
// Get pip value for this symbol
// Pip value = (tick value / tick size) × 10
// For most pairs: 1 pip = 10 ticks (0.0001 / 0.00001 = 10)
double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
double pipValue = (tickValue / tickSize) * 0.0001;
// Handle JPY pairs and other non-standard pip values
// For pairs like USD/JPY where pip = 0.01 not 0.0001:
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
if(point == 0.001 || point == 0.01) // JPY or similar
pipValue = (tickValue / tickSize) * 0.01;
// Calculate lot size
double lotSize = riskAmount / (stopLossPips * pipValue);
// Round to allowed lot step
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
lotSize = MathFloor(lotSize / lotStep) * lotStep;
// Enforce broker's minimum and maximum
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
lotSize = MathMax(minLot, MathMin(maxLot, lotSize));
return lotSize;
}Usage in OnTick:
// Example: trade with 1% risk, 25-pip stop
double lots = CalculateLotSize(1.0, 25);
Print("Calculated lot size: ", lots);ATR-Based Dynamic Stop Loss
Rather than using a fixed pip stop, ATR (Average True Range) automatically adjusts the stop to current market volatility:
input double ATRMultiplier = 2.0; // Stop = 2× ATR
input double RiskPercent = 1.0; // Risk 1% per trade
int atrHandle;
int OnInit()
{
atrHandle = iATR(_Symbol, PERIOD_CURRENT, 14);
return(atrHandle != INVALID_HANDLE ? INIT_SUCCEEDED : INIT_FAILED);
}
void OnTick()
{
// Get ATR value from last completed bar
double atrValues[];
ArraySetAsSeries(atrValues, true);
CopyBuffer(atrHandle, 0, 0, 2, atrValues);
double atr = atrValues[1]; // Last completed bar's ATR
// Convert ATR to pips (ATR is in price units, e.g., 0.0012 = 12 pips for EUR/USD)
double pointSize = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double atrPips = atr / (pointSize * 10); // Divide by 10 for 5-decimal brokers
// Dynamic stop loss = ATR × multiplier
double stopLossPips = atrPips * ATRMultiplier;
// Calculate position size for this dynamic stop
double lots = CalculateLotSize(RiskPercent, stopLossPips);
// When volatility is high (large ATR): smaller lot size
// When volatility is low (small ATR): larger lot size
// This maintains consistent % risk regardless of market conditions
}Why ATR-based sizing works: During high-volatility events, ATR expands, stop distance increases, and lot size automatically decreases — reducing exposure exactly when markets are most dangerous. During low-volatility periods, stops tighten and lots increase, capturing more profit from cleaner moves.
Kelly Criterion: Optimal Growth Sizing
The Kelly Criterion calculates the theoretically optimal fraction of capital to risk per trade based on win rate and reward-to-risk ratio:
Kelly % = Win Rate - (1 - Win Rate) / (Average Win / Average Loss)Example:
- Win rate: 55%
- Average win: 40 pips
- Average loss: 20 pips
- Average Win/Loss ratio: 2.0
Kelly % = 0.55 - (0.45 / 2.0) = 0.55 - 0.225 = 0.325 = 32.5%Full Kelly (32.5% risk per trade) is extremely aggressive — a short losing streak would wipe most of the account. In practice, use fractional Kelly (typically 1/4 to 1/2 of full Kelly):
Fractional Kelly = Full Kelly × 0.25 = 32.5% × 0.25 = ~8%Even this may be aggressive for forex. Most professional systematic traders use 1–3% risk per trade. Kelly is most useful as a theoretical benchmark — if your Kelly fraction is very low (under 2%), the strategy's edge is weak.
Maximum Drawdown Limiter
An important addition to any position sizing system: a maximum drawdown limit that reduces lot sizes when the account is in drawdown:
input double MaxDrawdownPct = 15.0; // Pause if drawdown exceeds 15%
input double DrawdownReducePct = 10.0; // Reduce to 50% size at 10% drawdown
double GetEquityHighWaterMark()
{
static double hwm = 0;
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
if(equity > hwm) hwm = equity;
return hwm;
}
double GetCurrentDrawdown()
{
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double hwm = GetEquityHighWaterMark();
if(hwm == 0) return 0;
return ((hwm - equity) / hwm) * 100.0;
}
double ApplyDrawdownAdjustment(double baseLots)
{
double dd = GetCurrentDrawdown();
if(dd >= MaxDrawdownPct)
{
Print("Max drawdown exceeded — no new trades");
return 0; // Signal to skip this trade
}
if(dd >= DrawdownReducePct)
{
Print("Drawdown at ", dd, "% — reducing size by 50%");
return baseLots * 0.5;
}
return baseLots; // Normal sizing
}Using it:
double lots = CalculateLotSize(RiskPercent, stopLossPips);
lots = ApplyDrawdownAdjustment(lots);
if(lots <= 0) return; // Skip trade if drawdown limit exceededCommon Position Sizing Mistakes
Mistake 1: Fixed lot size regardless of account size
Running 0.10 lots on a $500 account is running 0.10 lots on a $5,000 account — the dollar risk is the same but the percentage risk is 10× higher. Always size relative to account equity.
Mistake 2: Increasing lot size after losses (martingale)
Doubling position size after each loss ("to recover faster") creates exponential risk. A sequence of 7 consecutive losses at 2× starting lot wipes the account completely. This is not position sizing — it's guaranteed eventual ruin.
Mistake 3: Not accounting for correlation when running multiple EAs
If two EAs each risk 2% on correlated pairs, the total correlated risk is approximately 4%. Ensure that total exposure across all EAs on correlated instruments stays within your target risk per trade.
Mistake 4: Using balance instead of equity
Balance doesn't include floating P&L from open positions. If you have $10,000 balance but are currently up $500 in open trades, equity is $10,500. Using equity for position sizing means position sizes increase with floating profits — both reasonable and correct.
Frequently Asked Questions
What percentage should I risk per trade on a new EA?
Start with 0.5% and increase only after 3+ months of live trading confirming the EA performs within expected parameters. Experienced traders with verified EAs typically use 1–2%. More than 3% per trade is generally aggressive.
How do I handle the fractional lot calculation at minimum account sizes?
At very small accounts ($100–$500), proper risk-based position sizing may require lot sizes below the broker's minimum (usually 0.01 lots). In this case, either: (1) use the minimum lot and accept that your risk per trade is above your target %, or (2) increase account size until proper sizing is possible.
Should position sizing change based on market conditions?
Yes — ATR-based sizing achieves this automatically. In high-volatility conditions, the ATR-scaled stop grows, which reduces lot size automatically. This is generally preferable to time-varying risk percentage adjustments, which require subjective judgment about when to adjust.
Can I backtest different position sizing rules in MT5?
Yes. The MT5 Strategy Tester uses the lot sizing logic in your EA. Test different risk percentages to see how they affect the equity curve and maximum drawdown. Walk-forward optimization can also optimize the risk percentage parameter alongside other inputs.
Position sizing controls risk but does not eliminate it. All automated forex trading involves the possibility of capital loss including the entire invested amount.
William Harris is the founding editor of Forex Robot Easy. He has spent over a decade building and reviewing algorithmic trading systems on MetaTrader 4 and 5, with a focus on machine learning, walk-forward validation, and execution mechanics.