MQL4/.github/instructions/mql4-syntax-critical.instructions.md
Rahul Dhangar 740e967470 Add comprehensive MQL4 instruction files and update main copilot instructions
- 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
2025-11-04 04:07:37 +05:30

545 lines
16 KiB
Markdown

---
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.