MQL4/.github/instructions/mql4-scripts.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

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 of OnTick()
  • 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

  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!