Why Understanding Compilation Errors Matters
Compilation errors are inevitable in EA development. Every programmer, from beginner to expert, encounters them. The key difference between successful EA developers and struggling ones is the ability to quickly identify, understand, and fix these errors. Mastering error resolution dramatically reduces development time and frustration.
Complete MQL4 Error Reference Table
| Error Code | Error Message | Common Cause | Solution |
|------------|---------------|--------------|----------|
| 1 | No result returned | Order function failed | Check error after every trade function |
| 2 | Common error | General failure | Check all parameters and conditions |
| 17 | Cannot convert type | Type mismatch in assignment | Use explicit type conversion |
| 30 | Semicolon expected | Missing semicolon | Add ; at end of statement |
| 31 | Unexpected token | Extra or missing braces | Check {} matching |
| 33 | Condition expected | Invalid if/while condition | Add parentheses around condition |
| 130 | Invalid stops | Stop loss/take profit too close | Check MODE_STOPLEVEL distance |
| 134 | Not enough money | Insufficient margin | Reduce lot size or check free margin |
| 138 | Requote | Price changed during execution | Increase slippage or refresh rates |
| 146 | Trading context busy | Multiple OrderSend calls | Add Sleep() or use semaphore |
| 147 | Expiration denied | Broker doesn't support expiration | Set expiration to 0 |
| 148 | Too many orders | Order limit reached | Close some orders first |
| 4051 | Wrong parameter count | Incorrect number of arguments | Check function definition parameters |
1. Compilation Errors - Fixing Code That Won't Build
Error 30: ';' - Semicolon Expected
This error occurs when the compiler expects a semicolon but doesn't find one.
```mql4
// WRONG - Missing semicolon
int x = 10
double y = 20;
// WRONG - Missing semicolon before closing brace
if(condition) {
Print("Hello")
}
// CORRECT
int x = 10;
double y = 20;
// CORRECT
if(condition) {
Print("Hello");
}
```
Error 31: '}' - Unexpected Token
This error indicates mismatched or missing braces.
```mql4
// WRONG - Missing closing brace
void OnTick() {
if(condition) {
Print("Inside if");
}
// Missing } for OnTick
// WRONG - Extra brace
void OnTick() {
if(condition) {
Print("Inside if");
}}
// Extra closing brace
// CORRECT - Proper brace matching
void OnTick() {
if(condition) {
Print("Inside if");
}
}
// Debugging tip: Count your braces
// Each { should have a matching }
```
Error 33: 'if' - Condition Expected
The if statement requires parentheses around its condition.
```mql4
// WRONG - Missing parentheses
if x > 10 {
Print("x is greater than 10");
}
// WRONG - Using assignment instead of comparison
if(x = 10) { // This assigns 10 to x, doesn't compare
Print("x equals 10");
}
// CORRECT
if(x > 10) {
Print("x is greater than 10");
}
// CORRECT
if(x == 10) {
Print("x equals 10");
}
```
Error 17: 'return' - Cannot Convert Type
The function return type doesn't match the value being returned.
```mql4
// WRONG - Returning double from int function
int CalculateValue() {
double result = 10.5;
return result; // Error: cannot convert double to int
}
// WRONG - Returning string from double function
double GetPrice() {
return "1.09250"; // Error: cannot convert string to double
}
// CORRECT - Use explicit casting
int CalculateValue() {
double result = 10.5;
return (int)result; // Returns 10
}
// CORRECT - Match return type
double GetPrice() {
return StringToDouble("1.09250");
}
// CORRECT - Use proper return type
int CalculateValue() {
int result = 10;
return result;
}
```
Error 1: 'variable' - Undeclared Identifier
Using a variable before declaring it.
```mql4
// WRONG - Variable used before declaration
void OnTick() {
myVariable = 10; // Error: undeclared identifier
int myVariable;
}
// WRONG - Scope issue
void Function1() {
int localVar = 10;
}
void Function2() {
localVar = 20; // Error: undeclared - localVar not in scope
}
// CORRECT - Declare before use
void OnTick() {
int myVariable;
myVariable = 10;
}
// CORRECT - Use global variable
int globalVar = 10;
void Function2() {
globalVar = 20; // OK - global variable accessible
}
// CORRECT - Pass as parameter
void Function1() {
int localVar = 10;
Function2(localVar);
}
void Function2(int param) {
param = 20;
}
```
Error 4051: 'iMA' - Wrong Parameter Count
Incorrect number of arguments passed to a function.
```mql4
// WRONG - iMA requires 7 parameters
double ma = iMA(NULL, 0, 14);
// WRONG - Too many parameters
double ma = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE, 1, 0, 0);
// CORRECT - iMA with 7 parameters
double ma = iMA(NULL, 0, 14, 0, MODE_SMA, PRICE_CLOSE, 1);
// CORRECT syntax for iMA
double ma = iMA(
Symbol(), // 1: symbol
Period(), // 2: timeframe
14, // 3: period
0, // 4: shift
MODE_SMA, // 5: method
PRICE_CLOSE, // 6: applied price
1 // 7: index shift
);
```
2. Runtime Errors - Fixing EA That Won't Trade
Error 130: Invalid Stops
Stop loss or take profit is too close to current price.
```mql4
// SOLUTION: Check and adjust stop distance
int GetValidStopLoss(int orderType, int requestedPoints) {
int minDistance = (int)MarketInfo(Symbol(), MODE_STOPLEVEL);
int actualPoints = MathMax(requestedPoints, minDistance);
double price = (orderType == OP_BUY) ? Ask : Bid;
double stopLoss;
if(orderType == OP_BUY) {
stopLoss = NormalizeDouble(price - actualPoints * Point(), Digits);
} else {
stopLoss = NormalizeDouble(price + actualPoints * Point(), Digits);
}
Print("Stop loss adjusted from ", requestedPoints, " to ", actualPoints, " points");
return stopLoss;
}
// Safe OrderSend with error 130 handling
int SafeOrderSend(int orderType, double lotSize, int stopPoints, int tpPoints) {
RefreshRates();
int minStop = (int)MarketInfo(Symbol(), MODE_STOPLEVEL);
int stopPointsAdjusted = MathMax(stopPoints, minStop);
int tpPointsAdjusted = MathMax(tpPoints, minStop);
double price = (orderType == OP_BUY) ? Ask : Bid;
double sl = 0, tp = 0;
if(stopPointsAdjusted > 0) {
if(orderType == OP_BUY) {
sl = NormalizeDouble(price - stopPointsAdjusted * Point(), Digits);
} else {
sl = NormalizeDouble(price + stopPointsAdjusted * Point(), Digits);
}
}
if(tpPointsAdjusted > 0) {
if(orderType == OP_BUY) {
tp = NormalizeDouble(price + tpPointsAdjusted * Point(), Digits);
} else {
tp = NormalizeDouble(price - tpPointsAdjusted * Point(), Digits);
}
}
int ticket = OrderSend(Symbol(), orderType, lotSize, price, 30, sl, tp, "Safe EA", magicNumber, 0, clrNONE);
if(ticket < 0 && GetLastError() == 130) {
Print("Error 130 occurred. Trying without stops.");
ticket = OrderSend(Symbol(), orderType, lotSize, price, 30, 0, 0, "Safe EA No SL", magicNumber, 0, clrNONE);
}
return ticket;
}
```
Error 134: Not Enough Money
Insufficient free margin to open position.
```mql4
// SOLUTION: Calculate maximum lot based on available margin
double GetMaxAffordableLot(double requestedLot) {
double freeMargin = AccountFreeMargin();
double marginPerLot = MarketInfo(Symbol(), MODE_MARGINREQUIRED);
if(marginPerLot <= 0) return requestedLot;
double maxLotByMargin = freeMargin / marginPerLot;
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double stepSize = MarketInfo(Symbol(), MODE_LOTSTEP);
maxLotByMargin = MathFloor(maxLotByMargin / stepSize) * stepSize;
maxLotByMargin = MathMax(minLot, MathMin(maxLot, maxLotByMargin));
if(requestedLot > maxLotByMargin) {
Print("Requested lot ", requestedLot, " exceeds margin availability. Reducing to ", maxLotByMargin);
return maxLotByMargin;
}
return requestedLot;
}
// Safe OrderSend with margin check
int OrderSendWithMarginCheck(int orderType, double lotSize) {
double adjustedLot = GetMaxAffordableLot(lotSize);
if(adjustedLot < MarketInfo(Symbol(), MODE_MINLOT)) {
Print("Insufficient margin for any trade");
return -1;
}
double price = (orderType == OP_BUY) ? Ask : Bid;
return OrderSend(Symbol(), orderType, adjustedLot, price, 30, 0, 0, "Margin Check EA", magicNumber, 0, clrNONE);
}
```
Error 138: Requote
Price changed between rate request and order execution.
```mql4
// SOLUTION: Refresh rates and retry with increased slippage
int OrderSendWithRetry(int orderType, double lotSize, int maxRetries = 3) {
for(int retry = 0; retry < maxRetries; retry++) {
RefreshRates();
double price = (orderType == OP_BUY) ? Ask : Bid;
int slippage = 30 + (retry * 10); // Increase slippage each retry
int ticket = OrderSend(Symbol(), orderType, lotSize, price, slippage, 0, 0, "Retry EA", magicNumber, 0, clrNONE);
if(ticket > 0) {
return ticket;
}
int error = GetLastError();
if(error == 138) {
Print("Requote on retry ", retry + 1, ". Increasing slippage to ", slippage);
Sleep(500);
} else {
Print("Non-retryable error: ", error);
break;
}
}
return -1;
}
```
Error 146: Trading Context Busy
Multiple OrderSend calls occurring simultaneously.
```mql4
// SOLUTION: Use semaphore pattern
bool g_tradeInProgress = false;
int OrderSendWithSemaphore(int orderType, double lotSize) {
if(g_tradeInProgress) {
Print("Trade already in progress. Skipping.");
return -1;
}
g_tradeInProgress = true;
RefreshRates();
double price = (orderType == OP_BUY) ? Ask : Bid;
int ticket = OrderSend(Symbol(), orderType, lotSize, price, 30, 0, 0, "Semaphore EA", magicNumber, 0, clrNONE);
g_tradeInProgress = false;
return ticket;
}
// Alternative: Use Sleep and retry
int OrderSendWithBusyRetry(int orderType, double lotSize, int maxRetries = 5) {
for(int retry = 0; retry < maxRetries; retry++) {
RefreshRates();
double price = (orderType == OP_BUY) ? Ask : Bid;
int ticket = OrderSend(Symbol(), orderType, lotSize, price, 30, 0, 0, "Busy Retry EA", magicNumber, 0, clrNONE);
if(ticket > 0) {
return ticket;
}
int error = GetLastError();
if(error == 146) {
Print("Context busy. Retry ", retry + 1, " of ", maxRetries);
Sleep(100 * (retry + 1)); // Increasing delay
} else {
break;
}
}
return -1;
}
```
3. Complete Debugging Toolkit
```mql4
//+------------------------------------------------------------------+
//| Complete Debugging Toolkit |
//+------------------------------------------------------------------+
// Function to log all compilation errors with context
void LogCompilationError(int errorCode, string functionName, string details) {
string errorMsg;
switch(errorCode) {
case 1: errorMsg = "No result returned"; break;
case 2: errorMsg = "Common error"; break;
case 17: errorMsg = "Type conversion failed"; break;
case 30: errorMsg = "Missing semicolon"; break;
case 31: errorMsg = "Braces mismatch"; break;
case 33: errorMsg = "Invalid condition syntax"; break;
case 130: errorMsg = "Invalid stops"; break;
case 134: errorMsg = "Insufficient margin"; break;
case 138: errorMsg = "Requote"; break;
case 146: errorMsg = "Context busy"; break;
case 148: errorMsg = "Too many orders"; break;
case 4051: errorMsg = "Wrong parameter count"; break;
default: errorMsg = "Unknown error";
}
Print("[ERROR] Code: ", errorCode, " | ", errorMsg);
Print(" Function: ", functionName);
Print(" Details: ", details);
}
// Runtime error handler for trade operations
class TradeErrorHandler {
private:
int lastError;
string lastErrorMsg;
string GetErrorDescription(int error) {
switch(error) {
case 0: return "No error";
case 1: return "No result returned";
case 2: return "Common error";
case 3: return "Invalid trade parameters";
case 4: return "Trade server is busy";
case 5: return "Old version of the client terminal";
case 6: return "No connection with trade server";
case 7: return "Not enough rights";
case 8: return "Too frequent requests";
case 9: return "Malfunctional trade operation";
case 64: return "Account disabled";
case 65: return "Invalid account";
case 128: return "Trade timeout";
case 129: return "Invalid price";
case 130: return "Invalid stops";
case 131: return "Invalid trade volume";
case 132: return "Market is closed";
case 133: return "Trade is not allowed";
case 134: return "Not enough money";
case 135: return "Price changed";
case 136: return "Off quotes";
case 137: return "Broker is busy";
case 138: return "Requote";
case 139: return "Order is locked";
case 140: return "Long positions only allowed";
case 141: return "Too many requests";
case 145: return "Modification denied";
case 146: return "Trade context is busy";
case 147: return "Expirations are denied";
case 148: return "Amount of open orders is too many";
case 149: return "Hedge is prohibited";
case 150: return "Trade is not allowed for the symbol";
default: return "Unknown error";
}
}
public:
TradeErrorHandler() { lastError = 0; lastErrorMsg = ""; }
void RecordError() {
lastError = GetLastError();
lastErrorMsg = GetErrorDescription(lastError);
Print("Trade Error: ", lastError, " - ", lastErrorMsg);
}
bool IsRetryable() {
return (lastError == 138 || lastError == 146 || lastError == 4 || lastError == 137);
}
bool IsFatal() {
return (lastError == 134 || lastError == 148 || lastError == 130);
}
void PrintRecommendation() {
switch(lastError) {
case 130:
Print("Recommendation: Increase stop loss distance. Check MODE_STOPLEVEL.");
break;
case 134:
Print("Recommendation: Reduce lot size or deposit more funds.");
break;
case 138:
Print("Recommendation: Refresh rates and increase slippage.");
break;
case 146:
Print("Recommendation: Add Sleep() between trade operations.");
break;
case 148:
Print("Recommendation: Close some open orders first.");
break;
case 4051:
Print("Recommendation: Check function parameter count in documentation.");
break;
default:
Print("Recommendation: Check error code in MQL4 documentation.");
}
}
};
```
Compilation Error Prevention Checklist
Runtime Error Prevention Checklist
Reference:
9. Next Step
Part 16 will explain Strategy Backtesting and Optimization – Complete guide to using MT4 Strategy Tester, optimizing parameters, avoiding overfitting, and interpreting backtest reports.