Trang chủ Kiến thức Vòng Lặp FOR trong MQL5: Xử Lý Dữ Liệu Lặp Đi Lặp Lại
Knowledge

Vòng Lặp FOR trong MQL5: Xử Lý Dữ Liệu Lặp Đi Lặp Lại

14 tháng 11, 2025

Học cách sử dụng for loop để duyệt mảng, xử lý bars, tính toán indicators và optimize performance.

Vòng Lặp FOR Loop

for là vòng lặp phổ biến nhất trong MQL5, được sử dụng khi biết trước số lần lặp. Rất hữu ích cho việc duyệt mảng, xử lý historical bars, và tính toán indicators.

Cú Pháp Cơ Bản

// Syntax: for(initialization; condition; increment)

// Simple counting loop
for(int i = 0; i < 10; i++) {
    Print("Iteration: ", i);  // 0, 1, 2, ..., 9
}

// Counting backward
for(int i = 10; i > 0; i--) {
    Print("Countdown: ", i);  // 10, 9, 8, ..., 1
}

// Increment by 2
for(int i = 0; i < 100; i += 2) {
    Print("Even number: ", i);  // 0, 2, 4, ..., 98
}

// Multiple variables (comma operator)
for(int i = 0, j = 10; i < 10; i++, j--) {
    Print("i=", i, " j=", j);
}

Duyệt Mảng (Array Iteration)

// Array of prices
double prices[] = {1.12345, 1.12445, 1.12545, 1.12645, 1.12745};

// Loop through array
for(int i = 0; i < ArraySize(prices); i++) {
    Print("Price[", i, "] = ", prices[i]);
}

// Calculate sum and average
double sum = 0;
for(int i = 0; i < ArraySize(prices); i++) {
    sum += prices[i];
}
double average = sum / ArraySize(prices);
Print("Average price: ", average);

// Find maximum value
double maxPrice = prices[0];
for(int i = 1; i < ArraySize(prices); i++) {
    if(prices[i] > maxPrice) {
        maxPrice = prices[i];
    }
}
Print("Maximum price: ", maxPrice);

// Find minimum with index
double minPrice = prices[0];
int minIndex = 0;
for(int i = 1; i < ArraySize(prices); i++) {
    if(prices[i] < minPrice) {
        minPrice = prices[i];
        minIndex = i;
    }
}
Print("Minimum price: ", minPrice, " at index: ", minIndex);

Xử Lý Historical Bars

// Copy bar data
double high[], low[], close[];
ArraySetAsSeries(high, true);
ArraySetAsSeries(low, true);
ArraySetAsSeries(close, true);

int bars = 100;
CopyHigh(_Symbol, PERIOD_CURRENT, 0, bars, high);
CopyLow(_Symbol, PERIOD_CURRENT, 0, bars, low);
CopyClose(_Symbol, PERIOD_CURRENT, 0, bars, close);

// Loop through bars to calculate custom indicator
double indicator[];
ArrayResize(indicator, bars);
ArraySetAsSeries(indicator, true);

for(int i = 0; i < bars; i++) {
    // Calculate true range
    double tr = high[i] - low[i];
    indicator[i] = tr;
}

// Calculate moving average of true range (ATR-like)
int period = 14;
double atr[];
ArrayResize(atr, bars);
ArraySetAsSeries(atr, true);

for(int i = 0; i < bars - period + 1; i++) {
    double sum = 0;
    for(int j = 0; j < period; j++) {
        sum += indicator[i + j];
    }
    atr[i] = sum / period;
}

Print("ATR[0] = ", atr[0]);

Nested Loops (Vòng Lặp Lồng Nhau)

// 2D array processing
double matrix[5][5];

// Fill matrix
for(int row = 0; row < 5; row++) {
    for(int col = 0; col < 5; col++) {
        matrix[row][col] = row * 10 + col;
    }
}

// Print matrix
for(int row = 0; row < 5; row++) {
    string rowStr = "";
    for(int col = 0; col < 5; col++) {
        rowStr += DoubleToString(matrix[row][col], 0) + " ";
    }
    Print("Row ", row, ": ", rowStr);
}

// Find pattern in bars
int signalCount = 0;
for(int i = 0; i < bars - 3; i++) {
    // Check for 3 consecutive bullish candles
    bool pattern = true;
    for(int j = 0; j < 3; j++) {
        if(close[i + j] <= close[i + j + 1]) {
            pattern = false;
            break;
        }
    }
    if(pattern) {
        signalCount++;
        Print("Pattern found at bar: ", i);
    }
}

Break và Continue Statements

// BREAK: Exit loop immediately
for(int i = 0; i < 100; i++) {
    if(i == 50) {
        Print("Breaking at: ", i);
        break;  // Stop loop
    }
    Print(i);
}

// Find first bullish candle
for(int i = 0; i < bars; i++) {
    if(close[i] > close[i + 1]) {
        Print("First bullish candle at bar: ", i);
        break;  // Found it, stop searching
    }
}

// CONTINUE: Skip current iteration
for(int i = 0; i < 20; i++) {
    if(i % 2 == 0) {
        continue;  // Skip even numbers
    }
    Print("Odd number: ", i);
}

// Process only closed positions
for(int i = PositionsTotal() - 1; i >= 0; i--) {
    ulong ticket = PositionGetTicket(i);
    if(ticket == 0) continue;  // Skip if ticket invalid
    
    double profit = PositionGetDouble(POSITION_PROFIT);
    if(profit <= 0) continue;  // Skip losing positions
    
    Print("Profitable position: ", ticket, " Profit: $", profit);
}

Performance Optimization

// ❌ SLOW: Calculate ArraySize() every iteration
for(int i = 0; i < ArraySize(prices); i++) {
    // Process prices[i]
}

// ✅ FAST: Cache array size
int size = ArraySize(prices);
for(int i = 0; i < size; i++) {
    // Process prices[i]
}

// ❌ SLOW: Call function in condition
for(int i = 0; i < PositionsTotal(); i++) {
    // PositionsTotal() called every iteration!
}

// ✅ FAST: Cache result
int total = PositionsTotal();
for(int i = 0; i < total; i++) {
    // Much faster
}

// ❌ SLOW: Nested loops with large arrays
for(int i = 0; i < 1000; i++) {
    for(int j = 0; j < 1000; j++) {
        // 1,000,000 iterations!
    }
}

// ✅ BETTER: Reduce iterations where possible
for(int i = 0; i < 1000; i++) {
    for(int j = i + 1; j < 1000; j++) {
        // ~500,000 iterations (half)
    }
}

Ứng Dụng Thực Tế: Close Positions

// Close all losing positions
void CloseLosingPositions() {
    // ⚠️ Important: Loop backward when closing positions
    // (closing changes array indices)
    for(int i = PositionsTotal() - 1; i >= 0; i--) {
        ulong ticket = PositionGetTicket(i);
        if(ticket == 0) continue;
        
        // Check if position belongs to this EA
        long magic = PositionGetInteger(POSITION_MAGIC);
        if(magic != EA_MAGIC) continue;
        
        // Check profit
        double profit = PositionGetDouble(POSITION_PROFIT);
        if(profit >= 0) continue;  // Skip profitable positions
        
        // Close losing position
        MqlTradeRequest request = {};
        MqlTradeResult result = {};
        
        request.action = TRADE_ACTION_DEAL;
        request.position = ticket;
        request.symbol = PositionGetString(POSITION_SYMBOL);
        request.volume = PositionGetDouble(POSITION_VOLUME);
        request.type = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? 
                       ORDER_TYPE_SELL : ORDER_TYPE_BUY;
        request.price = (request.type == ORDER_TYPE_SELL) ? 
                        SymbolInfoDouble(_Symbol, SYMBOL_BID) : 
                        SymbolInfoDouble(_Symbol, SYMBOL_ASK);
        request.deviation = 10;
        
        if(OrderSend(request, result)) {
            Print("Closed losing position #", ticket);
        }
    }
}

// Count orders by type
int CountOrdersByType(ENUM_ORDER_TYPE type) {
    int count = 0;
    int total = PositionsTotal();
    
    for(int i = 0; i < total; i++) {
        ulong ticket = PositionGetTicket(i);
        if(ticket == 0) continue;
        
        if(PositionGetInteger(POSITION_TYPE) == type) {
            count++;
        }
    }
    
    return count;
}

// Calculate total profit
double CalculateTotalProfit() {
    double totalProfit = 0;
    int total = PositionsTotal();
    
    for(int i = 0; i < total; i++) {
        ulong ticket = PositionGetTicket(i);
        if(ticket == 0) continue;
        
        long magic = PositionGetInteger(POSITION_MAGIC);
        if(magic != EA_MAGIC) continue;
        
        totalProfit += PositionGetDouble(POSITION_PROFIT);
    }
    
    return totalProfit;
}

Infinite Loop Protection

// ⚠️ DANGER: Infinite loop
for(int i = 0; i < 10; i--) {  // Decrementing instead of incrementing!
    // This will run forever!
}

// ✅ SAFE: Add safety counter
int maxIterations = 10000;
int counter = 0;
for(int i = 0; i < someCondition; i++) {
    counter++;
    if(counter > maxIterations) {
        Print("Max iterations reached - breaking loop");
        break;
    }
    // Your logic here
}

// ✅ SAFE: Use while with timeout
datetime startTime = GetTickCount();
int timeout = 1000;  // 1 second
while(someCondition) {
    if(GetTickCount() - startTime > timeout) {
        Print("Timeout - breaking loop");
        break;
    }
    // Your logic here
}

Best Practices

  • ✅ Cache ArraySize()PositionsTotal() trước loop
  • ✅ Loop backward khi closing positions: i--
  • ✅ Sử dụng break khi tìm thấy kết quả
  • ✅ Sử dụng continue để skip invalid data
  • ✅ Kiểm tra bounds: i < size
  • ⛔ Tránh modify array size trong loop
  • ⛔ Không tạo infinite loops
  • ⛔ Tránh nested loops với số lần lặp lớn

Bài Tập Thực Hành

  1. Viết loop tính sum của 100 close prices gần nhất
  2. Tạo hàm đếm số lần RSI cross 50 trong 200 bars
  3. Implement loop để tìm highest high trong 50 bars

Tài Liệu Tham Khảo