- 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
17 KiB
17 KiB
| 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 ofOnTick() - Execute once and terminate
- No continuous monitoring
- Perfect for utility functions
Script Structure
Basic Template
//+------------------------------------------------------------------+
//| 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
#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
#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
#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
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
#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:
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:
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:
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:
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
- ✅ Use
OnStart()function (executes once) - ✅ Set
#property show_inputsto show input dialog - ✅ Ask confirmation for destructive operations
- ✅ Report progress for long operations
- ✅ Handle errors with GetLastError()
- ✅ Provide clear feedback to user (MessageBox, Print)
- ✅ Clean up resources (close files, etc.)
- ✅ Test thoroughly before deployment
- ✅ Document script functionality clearly
- ✅ Follow MQL4 syntax rules from critical instructions
Scripts are powerful utilities for traders - make them user-friendly and safe!