Edgoro
Trade server return code 10014 · MQL5

MT5 error 10014 Invalid volume: causes and fix

Fix MetaTrader 5 retcode 10014 (invalid volume): round lots to SYMBOL_VOLUME_STEP and keep them between the symbol's minimum and maximum. MQL5 code.

Trade server return code · MqlTradeResult.retcode
10014 TRADE_RETCODE_INVALID_VOLUME
“Invalid volume in the request”
Experts tab · line printed by CTrade (example values)
CTrade::OrderSend: market buy 0.14 EURUSD [invalid volume]

What it means

The volume in the request isn't one the symbol accepts. Every symbol has a minimum volume, a maximum per order and a step, and the lot size must fit all three. The order isn't sent to the market.

Usual causes

  • Not a multiple of the step. A lot size from a risk formula, such as 0.137, on a symbol whose SYMBOL_VOLUME_STEP is 0.01.
  • Below the minimum. A small account or a wide stop gives 0.004 lots where SYMBOL_VOLUME_MIN is 0.01.
  • Above the maximum. One order larger than SYMBOL_VOLUME_MAX. Split it, or trade less.
  • Floating-point leftovers. 0.1 * 3 isn't exactly 0.3 in a double. Round the result with NormalizeDouble() to the step's number of decimals.
  • Zero or negative. CTrade refuses a volume of 0 or less itself and sets the retcode to 10014 without sending anything.

The minimum, maximum and step are set per symbol by the broker; they aren't always 0.01, 100 and 0.01.

How to detect it

  • result.retcode (or trade.ResultRetcode()) is 10014.
  • The CTrade line in the Experts tab prints the volume with two decimals, so 0.137 lots shows as 0.14. Print the volume yourself with DoubleToString(volume, 8) to see the real value.
  • Compare it with SYMBOL_VOLUME_MIN, SYMBOL_VOLUME_MAX and SYMBOL_VOLUME_STEP from SymbolInfoDouble().

Broken code

This EA compiles. Unless the equity happens to give a round number, the volume isn't on the symbol's step and the order fails with 10014.

MQL5
#include <Trade/Trade.mqh>

input double InpLotsPer10k = 0.1; // Lots per 10,000 of equity

CTrade trade;

void OnTick()
  {
   if(PositionSelect(_Symbol))
      return;
   // 13,700 of equity gives 0.137 lots: not a multiple of a 0.01 step
   double lots = AccountInfoDouble(ACCOUNT_EQUITY) / 10000.0 * InpLotsPer10k;
   trade.Buy(lots);
  }

Fixed code

The same program with the check that prevents the error. It compiles in MetaEditor with 0 errors and 0 warnings.

MQL5
#include <Trade/Trade.mqh>

input double InpLotsPer10k = 0.1; // Lots per 10,000 of equity

CTrade trade;

// Rounds a volume DOWN to the symbol's step; 0 means "too small to trade"
double NormalizeVolume(const double volume)
  {
   double minVol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxVol = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double step   = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   if(step <= 0.0)
      return 0.0;
   // The epsilon keeps 0.3 / 0.1 = 2.9999... from losing a whole step
   double v = MathFloor(volume / step + 1e-9) * step;
   int digits = (int)MathMax(0.0, MathCeil(-MathLog10(step) - 1e-9));
   v = NormalizeDouble(v, digits);
   if(v < minVol)
      return 0.0;
   return MathMin(v, maxVol);
  }

void OnTick()
  {
   if(PositionSelect(_Symbol))
      return;
   double raw  = AccountInfoDouble(ACCOUNT_EQUITY) / 10000.0 * InpLotsPer10k;
   double lots = NormalizeVolume(raw);
   if(lots <= 0.0)
     {
      static bool warned = false;
      if(!warned)
         PrintFormat("Skipped: %s lots is below this symbol's minimum volume", DoubleToString(raw, 8));
      warned = true;
      return;
     }
   if(!trade.Buy(lots))
      PrintFormat("Buy %s lots failed: retcode %u (%s)", DoubleToString(lots, 8), trade.ResultRetcode(), trade.ResultRetcodeDescription());
  }

Why the fix works

NormalizeVolume() rounds down to a whole number of steps, removes floating-point leftovers with NormalizeDouble() and keeps the result between the symbol's minimum and maximum. Rounding down keeps the risk at or below what you asked for.

Returning 0 under the minimum is deliberate: rounding up to the minimum lot would risk more than the formula allows, so the EA skips the trade and says why.

Other volume limits

SYMBOL_VOLUME_LIMIT caps the total volume of open positions and pending orders in one direction on a symbol. Going over it is a different return code, 10034 (TRADE_RETCODE_LIMIT_VOLUME), not 10014. Margin is a separate check too: a valid volume can still fail with 10019, not enough money.

Questions

How do I round the lot size in MQL5?

Read SYMBOL_VOLUME_STEP, divide the volume by it, round down with MathFloor, multiply back and clean the result with NormalizeDouble to the step's decimals. Then keep it between SYMBOL_VOLUME_MIN and SYMBOL_VOLUME_MAX.

Why does 0.01 lots fail on some symbols?

Because the minimum volume and the step are set per symbol by the broker. Some symbols have a minimum or a step larger than 0.01. Read them with SymbolInfoDouble() instead of assuming them.

Is MT5 error 10014 the same as MT4 error 131?

Yes. MQL4's error 131 (ERR_INVALID_TRADE_VOLUME) is trade server return code 10014 in MQL5.

The programs on this page are minimal examples written to show the error and its fix, not trading systems. Some of them send orders when they run: try them on a demo account. Trading involves substantial risk of loss and is not suitable for every investor. Edgoro is a software tool, not a broker or financial adviser: nothing it produces is investment advice, and past or backtested performance does not guarantee future results.

Working code that avoids it

All MQL5 examples

Rather not write the error handling yourself?

Edgoro's MT5 EA generator writes complete MQL5 Expert Advisors from plain English and compiles each one in MetaEditor before you get it. A clean build proves the code compiles, not that a strategy works: test it on a demo account.