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_STEPis 0.01. - Below the minimum. A small account or a wide stop gives 0.004 lots where
SYMBOL_VOLUME_MINis 0.01. - Above the maximum. One order larger than
SYMBOL_VOLUME_MAX. Split it, or trade less. - Floating-point leftovers.
0.1 * 3isn't exactly 0.3 in adouble. Round the result withNormalizeDouble()to the step's number of decimals. - Zero or negative.
CTraderefuses 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(ortrade.ResultRetcode()) is10014.- 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 withDoubleToString(volume, 8)to see the real value. - Compare it with
SYMBOL_VOLUME_MIN,SYMBOL_VOLUME_MAXandSYMBOL_VOLUME_STEPfromSymbolInfoDouble().
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.
#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.
#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.