Trang chủ Kiến thức Kiểu Dữ Liệu Double trong MQL5: Làm Việc với Số Thực
Knowledge

Kiểu Dữ Liệu Double trong MQL5: Làm Việc với Số Thực

14 tháng 11, 2025

Hướng dẫn sử dụng kiểu double để xử lý giá cả, volume, và các phép tính thập phân chính xác trong trading.

Double: Kiểu Dữ Liệu Số Thực Chính Xác

double là kiểu dữ liệu floating-point 64-bit trong MQL5, có độ chính xác khoảng 15-17 chữ số thập phân. Đây là kiểu dữ liệu quan trọng nhất trong trading vì hầu hết giá cả, volume, và indicator values đều là số thực.

Khai Báo và Khởi Tạo

// Giá cả
double askPrice = 1.12345;
double bidPrice = 1.12340;

// Volume và lot size
double volume = 0.01;
double maxLot = 100.0;

// Indicator values
double maValue = 1.12300;
double rsiValue = 65.75;

// Percentage và ratios
double riskPercent = 2.0;
double rewardRatio = 3.0;

Độ Chính Xác và Digits

// Lấy số digits của symbol
int digits = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
Print("Digits: ", digits);  // Ví dụ: 5 (cho EURUSD)

// Normalize giá theo digits
double price = 1.123456789;
double normalizedPrice = NormalizeDouble(price, digits);
Print("Normalized: ", normalizedPrice);  // 1.12346

// Point value (thường = 0.00001 cho 5-digit broker)
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
Print("Point: ", point);  // 0.00001

So Sánh Double: Vấn Đề Độ Chính Xác

❌ SAI: So sánh trực tiếp

double a = 0.1 + 0.2;  // = 0.30000000000000004
double b = 0.3;
if(a == b)  // FALSE! (floating-point error)
    Print("Equal");

✅ ĐÚNG: So sánh với epsilon

double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.00001;  // Độ sai số cho phép

if(MathAbs(a - b) < epsilon)
    Print("Equal");  // TRUE

Ứng Dụng Thực Tế trong Trading

// Tính lot size dựa trên risk management
double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE);
double riskPercent = 2.0;  // 2%
int stopLossPips = 50;

double pipValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
double riskAmount = accountBalance * riskPercent / 100.0;
double lotSize = riskAmount / (stopLossPips * pipValue);
lotSize = NormalizeDouble(lotSize, 2);  // 0.01, 0.1, 1.0, etc.

// Kiểm tra lot size với giới hạn
double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);

if(lotSize < minLot) lotSize = minLot;
if(lotSize > maxLot) lotSize = maxLot;

// Tính profit/loss tiềm năng
double entryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double takeProfitPrice = entryPrice + 100 * point;
double potentialProfit = (takeProfitPrice - entryPrice) / point * lotSize * pipValue;
Print("Potential Profit: $", NormalizeDouble(potentialProfit, 2));

Các Hàm Toán Học Thường Dùng

double value = -123.456;

// Giá trị tuyệt đối
double absolute = MathAbs(value);  // 123.456

// Làm tròn
double rounded = MathRound(value);  // -123
double ceil = MathCeil(value);      // -123
double floor = MathFloor(value);    // -124

// Min/Max
double min = MathMin(100.5, 200.3);  // 100.5
double max = MathMax(100.5, 200.3);  // 200.3

// Căn bậc hai và lũy thừa
double sqrt = MathSqrt(16.0);        // 4.0
double power = MathPow(2.0, 3.0);    // 8.0

Working with Price Data

// Lấy giá hiện tại
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double spread = ask - bid;
int spreadPips = (int)((spread / point) + 0.5);

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

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

// Tính average true range
double atr = 0;
for(int i = 1; i < 14; i++) {
    double trueRange = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]);
    atr += trueRange;
}
atr = atr / 14.0;
Print("ATR(14): ", NormalizeDouble(atr, digits));

Best Practices

  • ✅ Luôn sử dụng NormalizeDouble() trước khi gửi order
  • ✅ So sánh double với epsilon thay vì dùng ==
  • ✅ Kiểm tra division by zero: if(divisor > 0.0001)
  • ✅ Sử dụng SymbolInfoDouble() để lấy thông tin symbol
  • ⛔ Tránh hardcode giá trị digits, luôn lấy từ symbol properties
  • ⛔ Không so sánh if(price == 0), dùng if(price < 0.000001)

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

  1. Viết hàm tính lot size với input: accountBalance, riskPercent, stopLossPips
  2. Tạo hàm kiểm tra xem giá hiện tại có nằm trong vùng ±50 pips của MA(50) không
  3. Viết code tính win rate từ mảng profit/loss: [50.5, -30.2, 100.0, -45.8, 75.3]

Tài Liệu Tham Khảo