--- 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 ```mql4 // ✅ 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 `const` on 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 expected` - `expression 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 ```mql4 // ✅ 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 ```mql4 // ✅ 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 ```mql4 // 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_MINLOT` or `MODE_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 ```mql4 // ✅ 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 ```mql4 // 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 ```mql4 // ✅ 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 ```mql4 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 ```mql4 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 ```mql4 // ✅ 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 ```mql4 // ✅ 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 ```mql4 // ✅ 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 ```mql4 // ✅ 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 ```mql4 // ✅ 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 ```mql4 // ✅ 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 ```mql4 // ✅ 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:** 1. ✅ Declare loop variables BEFORE for-loop 2. ✅ Use dot operator (`.`) only 3. ✅ Normalize all prices and lot sizes 4. ✅ Always check trade function return values 5. ✅ Verify object property constant names 6. ✅ Use MQL4 account functions, not MQL5 variants 7. ✅ Implement proper error handling with GetLastError() 8. ✅ Execute trading logic once per bar 9. ✅ Calculate position size dynamically based on risk 10. ✅ Test thoroughly on demo before live trading Following these rules will prevent 95% of common MQL4 compilation and runtime errors.