TradingTeaching Press · Dubai, UAE Trading is high-risk. Check local laws, your residency rules and your finances. Risk warning
🤖 Trading Automation

MQL5 Risk Management: Protect Your Capital with Code

Implement professional risk management in your Expert Advisors. Calculate position sizes, set proper stops, and protect your trading capital.

6 min read TradingTeaching Team

Risk management separates profitable traders from those who blow accounts. This guide shows you how to implement proper risk management in your Expert Advisors.

Core Risk Management Principles

The 1% Rule

Never risk more than 1% of the account per trade:

  • Survives losing streaks
  • Allows recovery from drawdowns
  • Enables consistent position sizing

Risk Components

Every trade has:

  • Entry price: Where you enter
  • Stop loss: Where you exit if wrong
  • Position size: How much you trade
  • Risk amount: Entry minus stop × position size

Calculating Position Size

The Formula

Lot Size = Risk Amount / (Stop Loss Pips × Pip Value)

Where:

  • Risk Amount = Account Balance × Risk Percentage
  • Stop Loss Pips = Entry - Stop Loss (in pips)
  • Pip Value = Value of 1 pip for 1 lot

MQL5 Implementation

`mql5 double CalculateLotSize(double riskPercent, double stopLossPips) { // Get account information double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmount = accountBalance * riskPercent / 100;

// Get symbol information string symbol = _Symbol; double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);

// Calculate pip value for 1 lot double pipValue = (tickValue / tickSize) _Point 10;

// Calculate lot size double lots = riskAmount / (stopLossPips * pipValue);

// Round to lot step lots = MathFloor(lots / lotStep) * lotStep;

// Apply limits lots = MathMax(lots, minLot); lots = MathMin(lots, maxLot);

return NormalizeDouble(lots, 2); } `

Usage Example

void OnTick()
{
   double stopLossPips = 50;
   double riskPercent = 1.0;  // 1% risk

   double lots = CalculateLotSize(riskPercent, stopLossPips);
   Print("Calculated lot size: ", lots);

   // Use in trade
   PlaceBuyOrder(lots, sl, tp);
}

Dynamic Stop Loss Calculation

ATR-Based Stops

Use Average True Range for volatility-adjusted stops:

int atrHandle;
double atrBuffer[];

int OnInit()
{
   atrHandle = iATR(_Symbol, PERIOD_CURRENT, 14);
   ArraySetAsSeries(atrBuffer, true);
   return(INIT_SUCCEEDED);
}

double CalculateATRStop(double multiplier)
{
   if(CopyBuffer(atrHandle, 0, 0, 1, atrBuffer) < 1)
      return 0;

   double atr = atrBuffer[0];
   double stopDistance = atr * multiplier;

   return stopDistance;
}

// Usage
double stopDistance = CalculateATRStop(2.0);  // 2x ATR
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double stopLoss = bid - stopDistance;  // For buy trade

Support/Resistance Stops

`mql5 double FindRecentLow(int bars) { double low = DBL_MAX;

for(int i = 1; i <= bars; i++) { double barLow = iLow(_Symbol, PERIOD_CURRENT, i); if(barLow < low) low = barLow; }

return low; }

double FindRecentHigh(int bars) { double high = 0;

for(int i = 1; i <= bars; i++) { double barHigh = iHigh(_Symbol, PERIOD_CURRENT, i); if(barHigh > high) high = barHigh; }

return high; }

// Usage for buy trade double recentLow = FindRecentLow(20); double buffer = 10 * _Point; // Add buffer double stopLoss = recentLow - buffer; `

Maximum Drawdown Protection

Daily Loss Limit

input double MaxDailyLossPercent = 3.0;  // Maximum daily loss %

double dailyStartBalance;
datetime lastResetDay;

int OnInit()
{
   dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   lastResetDay = TimeCurrent();
   return(INIT_SUCCEEDED);
}

bool CheckDailyLossLimit()
{
   // Reset at new day
   MqlDateTime currentTime;
   TimeToStruct(TimeCurrent(), currentTime);

   MqlDateTime lastReset;
   TimeToStruct(lastResetDay, lastReset);

   if(currentTime.day != lastReset.day)
   {
      dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE);
      lastResetDay = TimeCurrent();
   }

   // Check current loss
   double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   double dailyLoss = dailyStartBalance - currentBalance;
   double lossPercent = (dailyLoss / dailyStartBalance) * 100;

   if(lossPercent >= MaxDailyLossPercent)
   {
      Print("Daily loss limit reached: ", lossPercent, "%");
      return false;  // Don't trade
   }

   return true;  // OK to trade
}

void OnTick()
{
   if(!CheckDailyLossLimit())
   {
      // Close all positions and stop trading
      CloseAllPositions();
      return;
   }

   // Normal trading logic...
}

Maximum Drawdown Stop

input double MaxDrawdownPercent = 20.0;

double peakBalance;

int OnInit()
{
   peakBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   return(INIT_SUCCEEDED);
}

bool CheckDrawdownLimit()
{
   double currentBalance = AccountInfoDouble(ACCOUNT_BALANCE);

   // Update peak
   if(currentBalance > peakBalance)
      peakBalance = currentBalance;

   // Calculate drawdown
   double drawdown = peakBalance - currentBalance;
   double drawdownPercent = (drawdown / peakBalance) * 100;

   if(drawdownPercent >= MaxDrawdownPercent)
   {
      Print("Maximum drawdown reached: ", drawdownPercent, "%");
      Alert("EA STOPPED: Maximum drawdown exceeded!");
      ExpertRemove();  // Stop EA
      return false;
   }

   return true;
}

Position Limits

Maximum Open Positions

input int MaxOpenPositions = 3;

bool CanOpenNewPosition()
{
   int count = 0;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0)
      {
         if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)
            count++;
      }
   }

   return (count < MaxOpenPositions);
}

Maximum Lots Per Symbol

input double MaxLotsPerSymbol = 1.0;

double GetCurrentExposure()
{
   double totalLots = 0;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0)
      {
         if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
            PositionGetInteger(POSITION_MAGIC) == MagicNumber)
         {
            totalLots += PositionGetDouble(POSITION_VOLUME);
         }
      }
   }

   return totalLots;
}

bool CanAddPosition(double newLots)
{
   double currentExposure = GetCurrentExposure();
   return ((currentExposure + newLots) <= MaxLotsPerSymbol);
}

Complete Risk Manager Class

`mql5 class CRiskManager { private: double m_riskPercent; double m_maxDailyLoss; double m_maxDrawdown; int m_maxPositions; double m_dailyStartBalance; double m_peakBalance; int m_magicNumber;

public: CRiskManager(double risk, double dailyLoss, double drawdown, int maxPos, int magic) { m_riskPercent = risk; m_maxDailyLoss = dailyLoss; m_maxDrawdown = drawdown; m_maxPositions = maxPos; m_magicNumber = magic; m_dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE); m_peakBalance = m_dailyStartBalance; }

double CalculateLots(double stopLossPips) { double balance = AccountInfoDouble(ACCOUNT_BALANCE); double riskAmount = balance * m_riskPercent / 100; double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); double pipValue = (tickValue / tickSize) _Point 10;

double lots = riskAmount / (stopLossPips * pipValue); double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

lots = MathFloor(lots / lotStep) * lotStep; lots = MathMax(lots, minLot);

return NormalizeDouble(lots, 2); }

bool CanTrade() { if(!CheckDailyLoss()) return false; if(!CheckDrawdown()) return false; if(!CheckPositionCount()) return false; return true; }

bool CheckDailyLoss() { double balance = AccountInfoDouble(ACCOUNT_BALANCE); double loss = m_dailyStartBalance - balance; double lossPercent = (loss / m_dailyStartBalance) * 100; return (lossPercent < m_maxDailyLoss); }

bool CheckDrawdown() { double balance = AccountInfoDouble(ACCOUNT_BALANCE); if(balance > m_peakBalance) m_peakBalance = balance;

double drawdown = m_peakBalance - balance; double ddPercent = (drawdown / m_peakBalance) * 100; return (ddPercent < m_maxDrawdown); }

bool CheckPositionCount() { int count = 0; for(int i = PositionsTotal() - 1; i >= 0; i--) { if(PositionGetTicket(i) > 0) if(PositionGetInteger(POSITION_MAGIC) == m_magicNumber) count++; } return (count < m_maxPositions); }

void ResetDaily() { m_dailyStartBalance = AccountInfoDouble(ACCOUNT_BALANCE); } };

// Usage CRiskManager* riskMgr;

int OnInit() { riskMgr = new CRiskManager(1.0, 3.0, 20.0, 3, MagicNumber); return(INIT_SUCCEEDED); }

void OnDeinit(const int reason) { delete riskMgr; }

void OnTick() { if(!riskMgr.CanTrade()) { Print("Risk limits reached - no trading"); return; }

double lots = riskMgr.CalculateLots(50); // 50 pip stop // ... trading logic } ``

Key Takeaways

  • Never risk more than 1% per trade
  • Calculate position size based on stop loss distance
  • Use ATR for volatility-adjusted stops
  • Implement daily loss limits
  • Set maximum drawdown protection
  • Limit number of open positions
  • Use a risk manager class for clean code
  • Always test risk management thoroughly

What's Next?

Learn how to backtest your Expert Advisors to validate performance before live trading.


This article is for educational purposes only and does not constitute financial advice.

Risk warning. This is education only, not financial, investment, tax or legal advice, and not a recommendation to buy or sell anything. Trading forex, CFDs, stocks, commodities, futures, options and crypto is high-risk; with leverage you can lose more than you deposit, and most retail traders lose money. Before you trade or invest in any form, check the local laws where you are and the rules of your country of residence, and consider your own financial situation; if in doubt, ask a licensed adviser. Past and tested results, and all examples, are for illustration only and do not guarantee future results.

Get the strategy right before you automate it

An automated system is only as good as the rules behind it. The book series covers building and testing those rules before a line of code is written.

Explore the books