MT5 Return Codes (RetCodes) Reference¶
What is RetCode?¶
RetCode (Return Code) is a status code that MT5 Terminal returns after executing a trading operation. The code indicates success or the reason for failure.
RetCodes only appear in trading methods because only trading operations go through the broker and can be rejected for various reasons (insufficient margin, invalid price, market closed, etc.).
RetCode Source¶
RetCodes are standard MQL5 codes defined in the official MetaQuotes documentation:
MQL5 Documentation: Trade Result Codes (ENUM_TRADE_RETCODE)
These codes are:
- Unified across all languages (C#, Python, Java, Node.js, Go, PHP)
- Unified with MT5 Terminal - returned directly from the trade server
- Defined in protobuf - enum
MqlErrorTradeCodein the API proto contract
Where is RetCode Used in the API?¶
RetCode is returned in three types of trading operations:
1. OrderSend (opening orders)¶
var result = await mt5Service.BuyMarketAsync("EURUSD", 0.01, stopLoss: 1.0800);
Console.WriteLine($"RetCode: {result.ReturnedCode}"); // uint32
Console.WriteLine($"String Code: {result.ReturnedStringCode}"); // "TRADE_RETCODE_DONE"
Console.WriteLine($"Description: {result.ReturnedCodeDescription}"); // "Request completed"
2. OrderModify (modifying SL/TP)¶
var result = await mt5Account.OrderModifyAsync(ticket: 12345, stopLoss: 1.0850);
if (result.Data.ReturnedCode == 10009) {
Console.WriteLine("Modification successful");
}
3. OrderClose (closing positions)¶
var result = await mt5Account.OrderCloseAsync(ticket: 12345);
if (result.Data.ReturnedCode != 10009) {
Console.WriteLine($"Close failed: {result.Data.ReturnedCodeDescription}");
}
Why RetCode Only in Trading Methods?¶
Information methods (getting prices, symbols, balance) DO NOT return RetCode because:
- They don't go through the broker
- They can't be "rejected" - either data exists or not (gRPC error)
- They work with local terminal data
Trading methods return RetCode because:
- Request is sent to broker via trade server
- Broker validates: margin, symbol rules, trading hours, limits
- Broker can reject request for dozens of reasons
- Each reason has its unique code
Complete RetCode List¶
✅ Success Codes¶
| Code | Enum | Description |
|---|---|---|
| 0 | TRADE_RETCODE_SUCCESS |
Successful execution (non-trading operation) |
| 10008 | TRADE_RETCODE_PLACED |
Pending order placed |
| 10009 | TRADE_RETCODE_DONE |
Request completed (market order opened) |
| 10010 | TRADE_RETCODE_DONE_PARTIAL |
Partial execution |
⚠️ Requote Codes¶
| Code | Enum | Description |
|---|---|---|
| 10004 | TRADE_RETCODE_REQUOTE |
Requote - price changed, need to request again |
| 10020 | TRADE_RETCODE_PRICE_CHANGED |
Price changed - similar to requote |
❌ Request Rejection Codes (Validation Errors)¶
| Code | Enum | Description | Reason |
|---|---|---|---|
| 10006 | TRADE_RETCODE_REJECT |
Request rejected | General rejection by broker |
| 10007 | TRADE_RETCODE_CANCEL |
Request canceled by trader | User canceled request manually |
| 10013 | TRADE_RETCODE_INVALID |
Invalid request | Incorrect parameters |
| 10014 | TRADE_RETCODE_INVALID_VOLUME |
Invalid volume | Volume < MinVolume or > MaxVolume |
| 10015 | TRADE_RETCODE_INVALID_PRICE |
Invalid price | Price doesn't comply with symbol rules |
| 10016 | TRADE_RETCODE_INVALID_STOPS |
Invalid stops | SL/TP too close to price or violates StopLevel |
| 10022 | TRADE_RETCODE_INVALID_EXPIRATION |
Invalid expiration date | Expiration time is incorrect |
| 10030 | TRADE_RETCODE_INVALID_FILL |
Invalid fill type | Fill policy not supported by symbol |
| 10035 | TRADE_RETCODE_INVALID_ORDER |
Invalid order type | Order type prohibited for symbol |
| 10038 | TRADE_RETCODE_INVALID_CLOSE_VOLUME |
Invalid close volume | Volume greater than current position |
🚫 Trading Restriction Codes¶
| Code | Enum | Description | Reason |
|---|---|---|---|
| 10017 | TRADE_RETCODE_TRADE_DISABLED |
Trading disabled | Trading disabled for symbol |
| 10018 | TRADE_RETCODE_MARKET_CLOSED |
Market closed | Outside trading hours |
| 10026 | TRADE_RETCODE_SERVER_DISABLES_AT |
Autotrading disabled by server | Broker disabled autotrading |
| 10027 | TRADE_RETCODE_CLIENT_DISABLES_AT |
Autotrading disabled by client | AutoTrading disabled in terminal |
| 10032 | TRADE_RETCODE_ONLY_REAL |
Operation for live accounts only | Action unavailable on demo |
| 10042 | TRADE_RETCODE_LONG_ONLY |
Long positions only | Short positions prohibited |
| 10043 | TRADE_RETCODE_SHORT_ONLY |
Short positions only | Long positions prohibited |
| 10044 | TRADE_RETCODE_CLOSE_ONLY |
Close only | Opening new positions prohibited |
| 10045 | TRADE_RETCODE_FIFO_CLOSE |
FIFO close only | FIFO rule mandatory (US regulation) |
| 10046 | TRADE_RETCODE_HEDGE_PROHIBITED |
Hedging prohibited | Cannot open opposite positions |
💰 Resource Limit Codes¶
| Code | Enum | Description | Reason |
|---|---|---|---|
| 10019 | TRADE_RETCODE_NO_MONEY |
Insufficient funds | Free Margin < Required Margin |
| 10033 | TRADE_RETCODE_LIMIT_ORDERS |
Pending orders limit reached | Maximum number of orders |
| 10034 | TRADE_RETCODE_LIMIT_VOLUME |
Volume limit reached | Total position volume exceeded |
| 10040 | TRADE_RETCODE_LIMIT_POSITIONS |
Open positions limit reached | Maximum number of positions |
🔧 Technical Issue Codes¶
| Code | Enum | Description | Reason |
|---|---|---|---|
| 10011 | TRADE_RETCODE_ERROR |
Request processing error | Internal server error |
| 10012 | TRADE_RETCODE_TIMEOUT |
Request timeout | Request not processed in time |
| 10021 | TRADE_RETCODE_PRICE_OFF |
No quotes | Symbol price unavailable |
| 10024 | TRADE_RETCODE_TOO_MANY_REQUESTS |
Too many requests | Rate limiting from broker |
| 10028 | TRADE_RETCODE_LOCKED |
Request locked for processing | Previous request still processing |
| 10029 | TRADE_RETCODE_FROZEN |
Order/position frozen | Temporary lock |
| 10031 | TRADE_RETCODE_CONNECTION |
No connection with trade server | Connection lost |
🔄 State Management Codes¶
| Code | Enum | Description | Reason |
|---|---|---|---|
| 10023 | TRADE_RETCODE_ORDER_CHANGED |
Order state changed | Order already modified/closed |
| 10025 | TRADE_RETCODE_NO_CHANGES |
No changes in request | New parameters match current ones |
| 10036 | TRADE_RETCODE_POSITION_CLOSED |
Position already closed | Attempt to close non-existent position |
| 10039 | TRADE_RETCODE_CLOSE_ORDER_EXIST |
Close order already exists | Duplicate close request |
| 10041 | TRADE_RETCODE_REJECT_CANCEL |
Pending order activation rejected | Pending order cannot be activated |
Usage Examples¶
Example 1: Checking Order Opening Success¶
using mt5_term_api;
using mt5_term_api;
var config = ConnectionHelper.BuildConfiguration();
var account = await ConnectionHelper.CreateAndConnectAccountAsync(config);
var service = new MT5Service(account);
// Open market order
var result = await service.BuyMarketAsync(
symbol: "EURUSD",
volume: 0.01,
stopLoss: 1.0800,
takeProfit: 1.0900
);
// Check RetCode
if (result.ReturnedCode == 10009) // TRADE_RETCODE_DONE
{
Console.WriteLine($"✅ Order opened successfully!");
Console.WriteLine($" Ticket: #{result.Order}");
Console.WriteLine($" Volume: {result.Volume} lots");
Console.WriteLine($" Price: {result.Price}");
}
else if (result.ReturnedCode == 10008) // TRADE_RETCODE_PLACED
{
Console.WriteLine($"✅ Pending order placed!");
Console.WriteLine($" Ticket: #{result.Order}");
}
else
{
Console.WriteLine($"❌ Order failed!");
Console.WriteLine($" RetCode: {result.ReturnedCode}");
Console.WriteLine($" String: {result.ReturnedStringCode}");
Console.WriteLine($" Description: {result.ReturnedCodeDescription}");
}
Example 2: Handling Common Errors¶
var result = await service.SellMarketAsync("GBPUSD", 0.5);
switch (result.ReturnedCode)
{
case 10009: // Success
Console.WriteLine($"Order #{result.Order} opened at {result.Price}");
break;
case 10019: // No money
Console.WriteLine("⚠️ Insufficient funds! Reduce volume or add margin.");
break;
case 10018: // Market closed
Console.WriteLine("⚠️ Market is closed. Try again during trading hours.");
break;
case 10016: // Invalid stops
Console.WriteLine("⚠️ Stop Loss or Take Profit too close to market price.");
Console.WriteLine(" Increase distance between entry and SL/TP.");
break;
case 10014: // Invalid volume
var limits = await service.GetVolumeLimitsAsync("GBPUSD");
Console.WriteLine($"⚠️ Volume {result.Volume} is invalid.");
Console.WriteLine($" Min: {limits.MinVolume}, Max: {limits.MaxVolume}, Step: {limits.VolumeStep}");
break;
case 10004: // Requote
case 10020: // Price changed
Console.WriteLine("⚠️ Price changed. Retrying with new price...");
// Retry request
var retry = await service.SellMarketAsync("GBPUSD", 0.5);
break;
default:
Console.WriteLine($"❌ Unexpected error: {result.ReturnedCodeDescription}");
break;
}
Example 3: Retry Logic for Requotes¶
public static async Task<OrderSendData> SendWithRetry(
MT5Service service,
string symbol,
double volume,
int maxRetries = 3)
{
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
var result = await service.BuyMarketAsync(symbol, volume);
// Success
if (result.ReturnedCode == 10009 || result.ReturnedCode == 10008)
{
return result;
}
// Requote - retry
if (result.ReturnedCode == 10004 || result.ReturnedCode == 10020)
{
Console.WriteLine($"Requote on attempt {attempt}, retrying...");
await Task.Delay(100); // Small delay
continue;
}
// Other error - abort
Console.WriteLine($"Failed: {result.ReturnedCodeDescription}");
return result;
}
throw new Exception($"Failed after {maxRetries} retries");
}
Example 4: Sugar API with Auto-Check¶
using mt5_term_api;
var service = new MT5Service(account);
// Sugar API: risk-based order
var result = await service.BuyMarketByRisk(
symbol: "EURUSD",
riskAmount: 50.0, // Risk $50
stopLossPoints: 20 // SL 20 points away
);
// Sugar API automatically calculates volume
Console.WriteLine($"Calculated volume: {result.Volume} lots");
if (result.ReturnedCode == 10009)
{
Console.WriteLine($"✅ Position opened with $50 risk at ticket #{result.Order}");
}
else
{
Console.WriteLine($"❌ {result.ReturnedCodeDescription}");
}
Example 5: Modify SL/TP with Validation¶
// Modify SL/TP of existing position
var modifyResult = await mt5Account.OrderModifyAsync(
ticket: 123456,
stopLoss: 1.0850,
takeProfit: 1.0950
);
if (modifyResult.Data.ReturnedCode == 10009)
{
Console.WriteLine("✅ SL/TP updated successfully");
}
else if (modifyResult.Data.ReturnedCode == 10025) // No changes
{
Console.WriteLine("⚠️ New SL/TP values are same as current - no action taken");
}
else if (modifyResult.Data.ReturnedCode == 10036) // Position closed
{
Console.WriteLine("⚠️ Position already closed by SL/TP or manually");
}
else
{
Console.WriteLine($"❌ Modify failed: {modifyResult.Data.ReturnedCodeDescription}");
}
C# Enum¶
RetCodes are defined in enum MqlErrorTradeCode:
using Mt5TermApi;
// Using enum instead of magic numbers
if (result.ReturnedCode == (uint32)MqlErrorTradeCode.TradeRetcodeDone)
{
Console.WriteLine("Success!");
}
// Or simply use numeric constants
if (result.ReturnedCode == 10009)
{
Console.WriteLine("Success!");
}
Best Practices¶
- Always check RetCode after trading operations
- 10009 = success for market orders, 10008 = success for pending orders
- Requotes (10004, 10020) - retry the request
- 10019 (No Money) - check Free Margin before order
- 10016 (Invalid Stops) - increase distance to SL/TP (check StopLevel)
- 10018 (Market Closed) - check symbol trading hours
- Use
returned_code_descriptionto display user-friendly messages