Hướng dẫn chi tiết về if-else, if-else if, nested if và ứng dụng trong trading signal 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.
// 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 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 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();
}
}
// 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");
}
// 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";
// 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);
}
}
}
// && 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
}
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)
{} braces, ngay cả với single statement