- 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
652 lines
17 KiB
Markdown
652 lines
17 KiB
Markdown
---
|
|
applyTo: "**/MQL4/Scripts/_Thivyam/**/*.mq4"
|
|
---
|
|
# Instructions for _Thivyam MQL4 Scripts
|
|
|
|
## CRITICAL: MQL4 Syntax Compliance
|
|
**Before writing any MQL4 code, read and follow:** `mql4-syntax-critical.instructions.md`
|
|
|
|
Key mandatory rules for scripts:
|
|
- Declare loop variables BEFORE for-loop: `int i; for(i=0; i<n; i++)`
|
|
- Use `GetLastError()` after all trade operations
|
|
- Normalize all prices and lot sizes
|
|
- Scripts execute once and terminate (no OnTick)
|
|
|
|
---
|
|
|
|
## Script Overview
|
|
|
|
**MQL4 Scripts** are programs that execute a specific task once and then terminate. They are ideal for:
|
|
- Batch operations (closing all orders, deleting all objects)
|
|
- One-time calculations or analysis
|
|
- Chart setup automation
|
|
- Trade management utilities
|
|
- Data export/import operations
|
|
|
|
**Key Differences from EAs:**
|
|
- Scripts use `OnStart()` instead of `OnTick()`
|
|
- Execute once and terminate
|
|
- No continuous monitoring
|
|
- Perfect for utility functions
|
|
|
|
---
|
|
|
|
## Script Structure
|
|
|
|
### Basic Template
|
|
```mql4
|
|
//+------------------------------------------------------------------+
|
|
//| YourScript.mq4 |
|
|
//| Author: Your Name |
|
|
//| https://www.yourwebsite.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Your Name"
|
|
#property link "https://www.yourwebsite.com"
|
|
#property version "1.00"
|
|
#property strict
|
|
#property description "Brief description of script function"
|
|
#property show_inputs // Show input dialog before execution
|
|
|
|
// INPUT PARAMETERS
|
|
input int InpMagicNumber = 123456; // Magic Number
|
|
input bool InpConfirm = true; // Ask for confirmation
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Script program start function |
|
|
//+------------------------------------------------------------------+
|
|
void OnStart()
|
|
{
|
|
// 1. Validate inputs
|
|
if(InpMagicNumber == 0)
|
|
{
|
|
Print("Warning: Magic number is 0");
|
|
}
|
|
|
|
// 2. Ask for confirmation if enabled
|
|
if(InpConfirm)
|
|
{
|
|
int result = MessageBox("Execute script on " + Symbol() + "?",
|
|
"Confirm Action",
|
|
MB_YESNO | MB_ICONQUESTION);
|
|
if(result != IDYES)
|
|
{
|
|
Print("Script execution cancelled by user");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 3. Execute main logic
|
|
ExecuteScriptLogic();
|
|
|
|
// 4. Report results
|
|
Print("Script execution completed successfully");
|
|
}
|
|
|
|
void ExecuteScriptLogic()
|
|
{
|
|
// Main script functionality here
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Common Script Types
|
|
|
|
### 1. Close All Orders Script
|
|
```mql4
|
|
#property show_inputs
|
|
|
|
input int InpMagicNumber = 0; // Magic Number (0 = all)
|
|
input bool InpConfirm = true; // Ask confirmation
|
|
|
|
void OnStart()
|
|
{
|
|
int totalClosed = 0;
|
|
int totalFailed = 0;
|
|
|
|
// Count orders first
|
|
int totalOrders = CountOrders(InpMagicNumber);
|
|
|
|
if(totalOrders == 0)
|
|
{
|
|
Print("No orders to close");
|
|
return;
|
|
}
|
|
|
|
// Ask confirmation
|
|
if(InpConfirm)
|
|
{
|
|
string message = "Close " + IntegerToString(totalOrders) + " orders";
|
|
if(InpMagicNumber > 0)
|
|
message += " with Magic Number " + IntegerToString(InpMagicNumber);
|
|
message += "?";
|
|
|
|
int result = MessageBox(message, "Confirm Close All", MB_YESNO | MB_ICONWARNING);
|
|
if(result != IDYES)
|
|
{
|
|
Print("Operation cancelled");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Close all orders (iterate backwards)
|
|
int total = OrdersTotal();
|
|
int i;
|
|
for(i = total - 1; i >= 0; i--)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
|
|
// Filter by symbol
|
|
if(OrderSymbol() != Symbol()) continue;
|
|
|
|
// Filter by magic number
|
|
if(InpMagicNumber > 0 && OrderMagicNumber() != InpMagicNumber) continue;
|
|
|
|
bool closed = false;
|
|
int ticket = OrderTicket();
|
|
|
|
if(OrderType() == OP_BUY)
|
|
{
|
|
closed = OrderClose(ticket, OrderLots(), Bid, 3, clrRed);
|
|
}
|
|
else if(OrderType() == OP_SELL)
|
|
{
|
|
closed = OrderClose(ticket, OrderLots(), Ask, 3, clrRed);
|
|
}
|
|
else // Pending orders
|
|
{
|
|
closed = OrderDelete(ticket, clrRed);
|
|
}
|
|
|
|
if(closed)
|
|
{
|
|
totalClosed++;
|
|
Print("Closed ticket #", ticket);
|
|
}
|
|
else
|
|
{
|
|
totalFailed++;
|
|
int error = GetLastError();
|
|
Print("Failed to close ticket #", ticket, " Error: ", error);
|
|
}
|
|
}
|
|
|
|
// Report results
|
|
string message = "Closed: " + IntegerToString(totalClosed);
|
|
if(totalFailed > 0)
|
|
message += " | Failed: " + IntegerToString(totalFailed);
|
|
|
|
Print(message);
|
|
MessageBox(message, "Close All Complete", MB_OK | MB_ICONINFORMATION);
|
|
}
|
|
|
|
int CountOrders(int magicNumber)
|
|
{
|
|
int count = 0;
|
|
int total = OrdersTotal();
|
|
int i;
|
|
|
|
for(i = 0; i < total; i++)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
if(OrderSymbol() != Symbol()) continue;
|
|
if(magicNumber > 0 && OrderMagicNumber() != magicNumber) continue;
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 2. Delete All Objects Script
|
|
```mql4
|
|
#property show_inputs
|
|
|
|
input bool InpConfirm = true; // Ask confirmation
|
|
input string InpPrefix = ""; // Object prefix (empty = all)
|
|
|
|
void OnStart()
|
|
{
|
|
int totalDeleted = 0;
|
|
|
|
// Count objects
|
|
int totalObjects = ObjectsTotal(0);
|
|
|
|
if(totalObjects == 0)
|
|
{
|
|
Print("No objects to delete");
|
|
return;
|
|
}
|
|
|
|
// Ask confirmation
|
|
if(InpConfirm)
|
|
{
|
|
string message = "Delete " + IntegerToString(totalObjects) + " chart objects";
|
|
if(InpPrefix != "")
|
|
message += " with prefix '" + InpPrefix + "'";
|
|
message += "?";
|
|
|
|
int result = MessageBox(message, "Confirm Delete All", MB_YESNO | MB_ICONWARNING);
|
|
if(result != IDYES)
|
|
{
|
|
Print("Operation cancelled");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Delete all objects (iterate backwards)
|
|
int i;
|
|
for(i = totalObjects - 1; i >= 0; i--)
|
|
{
|
|
string objName = ObjectName(0, i);
|
|
|
|
// Filter by prefix if specified
|
|
if(InpPrefix != "")
|
|
{
|
|
if(StringFind(objName, InpPrefix) != 0) continue;
|
|
}
|
|
|
|
if(ObjectDelete(0, objName))
|
|
{
|
|
totalDeleted++;
|
|
}
|
|
}
|
|
|
|
// Redraw chart
|
|
ChartRedraw(0);
|
|
|
|
Print("Deleted ", totalDeleted, " objects");
|
|
MessageBox("Deleted " + IntegerToString(totalDeleted) + " objects",
|
|
"Delete Complete",
|
|
MB_OK | MB_ICONINFORMATION);
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 3. Modify All Orders Script
|
|
```mql4
|
|
#property show_inputs
|
|
|
|
input int InpMagicNumber = 0; // Magic Number (0 = all)
|
|
input int InpNewStopLossPips = 0; // New SL in pips (0 = no change)
|
|
input int InpNewTakeProfitPips = 0; // New TP in pips (0 = no change)
|
|
input bool InpConfirm = true; // Ask confirmation
|
|
|
|
void OnStart()
|
|
{
|
|
if(InpNewStopLossPips == 0 && InpNewTakeProfitPips == 0)
|
|
{
|
|
Print("ERROR: No modification specified");
|
|
MessageBox("Please specify SL or TP modification", "Error", MB_OK | MB_ICONERROR);
|
|
return;
|
|
}
|
|
|
|
int totalModified = 0;
|
|
int totalFailed = 0;
|
|
|
|
// Count orders
|
|
int totalOrders = CountOrders(InpMagicNumber);
|
|
|
|
if(totalOrders == 0)
|
|
{
|
|
Print("No orders to modify");
|
|
return;
|
|
}
|
|
|
|
// Ask confirmation
|
|
if(InpConfirm)
|
|
{
|
|
string message = "Modify " + IntegerToString(totalOrders) + " orders?";
|
|
if(InpNewStopLossPips > 0)
|
|
message += "\nNew SL: " + IntegerToString(InpNewStopLossPips) + " pips";
|
|
if(InpNewTakeProfitPips > 0)
|
|
message += "\nNew TP: " + IntegerToString(InpNewTakeProfitPips) + " pips";
|
|
|
|
int result = MessageBox(message, "Confirm Modify All", MB_YESNO | MB_ICONQUESTION);
|
|
if(result != IDYES)
|
|
{
|
|
Print("Operation cancelled");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Modify all orders
|
|
int total = OrdersTotal();
|
|
int i;
|
|
for(i = 0; i < total; i++)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
if(OrderSymbol() != Symbol()) continue;
|
|
if(InpMagicNumber > 0 && OrderMagicNumber() != InpMagicNumber) continue;
|
|
|
|
// Only modify market positions
|
|
if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
|
|
|
|
int ticket = OrderTicket();
|
|
double openPrice = OrderOpenPrice();
|
|
double newSL = OrderStopLoss();
|
|
double newTP = OrderTakeProfit();
|
|
|
|
// Calculate new SL
|
|
if(InpNewStopLossPips > 0)
|
|
{
|
|
if(OrderType() == OP_BUY)
|
|
newSL = openPrice - InpNewStopLossPips * Point * 10;
|
|
else
|
|
newSL = openPrice + InpNewStopLossPips * Point * 10;
|
|
|
|
newSL = NormalizeDouble(newSL, Digits);
|
|
}
|
|
|
|
// Calculate new TP
|
|
if(InpNewTakeProfitPips > 0)
|
|
{
|
|
if(OrderType() == OP_BUY)
|
|
newTP = openPrice + InpNewTakeProfitPips * Point * 10;
|
|
else
|
|
newTP = openPrice - InpNewTakeProfitPips * Point * 10;
|
|
|
|
newTP = NormalizeDouble(newTP, Digits);
|
|
}
|
|
|
|
// Modify order
|
|
bool modified = OrderModify(ticket, openPrice, newSL, newTP, 0, clrBlue);
|
|
|
|
if(modified)
|
|
{
|
|
totalModified++;
|
|
Print("Modified ticket #", ticket, " SL: ", newSL, " TP: ", newTP);
|
|
}
|
|
else
|
|
{
|
|
totalFailed++;
|
|
int error = GetLastError();
|
|
Print("Failed to modify ticket #", ticket, " Error: ", error);
|
|
}
|
|
}
|
|
|
|
// Report results
|
|
string message = "Modified: " + IntegerToString(totalModified);
|
|
if(totalFailed > 0)
|
|
message += " | Failed: " + IntegerToString(totalFailed);
|
|
|
|
Print(message);
|
|
MessageBox(message, "Modify Complete", MB_OK | MB_ICONINFORMATION);
|
|
}
|
|
|
|
int CountOrders(int magicNumber)
|
|
{
|
|
int count = 0;
|
|
int total = OrdersTotal();
|
|
int i;
|
|
|
|
for(i = 0; i < total; i++)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
if(OrderSymbol() != Symbol()) continue;
|
|
if(magicNumber > 0 && OrderMagicNumber() != magicNumber) continue;
|
|
if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 4. Account Information Script
|
|
```mql4
|
|
void OnStart()
|
|
{
|
|
string info = "";
|
|
|
|
info += "========================================\n";
|
|
info += "ACCOUNT INFORMATION\n";
|
|
info += "========================================\n\n";
|
|
|
|
info += "Account Number: " + IntegerToString(AccountNumber()) + "\n";
|
|
info += "Account Name: " + AccountName() + "\n";
|
|
info += "Account Server: " + AccountServer() + "\n";
|
|
info += "Account Company: " + AccountCompany() + "\n";
|
|
info += "Account Currency: " + AccountCurrency() + "\n";
|
|
info += "Account Leverage: 1:" + IntegerToString(AccountLeverage()) + "\n\n";
|
|
|
|
info += "Balance: " + DoubleToString(AccountBalance(), 2) + "\n";
|
|
info += "Equity: " + DoubleToString(AccountEquity(), 2) + "\n";
|
|
info += "Margin: " + DoubleToString(AccountMargin(), 2) + "\n";
|
|
info += "Free Margin: " + DoubleToString(AccountFreeMargin(), 2) + "\n";
|
|
info += "Margin Level: " + DoubleToString(AccountMargin() > 0 ? (AccountEquity() / AccountMargin() * 100) : 0, 2) + "%\n\n";
|
|
|
|
info += "Profit: " + DoubleToString(AccountProfit(), 2) + "\n";
|
|
info += "Credit: " + DoubleToString(AccountCredit(), 2) + "\n\n";
|
|
|
|
info += "Open Positions: " + IntegerToString(CountOpenPositions()) + "\n";
|
|
info += "Pending Orders: " + IntegerToString(CountPendingOrders()) + "\n";
|
|
|
|
info += "========================================\n";
|
|
|
|
// Print to journal
|
|
Print(info);
|
|
|
|
// Create file
|
|
int handle = FileOpen("AccountInfo_" + TimeToString(TimeCurrent(), TIME_DATE) + ".txt",
|
|
FILE_WRITE | FILE_TXT);
|
|
if(handle != INVALID_HANDLE)
|
|
{
|
|
FileWriteString(handle, info);
|
|
FileClose(handle);
|
|
Print("Account info saved to file");
|
|
}
|
|
|
|
// Show message
|
|
MessageBox(info, "Account Information", MB_OK | MB_ICONINFORMATION);
|
|
}
|
|
|
|
int CountOpenPositions()
|
|
{
|
|
int count = 0;
|
|
int total = OrdersTotal();
|
|
int i;
|
|
|
|
for(i = 0; i < total; i++)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
if(OrderType() == OP_BUY || OrderType() == OP_SELL) count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int CountPendingOrders()
|
|
{
|
|
int count = 0;
|
|
int total = OrdersTotal();
|
|
int i;
|
|
|
|
for(i = 0; i < total; i++)
|
|
{
|
|
if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
|
|
if(OrderType() > OP_SELL) count++; // Pending orders
|
|
}
|
|
|
|
return count;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 5. Draw Support/Resistance Lines Script
|
|
```mql4
|
|
#property show_inputs
|
|
|
|
input int InpLookbackBars = 100; // Bars to analyze
|
|
input int InpMinTouches = 2; // Minimum touches
|
|
input color InpSupportColor = clrGreen;
|
|
input color InpResistanceColor = clrRed;
|
|
|
|
void OnStart()
|
|
{
|
|
// Delete old lines
|
|
DeleteOldLines();
|
|
|
|
// Find support/resistance levels
|
|
double support[], resistance[];
|
|
FindLevels(support, resistance);
|
|
|
|
// Draw support lines
|
|
int i;
|
|
for(i = 0; i < ArraySize(support); i++)
|
|
{
|
|
DrawHLine("Support_" + IntegerToString(i), support[i], InpSupportColor, STYLE_SOLID);
|
|
}
|
|
|
|
// Draw resistance lines
|
|
for(i = 0; i < ArraySize(resistance); i++)
|
|
{
|
|
DrawHLine("Resistance_" + IntegerToString(i), resistance[i], InpResistanceColor, STYLE_SOLID);
|
|
}
|
|
|
|
ChartRedraw(0);
|
|
|
|
Print("Drew ", ArraySize(support), " support and ", ArraySize(resistance), " resistance lines");
|
|
}
|
|
|
|
void FindLevels(double &support[], double &resistance[])
|
|
{
|
|
// Simplified logic - find swing highs/lows
|
|
ArrayResize(support, 0);
|
|
ArrayResize(resistance, 0);
|
|
|
|
int i;
|
|
for(i = 2; i < InpLookbackBars - 2; i++)
|
|
{
|
|
// Check for swing high (resistance)
|
|
if(iHigh(Symbol(), PERIOD_CURRENT, i) > iHigh(Symbol(), PERIOD_CURRENT, i-1) &&
|
|
iHigh(Symbol(), PERIOD_CURRENT, i) > iHigh(Symbol(), PERIOD_CURRENT, i-2) &&
|
|
iHigh(Symbol(), PERIOD_CURRENT, i) > iHigh(Symbol(), PERIOD_CURRENT, i+1) &&
|
|
iHigh(Symbol(), PERIOD_CURRENT, i) > iHigh(Symbol(), PERIOD_CURRENT, i+2))
|
|
{
|
|
double level = iHigh(Symbol(), PERIOD_CURRENT, i);
|
|
AddLevel(resistance, level);
|
|
}
|
|
|
|
// Check for swing low (support)
|
|
if(iLow(Symbol(), PERIOD_CURRENT, i) < iLow(Symbol(), PERIOD_CURRENT, i-1) &&
|
|
iLow(Symbol(), PERIOD_CURRENT, i) < iLow(Symbol(), PERIOD_CURRENT, i-2) &&
|
|
iLow(Symbol(), PERIOD_CURRENT, i) < iLow(Symbol(), PERIOD_CURRENT, i+1) &&
|
|
iLow(Symbol(), PERIOD_CURRENT, i) < iLow(Symbol(), PERIOD_CURRENT, i+2))
|
|
{
|
|
double level = iLow(Symbol(), PERIOD_CURRENT, i);
|
|
AddLevel(support, level);
|
|
}
|
|
}
|
|
}
|
|
|
|
void AddLevel(double &levels[], double price)
|
|
{
|
|
int size = ArraySize(levels);
|
|
ArrayResize(levels, size + 1);
|
|
levels[size] = NormalizeDouble(price, Digits);
|
|
}
|
|
|
|
void DrawHLine(string name, double price, color lineColor, int style)
|
|
{
|
|
ObjectDelete(0, name);
|
|
ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
|
|
ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
|
|
ObjectSetInteger(0, name, OBJPROP_STYLE, style);
|
|
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
|
|
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, true);
|
|
}
|
|
|
|
void DeleteOldLines()
|
|
{
|
|
int total = ObjectsTotal(0);
|
|
int i;
|
|
|
|
for(i = total - 1; i >= 0; i--)
|
|
{
|
|
string name = ObjectName(0, i);
|
|
if(StringFind(name, "Support_") == 0 || StringFind(name, "Resistance_") == 0)
|
|
{
|
|
ObjectDelete(0, name);
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Best Practices for Scripts
|
|
|
|
### 1. User Confirmation
|
|
Always ask for confirmation before destructive operations:
|
|
```mql4
|
|
if(InpConfirm)
|
|
{
|
|
int result = MessageBox("Are you sure?", "Confirm", MB_YESNO | MB_ICONWARNING);
|
|
if(result != IDYES) return;
|
|
}
|
|
```
|
|
|
|
### 2. Progress Reporting
|
|
Report progress for long operations:
|
|
```mql4
|
|
int total = 1000;
|
|
int i;
|
|
for(i = 0; i < total; i++)
|
|
{
|
|
if(i % 100 == 0)
|
|
{
|
|
Comment("Processing: ", (i * 100 / total), "%");
|
|
}
|
|
// Process...
|
|
}
|
|
Comment(""); // Clear comment
|
|
```
|
|
|
|
### 3. Error Handling
|
|
Handle errors gracefully:
|
|
```mql4
|
|
bool success = OrderClose(ticket, lots, price, slippage);
|
|
if(!success)
|
|
{
|
|
int error = GetLastError();
|
|
Print("Error closing order: ", error, " - ", ErrorDescription(error));
|
|
// Continue or abort?
|
|
}
|
|
```
|
|
|
|
### 4. File Operations
|
|
Save results to files when appropriate:
|
|
```mql4
|
|
int handle = FileOpen("results.csv", FILE_WRITE | FILE_CSV);
|
|
if(handle != INVALID_HANDLE)
|
|
{
|
|
FileWrite(handle, "Date", "Value");
|
|
// Write data...
|
|
FileClose(handle);
|
|
Print("Results saved to files folder");
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Summary: MQL4 Script Best Practices
|
|
|
|
1. ✅ Use `OnStart()` function (executes once)
|
|
2. ✅ Set `#property show_inputs` to show input dialog
|
|
3. ✅ Ask confirmation for destructive operations
|
|
4. ✅ Report progress for long operations
|
|
5. ✅ Handle errors with GetLastError()
|
|
6. ✅ Provide clear feedback to user (MessageBox, Print)
|
|
7. ✅ Clean up resources (close files, etc.)
|
|
8. ✅ Test thoroughly before deployment
|
|
9. ✅ Document script functionality clearly
|
|
10. ✅ Follow MQL4 syntax rules from critical instructions
|
|
|
|
Scripts are powerful utilities for traders - make them user-friendly and safe!
|