Quick Answer
Trade return code 10019 (TRADE_RETCODE_NO_MONEY) means that the free margin of the account is not enough to open the position you asked for. The server rejects the order because the margin that the new position needs is larger than the money that is free at that moment. The volume itself can be perfectly valid. This is the difference from error 10014 (invalid volume), where the lot size breaks the rules of the symbol.
You can check it before you send the order. OrderCalcMargin returns the margin that a trade would need, and ACCOUNT_MARGIN_FREE is the money that is free now. If the first number is larger than the second, do not send the order: reduce the lot, wait, or skip the trade. A good EA does this check on every order, and it also keeps a safety buffer so that one new position does not push the account close to a margin call.
From the author: I build and convert Expert Advisors, and 10019 usually appears in two situations: a backtest or demo account with a small balance where a risk formula asks for a bigger lot than the account can hold, and a live account where other positions already use most of the margin. This guide shows how to read the numbers and how to protect the EA.
Key Facts
| What you see | Usual cause | Fix |
|---|---|---|
| 10019 on the first trade of a small account | The lot needs more margin than the balance | Reduce the lot, or check the margin first |
| 10019 when several positions are open | Open positions use the free margin | Check ACCOUNT_MARGIN_FREE before each order |
| 10019 on a symbol with high margin (index, gold, crypto) | The margin per lot is much larger than on forex | Use OrderCalcMargin for that symbol |
| Works on a demo account, fails on live | Different balance or different leverage | Compare balance and leverage |
| Works in the tester, fails live | Tester deposit is larger than the live balance | Test with the live deposit |
| 10014 instead | The volume breaks min, max or step | Fix the volume first |
What the Error Looks Like
With CTrade, a rejected order makes Buy or Sell return false, and the code and the text are in the result:
if(!trade.Buy(lots, _Symbol, 0.0, sl, tp, "bot"))
{
PrintFormat("Order failed. Retcode %u: %s",
trade.ResultRetcode(), trade.ResultRetcodeDescription());
}
The full list of return codes is in MQL5 trade return codes. The related errors for the volume and for the stops are MQL5 invalid stops error 10016 and the volume rules explained below.
The Words: Balance, Equity, Margin, Free Margin
These four numbers are different, and mixing them is the usual source of confusion:
| Term | Meaning | Property |
|---|---|---|
| Balance | Money in the account without open trades | ACCOUNT_BALANCE |
| Equity | Balance plus the floating profit or loss | ACCOUNT_EQUITY |
| Margin | Money that open positions have locked | ACCOUNT_MARGIN |
| Free margin | Equity minus the margin in use | ACCOUNT_MARGIN_FREE |
A new position needs margin. If the free margin is smaller than that margin, the server answers with 10019. A floating loss on other positions lowers the equity and therefore the free margin, so an EA can have enough money at 9:00 and not enough at 9:30, without any change of the balance.
The margin level (ACCOUNT_MARGIN_LEVEL) is equity divided by margin, in percent. Brokers use it for their margin call and stop-out rules, and those levels differ between brokers. An EA that keeps a high margin level has more room before the broker steps in.
How Much Margin a Trade Needs
The margin depends on the symbol, the volume, the price, the leverage of the account and the margin settings of the broker. Do not calculate it by hand. Ask the platform:
bool GetMarginForTrade(const string symbol, ENUM_ORDER_TYPE type, double volume, double &margin)
{
double price = (type == ORDER_TYPE_BUY)
? SymbolInfoDouble(symbol, SYMBOL_ASK)
: SymbolInfoDouble(symbol, SYMBOL_BID);
if(price <= 0.0 || volume <= 0.0)
return false;
margin = 0.0;
return OrderCalcMargin(type, symbol, volume, price, margin);
}
OrderCalcMargin returns true when the calculation worked, and the margin comes back through the last argument. It is calculated in the currency of the account. Use the ask price for a buy and the bid price for a sell.
Check Before You Send the Order
// Returns true when the account has enough free margin, with a safety buffer.
// bufferPercent = 20 means: the trade may use at most 80% of the free margin.
bool HasEnoughMargin(const string symbol, ENUM_ORDER_TYPE type, double volume, double bufferPercent = 20.0)
{
double needed = 0.0;
if(!GetMarginForTrade(symbol, type, volume, needed) || needed <= 0.0)
return false;
double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
double allowed = freeMargin * (1.0 - bufferPercent / 100.0);
return (needed <= allowed);
}
The buffer is a choice of the EA, not a rule of the broker. It keeps some room for a price move against the position and for the spread. Pick a value that fits your own risk rules, and test it on a demo account.
Reduce the Lot Instead of Skipping
When the margin check fails, you can try a smaller volume. The loop below steps down by the volume step until the margin fits, or gives up when it reaches the minimum:
double FitVolumeToMargin(const string symbol, ENUM_ORDER_TYPE type, double wanted)
{
double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
double stepLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);
if(minLot <= 0.0 || stepLot <= 0.0)
return 0.0;
double volume = wanted;
int guard = 0;
while(volume >= minLot && guard < 1000)
{
if(HasEnoughMargin(symbol, type, volume))
return volume;
volume -= stepLot;
guard++;
}
return 0.0; // nothing fits: do not trade
}
The loop assumes that wanted is already a valid volume (a multiple of the step, between the minimum and the maximum). Smaller volume also means a smaller stop-loss risk only if the stop distance stays the same, so decide whether your rules allow a smaller position than the formula calculated. Many risk rules say that a trade that does not fit should be skipped, and not shrunk.
Using It With CTrade
#include <Trade\Trade.mqh>
CTrade trade;
void TryBuy(double wantedLots, double sl, double tp)
{
double lots = FitVolumeToMargin(_Symbol, ORDER_TYPE_BUY, wantedLots);
if(lots <= 0.0)
{
Print("Skipping the trade: not enough free margin for the minimum volume");
return;
}
if(!trade.Buy(lots, _Symbol, 0.0, sl, tp, "bot"))
PrintFormat("Buy failed. Retcode %u: %s",
trade.ResultRetcode(), trade.ResultRetcodeDescription());
}
The stops in the call must also follow the stops level of the symbol: MQL5 invalid stops error 10016. The lot sizing rules behind wantedLots are in MQL5 lot size calculation.
Leverage and Why a Symbol Can Need More Margin
Leverage lowers the margin per trade: with a higher leverage, the same volume locks less money. The leverage of the account is in ACCOUNT_LEVERAGE, and brokers can set a different leverage for some symbols or for large positions, so the margin of a symbol can be higher than the account leverage suggests. That is why OrderCalcMargin is better than a formula of your own.
A demo account and a live account of the same broker can have different leverage. If an EA works on the demo and gets 10019 on the live account, compare the leverage and the balance first.
A Full EA That Only Prints
This EA does not trade. It prints the account numbers and the margin that three volumes would need on the current symbol, so you can see what your account can hold before any trade logic is connected:
input double Volume1 = 0.01;
input double Volume2 = 0.10;
input double Volume3 = 1.00;
int OnInit()
{
PrintFormat("Balance %.2f, equity %.2f, margin %.2f, free margin %.2f, leverage 1:%d",
AccountInfoDouble(ACCOUNT_BALANCE),
AccountInfoDouble(ACCOUNT_EQUITY),
AccountInfoDouble(ACCOUNT_MARGIN),
AccountInfoDouble(ACCOUNT_MARGIN_FREE),
(int)AccountInfoInteger(ACCOUNT_LEVERAGE));
double volumes[3];
volumes[0] = Volume1;
volumes[1] = Volume2;
volumes[2] = Volume3;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
for(int i = 0; i < 3; i++)
{
double margin = 0.0;
if(ask > 0.0 && OrderCalcMargin(ORDER_TYPE_BUY, _Symbol, volumes[i], ask, margin))
PrintFormat("%s buy %.2f lots needs margin %.2f (free margin %.2f)",
_Symbol, volumes[i], margin, AccountInfoDouble(ACCOUNT_MARGIN_FREE));
else
PrintFormat("%s buy %.2f lots: margin could not be calculated", _Symbol, volumes[i]);
}
return INIT_SUCCEEDED;
}
void OnTick()
{
}
Run it on the symbols you trade. The margin of an index or gold can be many times larger than the margin of a forex pair for the same volume.
Common Causes Checklist
- The lot is too big for the balance. Check the margin with
OrderCalcMargin. - Other positions use the margin. Check
ACCOUNT_MARGIN_FREE, notACCOUNT_BALANCE. - A floating loss lowered the equity.
- A symbol with a high margin (index, metal, crypto).
- Different leverage on demo and live accounts.
- A tester deposit that is larger than the live balance.
- A grid or martingale EA that doubles the lot until the margin ends.
- The EA ignores the return value and keeps sending orders that fail.
Common Mistakes
- Comparing the margin with the balance instead of the free margin.
- Using the full free margin, with no buffer.
- Calculating the margin by hand with a fixed number per lot.
- Testing with a deposit that is much larger than the real account.
- Retrying the same order in a loop after 10019.
- Shrinking the lot silently, so that the risk rule is broken without a message.
FAQ
Related Guides
- MQL5 trade return codes: what each return code means and how to react.
- MQL5 invalid stops error 10016: the matching error for stop loss and take profit.
- MQL5 unsupported filling mode error: another order rejection with a clear fix.
- MQL5 lot size calculation: risk-based lots, step by step.
- MQL5 daily loss limit: stop trading when the day goes wrong.
- MT5 hedging vs netting: how the account type changes positions and margin.
- What to check in a trading bot before going live: a pre-live checklist for stops, lot size, spread and trade results.
- MQL5 invalid volume error 10014: the volume breaks min, max or step.
Fix Compile Errors Without Guessing
If an Expert Advisor does not compile, or you want a second look at its lot size and risk logic, paste the code into the CodeFlowOS Error Fixer. It suggests a minimal fix, explains each error and shows what changed. A fix uses 1 credit, with up to 3 attempts included, and the compiler check is optional. Outputs are not guaranteed, and code that compiles can still have wrong trading logic, so always review the result. The Code Review is free during the early-bird period and checks an EA for common mistakes such as a fixed lot size or a missing stop loss. CodeFlowOS also converts strategies between Pine Script, MQL5 and cTrader C#: try the converter page.
This article is educational. It does not describe trading performance and is not financial advice. Always compile and test code in MetaEditor and the Strategy Tester before using it on a live account.