Summary: This comprehensive guide covers all loop structures in MQL4 including for, while, and do-while loops. Learn how to process multiple orders, traverse arrays, and implement repetitive trading tasks with practical EA examples.




Why Loop Structures Matter in EA Development
Loop structures allow your EA to execute a block of code multiple times without writing repetitive code. They are essential for processing multiple orders, iterating through arrays, implementing grid strategies, and performing repetitive calculations. Without loops, an EA could only process a fixed number of items.

Complete Loop Structures Reference Table
| Loop Type | Syntax | Execution | Best Use Case |
|-----------|--------|-----------|---------------|
| for | for(init; condition; increment) { code } | Checks condition before each iteration | Known iteration count |
| while | while(condition) { code } | Checks condition before each iteration | Unknown iteration count |
| do-while | do { code } while(condition); | Executes once then checks condition | Must execute at least once |

1. The for Loop - Fixed Iteration Counting
The for loop is ideal when you know exactly how many times you need to iterate. It combines initialization, condition checking, and increment in one line.
```mql4
// Basic for loop syntax
for(initialization; condition; increment) {
// Code to repeat
}

// Simple for loop examples
for(int i = 0; i < 10; i++) {
Print("Iteration number: ", i);
}

// Countdown loop
for(int i = 10; i > 0; i--) {
Print("Countdown: ", i);
}

// Step by 2
for(int i = 0; i < 20; i += 2) {
Print("Even number: ", i);
}

// Practical EA example - Process all open orders
void ProcessAllOrders() {
int totalOrders = OrdersTotal();
Print("Processing ", totalOrders, " open orders");

for(int i = 0; i < totalOrders; i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol()) {
Print("Order ", i, " Ticket: ", OrderTicket(), " Type: ", OrderType());

// Calculate order profit in points
double profitPoints = 0;
if(OrderType() == OP_BUY) {
profitPoints = (Bid - OrderOpenPrice()) / Point();
} else if(OrderType() == OP_SELL) {
profitPoints = (OrderOpenPrice() - Ask) / Point();
}
Print("Order profit in points: ", profitPoints);
}
}
}
}

// Calculate average price of all positions
double CalculateAveragePrice() {
double totalPrice = 0;
int positionCount = 0;
int totalOrders = OrdersTotal();

for(int i = 0; i < totalOrders; i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber) {
totalPrice += OrderOpenPrice();
positionCount++;
}
}
}

if(positionCount > 0) {
return totalPrice / positionCount;
}
return 0;
}

// Array processing with for loop
double CalculateMovingAverage(double &prices[], int period) {
if(ArraySize(prices) < period) return 0;

double sum = 0;
for(int i = 0; i < period; i++) {
sum += prices[i];
}
return sum / period;
}

// Multi-timeframe analysis with nested for loops
void AnalyzeMultipleTimeframes() {
int timeframes[] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_H1, PERIOD_H4};
string tfNames[] = {"M1", "M5", "M15", "H1", "H4"};

for(int i = 0; i < ArraySize(timeframes); i++) {
double maValue = iMA(Symbol(), timeframes[i], 20, 0, MODE_SMA, PRICE_CLOSE, 1);
Print(tfNames[i], " MA20: ", maValue);

// Nested loop for multiple indicator values
for(int j = 1; j <= 3; j++) {
double close = iClose(Symbol(), timeframes[i], j);
Print(" ", tfNames[i], " Close[", j, "]: ", close);
}
}
}
```

2. The while Loop - Condition-Based Iteration
The while loop continues executing as long as the specified condition remains true. It checks the condition before each iteration, so if the condition starts false, the loop never executes.
```mql4
// Basic while loop syntax
while(condition) {
// Code to repeat while condition is true
}

// Simple while loop examples
int counter = 0;
while(counter < 10) {
Print("Counter: ", counter);
counter++;
}

// While loop with complex condition
double balance = AccountBalance();
while(balance > 10000 && !IsTradeAllowed() == false) {
balance = AccountBalance();
Print("Current balance: ", balance);
Sleep(1000); // Wait 1 second
}

// Practical EA example - Process orders with index management
void ProcessOrdersWithWhile() {
int i = 0;
while(i < OrdersTotal()) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber) {
// Check if order needs modification
if(OrderStopLoss() == 0 && OrderProfit() > 10) {
double newStopLoss = OrderType() == OP_BUY ?
Bid - 30 * Point() :
Ask + 30 * Point();
OrderModify(OrderTicket(), OrderOpenPrice(), newStopLoss, OrderTakeProfit(), 0, clrNONE);
Print("Stop loss added for order ", OrderTicket());
}
}
i++; // Only increment when order exists
} else {
i++; // Increment on selection failure as well
}
}
}

// Grid strategy implementation with while loop
void ExecuteGridStrategy(double startPrice, double gridSpacing, int maxLevels) {
int currentLevel = 0;
double currentPrice = startPrice;

while(currentLevel < maxLevels) {
if(MathAbs(Bid - currentPrice) >= gridSpacing) {
// Price crossed grid level - place order
if(Bid > currentPrice) {
OpenSellOrder(0.1, currentPrice + gridSpacing);
Print("Sell order placed at grid level ", currentLevel);
} else {
OpenBuyOrder(0.1, currentPrice - gridSpacing);
Print("Buy order placed at grid level ", currentLevel);
}
currentPrice = Bid;
currentLevel++;
}
Sleep(100); // Small pause to prevent CPU overload
}
}

// Retry mechanism for order placement
bool PlaceOrderWithRetry(int maxRetries) {
int retryCount = 0;
bool orderPlaced = false;

while(retryCount < maxRetries && !orderPlaced) {
int ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 30, 0, 0, "Retry Order", magicNumber, 0, clrNONE);

if(ticket > 0) {
orderPlaced = true;
Print("Order placed successfully on retry ", retryCount);
} else {
retryCount++;
Print("Retry ", retryCount, " failed. Error: ", GetLastError());
Sleep(1000 * retryCount); // Exponential backoff
}
}
return orderPlaced;
}
```

3. The do-while Loop - Execute First, Check Later
The do-while loop executes the code block once before checking the condition. This guarantees at least one execution, making it ideal for scenarios where you need to perform an action before evaluating the loop condition.
```mql4
// Basic do-while loop syntax
do {
// Code to execute at least once
} while(condition);

// Simple do-while examples
int counter = 0;
do {
Print("This executes at least once, counter: ", counter);
counter++;
} while(counter < 5);

// User input validation (simulated)
int GetValidLotSize() {
int lotSize = 0;
do {
lotSize = 1; // In real scenario, this would get user input
if(lotSize < 0.01 || lotSize > 10) {
Print("Invalid lot size. Must be between 0.01 and 10");
}
} while(lotSize < 0.01 || lotSize > 10);
return lotSize;
}

// Practical EA example - Ensure at least one order modification attempt
void ModifyAllOrdersWithDoWhile() {
int modifiedCount = 0;
int totalOrders = OrdersTotal();
int attemptCount = 0;

if(totalOrders == 0) {
Print("No orders to modify");
return;
}

do {
attemptCount++;
modifiedCount = 0;

for(int i = 0; i < totalOrders; i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber) {
// Attempt to modify order
if(OrderStopLoss() == 0 && OrderProfit() > 5) {
double newStop = OrderType() == OP_BUY ? Bid - 20 * Point() : Ask + 20 * Point();
if(OrderModify(OrderTicket(), OrderOpenPrice(), newStop, OrderTakeProfit(), 0, clrNONE)) {
modifiedCount++;
}
}
}
}
}

if(modifiedCount > 0) {
Print("Modified ", modifiedCount, " orders on attempt ", attemptCount);
} else if(attemptCount < 3) {
Print("No orders modified on attempt ", attemptCount, ", retrying...");
Sleep(500);
}

} while(modifiedCount == 0 && attemptCount < 3);
}

// Position management with guaranteed execution
void EnsurePositionClosing() {
int remainingAttempts = 5;
bool allClosed = false;

do {
int openOrders = 0;

// Count and try to close all positions
for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber) {
openOrders++;
bool closed = OrderType() == OP_BUY ?
OrderClose(OrderTicket(), OrderLots(), Bid, 30, clrNONE) :
OrderClose(OrderTicket(), OrderLots(), Ask, 30, clrNONE);
if(closed) {
Print("Closed order ", OrderTicket());
} else {
Print("Failed to close order ", OrderTicket(), " Error: ", GetLastError());
}
}
}
}

allClosed = (openOrders == 0);
remainingAttempts--;

if(!allClosed && remainingAttempts > 0) {
Print("Still have ", openOrders, " open positions. Retrying...");
Sleep(1000);
}

} while(!allClosed && remainingAttempts > 0);

if(allClosed) {
Print("All positions closed successfully");
} else {
Print("Failed to close all positions after maximum attempts");
}
}
```

Loop Control Statements - break and continue
```mql4
// break - exit loop immediately
void FindFirstProfitableOrder() {
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderProfit() > 0) {
Print("Found profitable order: ", OrderTicket(), " Profit: ", OrderProfit());
break; // Exit loop immediately
}
}
}
}

// continue - skip to next iteration
void ProcessOnlyBuyOrders() {
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderType() != OP_BUY) {
continue; // Skip non-buy orders
}
// Process only buy orders here
Print("Processing buy order: ", OrderTicket());
}
}
}

// Nested loops with break labels
void FindSpecificOrder(int targetTicket) {
bool found = false;

for(int i = 0; i < OrdersTotal() && !found; i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderTicket() == targetTicket) {
Print("Found target order: ", OrderTicket());
found = true;
break;
}
}
}
}
```

Complete EA Template Using All Loop Types
```mql4
//+------------------------------------------------------------------+
//| LoopsEA.mq4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property version "1.00"
#property strict

input double InpLotSize = 0.1;
input int InpMagic = 12345;
input int InpMaxOrders = 5;
input int InpTrailingStop = 30;
input bool InpUseGrid = false;
input double InpGridSpacing = 50; // Points

//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit() {
Print("Loops EA initialized");
return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick() {
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];

ManageAllPositions();

if(CountOrders(InpMagic) < InpMaxOrders) {
CheckAndEnterTrades();
}

if(InpUseGrid) {
ManageGridOrders();
}
}

//+------------------------------------------------------------------+
//| Count orders using for loop |
//+------------------------------------------------------------------+
int CountOrders(int magic) {
int count = 0;
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == magic) {
count++;
}
}
}
return count;
}

//+------------------------------------------------------------------+
//| Manage all positions with trailing stop using for loop |
//+------------------------------------------------------------------+
void ManageAllPositions() {
for(int i = 0; i < OrdersTotal(); i++) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagic) {
ApplyTrailingStop(OrderTicket());
}
}
}
}

//+------------------------------------------------------------------+
//| Apply trailing stop to single order |
//+------------------------------------------------------------------+
void ApplyTrailingStop(int ticket) {
if(OrderSelect(ticket, SELECT_BY_TICKET)) {
double currentStop = OrderStopLoss();
double newStop = 0;
double currentPrice = (OrderType() == OP_BUY) ? Bid : Ask;
double openPrice = OrderOpenPrice();
double profitPoints = 0;

if(OrderType() == OP_BUY) {
profitPoints = (currentPrice - openPrice) / Point();
if(profitPoints > InpTrailingStop) {
newStop = currentPrice - InpTrailingStop * Point();
}
} else {
profitPoints = (openPrice - currentPrice) / Point();
if(profitPoints > InpTrailingStop) {
newStop = currentPrice + InpTrailingStop * Point();
}
}

if(newStop > 0 && newStop != currentStop) {
OrderModify(ticket, openPrice, newStop, OrderTakeProfit(), 0, clrNONE);
Print("Trailing stop updated for order ", ticket);
}
}
}

//+------------------------------------------------------------------+
//| Check and enter trades using for loop on multiple conditions |
//+------------------------------------------------------------------+
void CheckAndEnterTrades() {
int timeframes[] = {PERIOD_M15, PERIOD_H1, PERIOD_H4};

for(int tf = 0; tf < ArraySize(timeframes); tf++) {
double rsi = iRSI(Symbol(), timeframes[tf], 14, PRICE_CLOSE, 1);

if(rsi < 30) {
Print("Buy signal on timeframe ", timeframes[tf]);
OpenTrade(OP_BUY);
break; // Enter only one trade per bar
} else if(rsi > 70) {
Print("Sell signal on timeframe ", timeframes[tf]);
OpenTrade(OP_SELL);
break;
}
}
}

//+------------------------------------------------------------------+
//| Open a new trade |
//+------------------------------------------------------------------+
void OpenTrade(int orderType) {
double price = (orderType == OP_BUY) ? Ask : Bid;
int ticket = OrderSend(Symbol(), orderType, InpLotSize, price, 30, 0, 0, "Loops EA", InpMagic, 0, clrNONE);

if(ticket > 0) {
Print("Order opened: ", ticket);
} else {
Print("Order failed. Error: ", GetLastError());
}
}

//+------------------------------------------------------------------+
//| Manage grid orders using while loop |
//+------------------------------------------------------------------+
void ManageGridOrders() {
static double lastGridPrice = 0;

if(lastGridPrice == 0) {
lastGridPrice = Bid;
return;
}

double priceMovement = MathAbs(Bid - lastGridPrice) / Point();

while(priceMovement >= InpGridSpacing) {
if(Bid > lastGridPrice) {
// Price moved up - place sell order above
double sellPrice = lastGridPrice + InpGridSpacing * Point();
OrderSend(Symbol(), OP_SELL, InpLotSize * 0.5, sellPrice, 30, 0, 0, "Grid Sell", InpMagic, 0, clrNONE);
Print("Grid sell order at ", sellPrice);
} else {
// Price moved down - place buy order below
double buyPrice = lastGridPrice - InpGridSpacing * Point();
OrderSend(Symbol(), OP_BUY, InpLotSize * 0.5, buyPrice, 30, 0, 0, "Grid Buy", InpMagic, 0, clrNONE);
Print("Grid buy order at ", buyPrice);
}

lastGridPrice = Bid;
priceMovement -= InpGridSpacing;
}
}

//+------------------------------------------------------------------+
//| Close all orders using do-while loop (guaranteed at least one) |
//+------------------------------------------------------------------+
void CloseAllOrders() {
int attempts = 0;
int maxAttempts = 5;
int remainingOrders = 0;

do {
remainingOrders = 0;

for(int i = OrdersTotal() - 1; i >= 0; i--) {
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) {
if(OrderSymbol() == Symbol() && OrderMagicNumber() == InpMagic) {
bool closed = OrderClose(OrderTicket(), OrderLots(), OrderType() == OP_BUY ? Bid : Ask, 30, clrNONE);
if(!closed) {
remainingOrders++;
Print("Failed to close order ", OrderTicket());
}
}
}
}

attempts++;
if(remainingOrders > 0 && attempts < maxAttempts) {
Print("Retry closing ", remainingOrders, " orders. Attempt ", attempts);
Sleep(1000);
}

} while(remainingOrders > 0 && attempts < maxAttempts);

if(remainingOrders == 0) {
Print("All orders closed successfully");
} else {
Print("Failed to close ", remainingOrders, " orders after ", maxAttempts, " attempts");
}
}
```

Loop Performance Optimization Tips
| Issue | Problem | Solution |
|-------|---------|----------|
| Slow order processing | Large order counts | Process in reverse: for(int i=OrdersTotal()-1; i>=0; i--) |
| CPU overload | Infinite loops | Always include exit condition and Sleep() in while loops |
| Missed orders | Dynamic order count | Store total before loop: int total=OrdersTotal() |
| Stale data | Cache not refreshed | Re-select orders inside loop when modifying |
| Memory issues | Large arrays | Limit array size and use dynamic resizing |

Loop Best Practices Checklist
  • [ ] Use for loops when iteration count is known

  • [ ] Use while loops when condition determines continuation

  • [ ] Use do-while loops when code must execute at least once

  • [ ] Always include a termination condition to prevent infinite loops

  • [ ] Process orders in reverse order when deleting/modifying within loop

  • [ ] Store OrdersTotal() before loop to avoid dynamic changes

  • [ ] Use break to exit loops early when condition is met

  • [ ] Use continue to skip to next iteration

  • [ ] Avoid heavy calculations inside tight loops

  • [ ] Add Sleep() in while loops to prevent CPU overload


  • Reference:
  • MetaQuotes Ltd. "MQL4 Documentation - Loop Operators" (2024)

  • Kernighan, Brian W. "The C Programming Language" (1988)


  • 9. Next Step
    Part 10 will explain Functions in MQL4 - Definition and Calling – Creating custom functions, parameter passing, return values, and modular EA design with practical examples.