Trang chủ Kiến thức Câu Lệnh IF-ELSE trong MQL5: Điều Kiện Logic Cơ Bản
Knowledge

Câu Lệnh IF-ELSE trong MQL5: Điều Kiện Logic Cơ Bản

14 tháng 11, 2025

Hướng dẫn chi tiết về if-else, if-else if, nested if và ứng dụng trong trading signal logic.

Câu Lệnh IF-ELSE: Điều Kiện Logic

if-else là cấu trúc điều khiển cơ bản nhất trong MQL5, cho phép thực thi code dựa trên điều kiện true/false. Đây là nền tảng cho mọi trading logic.

Cú Pháp Cơ Bản

// Simple if
int signal = CheckSignal();
if(signal == 1) {
    Print("Buy signal detected");
    OpenBuyOrder();
}

// if-else
double rsi = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
if(rsi > 70) {
    Print("Overbought - Consider selling");
} else {
    Print("Not overbought");
}

// if-else if-else (multiple conditions)
if(rsi > 70) {
    Print("Overbought");
} else if(rsi < 30) {
    Print("Oversold");
} else {
    Print("Neutral zone");
}

Single-Line IF (Without Braces)

// ⚠️ Single statement - no braces needed (but not recommended)
if(signal == 1)
    Print("Signal detected");

// ✅ Better: Always use braces for clarity
if(signal == 1) {
    Print("Signal detected");
}

// ❌ ERROR: Multiple statements without braces
if(signal == 1)
    Print("Signal detected");
    OpenOrder();  // This ALWAYS executes! (not part of if)

// ✅ CORRECT: Use braces for multiple statements
if(signal == 1) {
    Print("Signal detected");
    OpenOrder();
}

Nested IF Statements

// Nested conditions for complex trading logic
void CheckTradingConditions() {
    // Level 1: Check spread
    int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    if(spread <= 20) {  // Max 2 pips
        
        // Level 2: Check time
        MqlDateTime timeStruct;
        TimeToStruct(TimeCurrent(), timeStruct);
        if(timeStruct.hour >= 8 && timeStruct.hour < 17) {
            
            // Level 3: Check balance
            double balance = AccountInfoDouble(ACCOUNT_BALANCE);
            if(balance >= 1000.0) {
                
                // Level 4: Check signal
                int signal = CheckSignal();
                if(signal == 1) {
                    Print("All conditions met - Opening BUY order");
                    OpenBuyOrder();
                } else if(signal == -1) {
                    Print("All conditions met - Opening SELL order");
                    OpenSellOrder();
                }
            } else {
                Print("Insufficient balance");
            }
        } else {
            Print("Outside trading hours");
        }
    } else {
        Print("Spread too high");
    }
}

// ✅ Better: Flatten nested ifs with early returns
void CheckTradingConditions_Better() {
    // Check 1: Spread
    int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    if(spread > 20) {
        Print("Spread too high");
        return;
    }
    
    // Check 2: Time
    MqlDateTime timeStruct;
    TimeToStruct(TimeCurrent(), timeStruct);
    if(timeStruct.hour < 8 || timeStruct.hour >= 17) {
        Print("Outside trading hours");
        return;
    }
    
    // Check 3: Balance
    double balance = AccountInfoDouble(ACCOUNT_BALANCE);
    if(balance < 1000.0) {
        Print("Insufficient balance");
        return;
    }
    
    // Check 4: Signal
    int signal = CheckSignal();
    if(signal == 1) {
        OpenBuyOrder();
    } else if(signal == -1) {
        OpenSellOrder();
    }
}

Compound Conditions with && and ||

// AND operator (&&) - All conditions must be true
double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double ma50 = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
double ma200 = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE);

// Golden cross: MA50 > MA200 AND Price > MA50
if(ma50 > ma200 && price > ma50) {
    Print("Strong bullish signal");
    OpenBuyOrder();
}

// OR operator (||) - At least one condition must be true
int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
int totalOrders = PositionsTotal();

// Stop if spread too high OR max orders reached
if(spread > 30 || totalOrders >= 5) {
    Print("Cannot open new orders");
    return;
}

// Complex combination
double rsi = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
double balance = AccountInfoDouble(ACCOUNT_BALANCE);
double equity = AccountInfoDouble(ACCOUNT_EQUITY);
double drawdown = (balance - equity) / balance * 100.0;

// Buy signal: (RSI < 30 OR Price < MA50) AND Drawdown < 10%
if((rsi < 30 || price < ma50) && drawdown < 10.0) {
    Print("Buy opportunity with acceptable risk");
}

Ternary Operator (?:) - Inline IF

// Syntax: condition ? value_if_true : value_if_false

// Simple example
int signal = 1;
string action = (signal == 1) ? "BUY" : "SELL";
Print("Action: ", action);  // "BUY"

// With calculations
double lotSize = (balance > 10000) ? 0.1 : 0.01;

// Nested ternary (not recommended - hard to read)
string signalType = (signal == 1) ? "BUY" : 
                    (signal == -1) ? "SELL" : "NONE";

// ✅ Better: Use if-else for complex cases
string signalType2;
if(signal == 1) {
    signalType2 = "BUY";
} else if(signal == -1) {
    signalType2 = "SELL";
} else {
    signalType2 = "NONE";
}

// Practical use: Avoid division by zero
int divisor = 0;
double result = (divisor != 0) ? (100.0 / divisor) : 0.0;

// Determine order type string
ENUM_ORDER_TYPE orderType = ORDER_TYPE_BUY;
string typeStr = (orderType == ORDER_TYPE_BUY) ? "Buy" : "Sell";

Ứng Dụng Thực Tế: Trading Signal Logic

// Enum for signal types
enum ENUM_TRADE_SIGNAL {
    SIGNAL_NONE = 0,
    SIGNAL_BUY = 1,
    SIGNAL_SELL = -1
};

// Check RSI + MA crossover signal
ENUM_TRADE_SIGNAL CheckRSI_MA_Signal() {
    // Get indicators
    double rsi = iRSI(_Symbol, PERIOD_CURRENT, 14, PRICE_CLOSE);
    double ma50 = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
    double ma200 = iMA(_Symbol, PERIOD_CURRENT, 200, 0, MODE_SMA, PRICE_CLOSE);
    double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
    
    // Buy conditions
    if(rsi < 30 && ma50 > ma200 && price > ma50) {
        return SIGNAL_BUY;
    }
    
    // Sell conditions
    if(rsi > 70 && ma50 < ma200 && price < ma50) {
        return SIGNAL_SELL;
    }
    
    return SIGNAL_NONE;
}

// Risk management checks
bool IsRiskAcceptable() {
    double balance = AccountInfoDouble(ACCOUNT_BALANCE);
    double equity = AccountInfoDouble(ACCOUNT_EQUITY);
    
    // Check minimum balance
    if(balance < 500.0) {
        Print("Balance too low");
        return false;
    }
    
    // Check drawdown
    double drawdownPercent = ((balance - equity) / balance) * 100.0;
    if(drawdownPercent > 20.0) {
        Print("Drawdown limit exceeded: ", drawdownPercent, "%");
        return false;
    }
    
    // Check max orders
    int totalOrders = PositionsTotal();
    if(totalOrders >= 5) {
        Print("Max orders limit reached");
        return false;
    }
    
    return true;
}

// Main trading logic
void OnTick() {
    // Early exit if risk not acceptable
    if(!IsRiskAcceptable()) {
        return;
    }
    
    // Check spread
    int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
    if(spread > 20) {
        return;  // Spread too high
    }
    
    // Get signal
    ENUM_TRADE_SIGNAL signal = CheckRSI_MA_Signal();
    
    // Execute based on signal
    if(signal == SIGNAL_BUY) {
        // Check if no buy positions exist
        int buyOrders = CountOrdersByType(ORDER_TYPE_BUY);
        if(buyOrders == 0) {
            Print("Opening BUY order");
            OpenOrder(ORDER_TYPE_BUY);
        }
    } else if(signal == SIGNAL_SELL) {
        // Check if no sell positions exist
        int sellOrders = CountOrdersByType(ORDER_TYPE_SELL);
        if(sellOrders == 0) {
            Print("Opening SELL order");
            OpenOrder(ORDER_TYPE_SELL);
        }
    }
}

Short-Circuit Evaluation

// && stops at first false
bool condition1 = false;
bool condition2 = true;

// condition2 is NOT evaluated (short-circuit)
if(condition1 && condition2) {
    Print("Both true");
}

// Practical use: Avoid unnecessary calculations
double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double ma50 = 0;

// MA50 only calculated if price check passes
if(price > 1.10000 && (ma50 = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE)) > 1.09000) {
    Print("Both conditions met");
}

// || stops at first true
int totalOrders = PositionsTotal();
int spread = (int)SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);

// spread check skipped if totalOrders already >= 5
if(totalOrders >= 5 || spread > 30) {
    return;  // Exit early
}

Common Mistakes

Lỗi 1: Assignment instead of comparison

❌ if(signal = 1)  // Assignment! Always true
✅ if(signal == 1) // Comparison

Lỗi 2: Forgetting braces with multiple statements

❌ if(signal == 1)
    Print("Signal");
    OpenOrder();  // Always executes!

✅ if(signal == 1) {
    Print("Signal");
    OpenOrder();
}

Lỗi 3: Comparing double with ==

❌ if(price == 1.12345)  // Floating-point error
✅ if(MathAbs(price - 1.12345) < 0.00001)

Best Practices

  • ✅ Luôn sử dụng {} braces, ngay cả với single statement
  • ✅ Use early returns để giảm nested ifs
  • ✅ Đặt điều kiện phổ biến nhất lên đầu (performance)
  • ✅ Sử dụng enum cho signals rõ ràng hơn magic numbers
  • ✅ Tách logic phức tạp thành functions riêng
  • ⛔ Tránh nested if quá sâu (>3 levels)
  • ⛔ Không dùng ternary operator cho logic phức tạp

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

  1. Viết hàm kiểm tra: Price nằm trong Bollinger Bands không?
  2. Tạo logic: Nếu RSI < 30 và Stochastic < 20 → BUY signal
  3. Implement risk filter: Stop trading nếu daily loss > 5%

Tài Liệu Tham Khảo