- Add mql4-syntax-critical.instructions.md: Complete syntax rules for MQL4 - Add mql4-experts.instructions.md: Expert Advisor development guidelines - Add mql4-indicators.instructions.md: Custom indicator development guidelines - Add mql4-scripts.instructions.md: Script development guidelines - Update copilot-instructions.md: Add language-specific instruction routing - Include MQL4 vs MQL5 comparison table and workflow guidance - Based on real-world experience from MultiTimeframeZone EA development
16 KiB
| applyTo |
|---|
| **/*.mq4,**/MQL4/**/*.mqh |
CRITICAL MQL4 Syntax Rules (Mandatory for All MQL4 Code)
⚠️ Overview
MQL4 is a C-like language with specific syntax requirements that differ from both standard C++ and MQL5. These rules are mandatory for all _Thivyam MQL4 development to ensure code compiles without errors.
1. Loop Variable Declaration ❌ → ✅
Rule
NEVER declare variables inside for-loop initializers
ALWAYS declare loop counters BEFORE the for statement
Why
MQL4 does not support C99/C++11 style variable declaration in for-loop initializers.
Examples
// ✅ CORRECT
int i;
for(i = 0; i < 10; i++)
{
Print(i);
}
// Multiple nested loops
int i, j;
for(i = 0; i < ArraySize(h4_ZoneHighs); i++)
{
for(j = 0; j < ArraySize(m30_ZoneHighs); j++)
{
// Process zones
}
}
// ❌ WRONG - Causes compilation errors
for(int i = 0; i < 10; i++) // Error: 'i' - undeclared identifier
{
Print(i);
}
Additional Rules
- Use post-increment (
i++) not pre-increment (++i) - Avoid
conston loop bound variables unless necessary - Declare all loop variables at the beginning of the function or at the nearest scope
Error Messages You'll See
'i' - undeclared identifier'for' - some operator expectedexpression expected
2. Array Declarations and Sizing
Rule
Declare arrays with size or use dynamic arrays for different purposes
Be explicit about array sizes when needed
Examples
// ✅ CORRECT - Fixed-size arrays for globals
double h4_ZoneHighs[50];
string h4_ZoneTypes[50];
int h4_ZoneCount = 0;
// ✅ CORRECT - Dynamic arrays for temporary data
double prices[];
ArrayResize(prices, 100);
// ✅ CORRECT - Array for iHigh, iLow, etc.
double high[], low[];
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
// ❌ WRONG - Don't mix fixed and dynamic concepts
double data[50];
ArrayResize(data, 100); // May cause issues
Best Practices
- Use fixed-size arrays for zone storage with a counter
- Use dynamic arrays for temporary calculations or data buffers
- Always check array bounds before accessing elements
- Use
ArraySize()to get the actual size of an array
3. Order Functions and Trade Operations
Rule
Use MQL4 trade functions correctly with proper error handling
Always check return values and use GetLastError()
Examples
// ✅ CORRECT - OrderSend with full error handling
int ticket = OrderSend(Symbol(), OP_BUYLIMIT, lotSize, entryPrice, slippage,
stopLoss, takeProfit, "Comment", magicNumber, 0, clrGreen);
if(ticket > 0)
{
Print("Order placed successfully. Ticket: ", ticket);
}
else
{
int error = GetLastError();
Print("OrderSend failed with error: ", error, " - ", ErrorDescription(error));
}
// ✅ CORRECT - OrderModify with validation
if(OrderSelect(ticket, SELECT_BY_TICKET))
{
bool modified = OrderModify(ticket, OrderOpenPrice(), newSL, newTP, 0, clrBlue);
if(!modified)
{
int error = GetLastError();
Print("OrderModify failed: ", error);
}
}
// ❌ WRONG - No error checking
OrderSend(Symbol(), OP_BUY, 0.1, Ask, 3, 0, 0, "", 0, 0, clrGreen);
// What if it fails?
Order Type Constants
// Pending Orders
OP_BUYLIMIT // Buy when price drops to entry
OP_SELLLIMIT // Sell when price rises to entry
OP_BUYSTOP // Buy when price rises to entry
OP_SELLSTOP // Sell when price drops to entry
// Market Orders
OP_BUY // Immediate buy at Ask
OP_SELL // Immediate sell at Bid
Common Errors
- Error 130 (Invalid Stops): SL/TP too close to entry, violates
MODE_STOPLEVEL - Error 131 (Invalid Volume): Lot size violates
MODE_MINLOTorMODE_MAXLOT - Error 134 (Not Enough Money): Insufficient margin
- Error 129 (Invalid Price): Price is stale, requote needed
4. Price and Market Information Functions
Rule
Use correct market info mode constants
Always normalize prices to Digits precision
Examples
// ✅ CORRECT - Getting market information
double ask = MarketInfo(Symbol(), MODE_ASK);
double bid = MarketInfo(Symbol(), MODE_BID);
double point = MarketInfo(Symbol(), MODE_POINT);
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double stopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
double spread = MarketInfo(Symbol(), MODE_SPREAD);
// ✅ CORRECT - Normalizing prices
double price = NormalizeDouble(calculatedPrice, Digits);
double lots = NormalizeDouble(calculatedLots, 2);
// ✅ CORRECT - Getting historical data
double high = iHigh(Symbol(), PERIOD_H4, barIndex);
double low = iLow(Symbol(), PERIOD_M30, barIndex);
double open = iOpen(Symbol(), PERIOD_M15, barIndex);
double close = iClose(Symbol(), PERIOD_CURRENT, barIndex);
// ❌ WRONG - Using undefined constants
double info = MarketInfo(Symbol(), MODE_INVALID); // No such constant
Normalization Best Practice
// Create normalization function
double NormalizePrice(double price)
{
return NormalizeDouble(price, Digits);
}
double NormalizeLots(double lots)
{
double minLot = MarketInfo(Symbol(), MODE_MINLOT);
double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
lots = NormalizeDouble(lots, 2);
lots = MathMax(lots, minLot);
lots = MathMin(lots, maxLot);
return NormalizeDouble(lots, 2);
}
5. Object Properties and Chart Objects
Rule
Verify object property constant names in MQL4 documentation
Property names can differ from what you expect
Examples
// ✅ CORRECT - Rectangle object
ObjectCreate(0, "MyRectangle", OBJ_RECTANGLE, 0, time1, price1, time2, price2);
ObjectSetInteger(0, "MyRectangle", OBJPROP_COLOR, clrRed);
ObjectSetInteger(0, "MyRectangle", OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, "MyRectangle", OBJPROP_WIDTH, 2);
ObjectSetInteger(0, "MyRectangle", OBJPROP_BACK, false);
ObjectSetInteger(0, "MyRectangle", OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, "MyRectangle", OBJPROP_RAY_RIGHT, true);
// ✅ CORRECT - Text object
ObjectCreate(0, "MyLabel", OBJ_TEXT, 0, time, price);
ObjectSetString(0, "MyLabel", OBJPROP_TEXT, "Zone Label");
ObjectSetInteger(0, "MyLabel", OBJPROP_COLOR, clrWhite);
ObjectSetInteger(0, "MyLabel", OBJPROP_FONTSIZE, 10);
ObjectSetString(0, "MyLabel", OBJPROP_FONT, "Arial");
// ✅ CORRECT - Label (screen coordinates)
ObjectCreate(0, "InfoPanel", OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, "InfoPanel", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "InfoPanel", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "InfoPanel", OBJPROP_YDISTANCE, 20);
// ❌ WRONG - Using non-existent properties
ObjectSetInteger(0, "MyObj", OBJPROP_ZORDER, 1); // Doesn't exist in MQL4
ObjectSetInteger(0, "MyObj", OBJPROP_HEIGHT, 100); // Use OBJPROP_YSIZE
Common Object Types
OBJ_RECTANGLE // Rectangle object
OBJ_TREND // Trend line
OBJ_HLINE // Horizontal line
OBJ_VLINE // Vertical line
OBJ_TEXT // Text at chart coordinates
OBJ_LABEL // Text at screen coordinates
OBJ_ARROW // Arrow marker
Line Styles
STYLE_SOLID // Solid line
STYLE_DASH // Dashed line
STYLE_DOT // Dotted line
STYLE_DASHDOT // Dash-dot line
STYLE_DASHDOTDOT // Dash-dot-dot line
6. String Operations and Formatting
Rule
Use correct string functions for MQL4
Be careful with string concatenation and formatting
Examples
// ✅ CORRECT - String concatenation
string message = "Value: " + DoubleToString(value, 2);
string info = "Ticket: " + IntegerToString(ticket);
string combined = part1 + " | " + part2 + " | " + part3;
// ✅ CORRECT - Number to string conversion
string priceStr = DoubleToString(price, Digits);
string lotsStr = DoubleToString(lots, 2);
string countStr = IntegerToString(count);
// ✅ CORRECT - String functions
int length = StringLen(myString);
string substr = StringSubstr(myString, 0, 10);
int pos = StringFind(myString, "pattern");
string upper = StringToUpper(myString);
string lower = StringToLower(myString);
// ✅ CORRECT - String filling
string spaces = "";
int i;
for(i = 0; i < 10; i++)
{
spaces += " ";
}
// ❌ WRONG - Using undefined functions
string formatted = StringFormat("%d", value); // Use DoubleToString instead
7. Time and Date Functions
Rule
Use MQL4 time functions correctly
Be aware of server time vs local time
Examples
// ✅ CORRECT - Time functions
datetime serverTime = TimeCurrent(); // Broker server time
datetime localTime = TimeLocal(); // Computer local time
datetime gmtTime = TimeGMT(); // GMT time
// ✅ CORRECT - Time components
int year = TimeYear(serverTime);
int month = TimeMonth(serverTime);
int day = TimeDay(serverTime);
int hour = TimeHour(serverTime);
int minute = TimeMinute(serverTime);
int dayOfWeek = TimeDayOfWeek(serverTime); // 0=Sunday, 1=Monday, etc.
// ✅ CORRECT - Bar time
datetime barTime = iTime(Symbol(), PERIOD_H4, 0);
datetime prevBarTime = iTime(Symbol(), PERIOD_H4, 1);
// ✅ CORRECT - Time string formatting
string timeStr = TimeToString(serverTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS);
8. Account and Trade Information
Rule
Use account info functions, not AccountInfo variants*
Select orders before accessing order properties
Examples
// ✅ CORRECT - Account information (MQL4 style)
double balance = AccountBalance();
double equity = AccountEquity();
double freeMargin = AccountFreeMargin();
double margin = AccountMargin();
double profit = AccountProfit();
int leverage = AccountLeverage();
string currency = AccountCurrency();
// ✅ CORRECT - Order selection and properties
int total = OrdersTotal();
int i;
for(i = 0; i < total; i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber)
{
int ticket = OrderTicket();
int type = OrderType();
double openPrice = OrderOpenPrice();
double sl = OrderStopLoss();
double tp = OrderTakeProfit();
double orderLots = OrderLots();
datetime openTime = OrderOpenTime();
double orderProfit = OrderProfit();
string comment = OrderComment();
}
}
}
// ❌ WRONG - Using MQL5 style functions
double balance = AccountInfoDouble(ACCOUNT_BALANCE); // This is MQL5
9. Global Variables vs Input Parameters
Rule
Use proper input parameter declaration
Understand the difference between input, extern, and global variables
Examples
// ✅ CORRECT - Input parameters (user can modify)
input double InpLotSize = 0.01; // Lot size
input int InpStopLossPips = 30; // Stop loss in pips
input int InpMagicNumber = 123456; // Magic number
input color InpBuyColor = clrGreen; // Buy zone color
input bool InpEnableTrading = true; // Enable trading
// ✅ CORRECT - Global variables (internal state)
datetime g_lastBarTime = 0;
int g_totalOrders = 0;
bool g_initialized = false;
// ✅ CORRECT - Constants
#define MAX_ZONES 100
#define EA_VERSION "1.00"
// ❌ WRONG - Mixing input with complex initialization
input datetime g_startTime = TimeCurrent(); // Can't use functions in input
10. Common Pitfalls and Best Practices
OnTick() Execution Control
// ✅ CORRECT - Execute once per bar
datetime g_lastBarTime = 0;
void OnTick()
{
datetime currentBarTime = iTime(Symbol(), PERIOD_CURRENT, 0);
if(currentBarTime != g_lastBarTime)
{
g_lastBarTime = currentBarTime;
// Execute trading logic here (once per new bar)
CheckForSignals();
}
// Monitoring logic that runs every tick
MonitorOpenPositions();
}
Risk Management
// ✅ CORRECT - Dynamic lot sizing based on risk
double CalculateLotSize(double riskPercent, double slPips)
{
double accountEquity = AccountEquity();
double riskAmount = accountEquity * (riskPercent / 100.0);
double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
double tickSize = MarketInfo(Symbol(), MODE_TICKSIZE);
double point = MarketInfo(Symbol(), MODE_POINT);
// Calculate pip value (for 4/5 digit brokers)
double pipValue = tickValue;
if(Digits == 3 || Digits == 5)
pipValue = tickValue * 10;
// Calculate lot size
double lots = riskAmount / (slPips * pipValue);
// Normalize to broker requirements
return NormalizeLots(lots);
}
// ❌ WRONG - Hardcoded lot size
double lots = 0.01; // No risk management!
Error Description Function
// ✅ CORRECT - Comprehensive error handling
string ErrorDescription(int errorCode)
{
switch(errorCode)
{
case 0: return "No error";
case 1: return "No error, result unknown";
case 2: return "Common error";
case 4: return "Trade server busy";
case 6: return "No connection";
case 8: return "Too frequent requests";
case 129: return "Invalid price";
case 130: return "Invalid stops";
case 131: return "Invalid volume";
case 132: return "Market closed";
case 133: return "Trading disabled";
case 134: return "Not enough money";
case 135: return "Price changed";
case 136: return "Off quotes";
case 138: return "Requote";
case 146: return "Trade context busy";
default: return "Unknown error";
}
}
11. Compilation and Testing
Pre-Compilation Checklist
- All loop variables declared before for-loops
- All prices normalized to Digits precision
- All lot sizes normalized to broker requirements
- All trade operations have error handling
- All object property constants verified
- No MQL5-specific functions used
- Input parameters properly declared
- No functions called in input initialization
Testing Checklist
- Test on demo account first
- Verify order placement works correctly
- Check zone drawing appears correctly
- Validate risk management calculations
- Test with different broker conditions
- Verify behavior across timeframe changes
- Check for memory leaks (objects, indicators)
- Test deinitialization cleanup
12. Key Differences: MQL4 vs MQL5
| Feature | MQL4 | MQL5 |
|---|---|---|
| Pointer Access | Use . operator |
Use . operator (NOT ->) |
| Loop Variables | Declare before loop | Declare before loop |
| Trade Functions | OrderSend(), OrderModify() |
CTrade class |
| Account Info | AccountBalance() |
AccountInfoDouble() |
| Order Selection | OrderSelect() required |
PositionSelect() different |
| Magic Number | Parameter in OrderSend() |
Set via CTrade::SetExpertMagicNumber() |
| Indicator Handles | Direct calls (iMA() returns value) |
Returns handle, use CopyBuffer() |
| Object Management | ObjectCreate(), ObjectSetInteger() |
Same, but some properties differ |
Summary
Critical Rules for MQL4:
- ✅ Declare loop variables BEFORE for-loop
- ✅ Use dot operator (
.) only - ✅ Normalize all prices and lot sizes
- ✅ Always check trade function return values
- ✅ Verify object property constant names
- ✅ Use MQL4 account functions, not MQL5 variants
- ✅ Implement proper error handling with GetLastError()
- ✅ Execute trading logic once per bar
- ✅ Calculate position size dynamically based on risk
- ✅ Test thoroughly on demo before live trading
Following these rules will prevent 95% of common MQL4 compilation and runtime errors.