Trang chủ Kiến thức OrderSend() - Gửi Lệnh Giao Dịch trong MQL5
Knowledge

OrderSend() - Gửi Lệnh Giao Dịch trong MQL5

14 tháng 11, 2025

Hướng dẫn chi tiết về hàm OrderSend() để thực hiện các lệnh giao dịch, từ cơ bản đến nâng cao với ví dụ thực tế.

Giới thiệu về OrderSend()

Hàm OrderSend() là một trong những hàm quan trọng nhất trong MQL5, được sử dụng để gửi các yêu cầu giao dịch đến máy chủ giao dịch. Đây là hàm cốt lõi mà mọi Expert Advisor đều cần sử dụng để mở, đóng hoặc sửa đổi các vị thế giao dịch.

Cú pháp

bool OrderSend(
   MqlTradeRequest&  request,      // cấu trúc yêu cầu
   MqlTradeResult&   result        // cấu trúc kết quả
);

Cấu trúc MqlTradeRequest

Để sử dụng OrderSend(), bạn cần khởi tạo cấu trúc MqlTradeRequest với các thông tin sau:

  • action - Loại thao tác giao dịch (TRADE_ACTION_DEAL, TRADE_ACTION_PENDING, etc.)
  • symbol - Tên cặp tiền tệ
  • volume - Khối lượng giao dịch (lots)
  • price - Giá mở lệnh
  • sl - Stop Loss
  • tp - Take Profit
  • type - Loại lệnh (ORDER_TYPE_BUY, ORDER_TYPE_SELL, etc.)
  • type_filling - Chế độ khớp lệnh
  • magic - Magic Number để nhận diện EA
  • comment - Ghi chú cho lệnh

Ví dụ 1: Mở Lệnh Buy Market

//+------------------------------------------------------------------+
//| Mở lệnh Buy với Stop Loss và Take Profit                        |
//+------------------------------------------------------------------+
bool OpenBuyPosition(string symbol, double volume, double sl_points, double tp_points)
{
   MqlTradeRequest request;
   MqlTradeResult result;

   // Reset cấu trúc
   ZeroMemory(request);
   ZeroMemory(result);

   // Lấy thông tin symbol
   double ask = SymbolInfoDouble(symbol, SYMBOL_ASK);
   double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);

   // Tính toán SL và TP
   double sl = NormalizeDouble(ask - sl_points * point, digits);
   double tp = NormalizeDouble(ask + tp_points * point, digits);

   // Thiết lập yêu cầu
   request.action = TRADE_ACTION_DEAL;        // Giao dịch ngay
   request.symbol = symbol;                    // Symbol
   request.volume = volume;                    // Khối lượng
   request.type = ORDER_TYPE_BUY;             // Lệnh Buy
   request.price = ask;                        // Giá Ask hiện tại
   request.sl = sl;                           // Stop Loss
   request.tp = tp;                           // Take Profit
   request.deviation = 10;                     // Độ trượt giá cho phép (points)
   request.magic = 123456;                     // Magic number
   request.comment = "Buy Order";              // Comment
   request.type_filling = ORDER_FILLING_FOK;   // Fill or Kill

   // Gửi lệnh
   if(!OrderSend(request, result))
   {
      Print("OrderSend error: ", GetLastError());
      Print("Result retcode: ", result.retcode);
      return false;
   }

   // Kiểm tra kết quả
   if(result.retcode == TRADE_RETCODE_DONE ||
      result.retcode == TRADE_RETCODE_PLACED)
   {
      Print("Buy order opened successfully!");
      Print("Order ticket: ", result.order);
      Print("Volume: ", result.volume);
      Print("Price: ", result.price);
      return true;
   }
   else
   {
      Print("Order failed! Return code: ", result.retcode);
      return false;
   }
}

//+------------------------------------------------------------------+
//| Sử dụng trong OnTick()                                          |
//+------------------------------------------------------------------+
void OnTick()
{
   static bool position_opened = false;

   if(!position_opened)
   {
      if(OpenBuyPosition(_Symbol, 0.1, 500, 1000))
      {
         position_opened = true;
      }
   }
}

Ví dụ 2: Mở Lệnh Sell Market

//+------------------------------------------------------------------+
//| Mở lệnh Sell với quản lý rủi ro                                 |
//+------------------------------------------------------------------+
bool OpenSellPosition(string symbol, double volume)
{
   MqlTradeRequest request;
   MqlTradeResult result;

   ZeroMemory(request);
   ZeroMemory(result);

   double bid = SymbolInfoDouble(symbol, SYMBOL_BID);
   double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);

   // SL và TP tính toán dựa trên ATR
   double sl = NormalizeDouble(bid + 500 * point, digits);
   double tp = NormalizeDouble(bid - 1000 * point, digits);

   request.action = TRADE_ACTION_DEAL;
   request.symbol = symbol;
   request.volume = volume;
   request.type = ORDER_TYPE_SELL;
   request.price = bid;
   request.sl = sl;
   request.tp = tp;
   request.deviation = 10;
   request.magic = 123456;
   request.comment = "Sell Order";
   request.type_filling = ORDER_FILLING_FOK;

   if(!OrderSend(request, result))
   {
      Print("OrderSend error: ", GetLastError());
      return false;
   }

   if(result.retcode == TRADE_RETCODE_DONE)
   {
      Print("Sell order opened at price: ", result.price);
      return true;
   }

   return false;
}

Ví dụ 3: Đặt Lệnh Pending (Buy Stop)

//+------------------------------------------------------------------+
//| Đặt lệnh Buy Stop                                               |
//+------------------------------------------------------------------+
bool PlaceBuyStopOrder(string symbol, double volume, double entry_price)
{
   MqlTradeRequest request;
   MqlTradeResult result;

   ZeroMemory(request);
   ZeroMemory(result);

   double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
   int digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);

   // Tính SL và TP từ entry price
   double sl = NormalizeDouble(entry_price - 500 * point, digits);
   double tp = NormalizeDouble(entry_price + 1000 * point, digits);

   request.action = TRADE_ACTION_PENDING;      // Lệnh chờ
   request.symbol = symbol;
   request.volume = volume;
   request.type = ORDER_TYPE_BUY_STOP;        // Buy Stop
   request.price = NormalizeDouble(entry_price, digits);
   request.sl = sl;
   request.tp = tp;
   request.magic = 123456;
   request.comment = "Buy Stop Order";
   request.type_time = ORDER_TIME_GTC;        // Good Till Cancel
   request.type_filling = ORDER_FILLING_RETURN;

   if(!OrderSend(request, result))
   {
      Print("Failed to place Buy Stop: ", GetLastError());
      return false;
   }

   if(result.retcode == TRADE_RETCODE_DONE ||
      result.retcode == TRADE_RETCODE_PLACED)
   {
      Print("Buy Stop placed successfully at: ", entry_price);
      Print("Order ticket: ", result.order);
      return true;
   }

   return false;
}

Các Mã Lỗi Thường Gặp

Mã Lỗi Tên Mô Tả Giải Pháp
10004 TRADE_RETCODE_REQUOTE Giá đã thay đổi Thử lại với giá mới
10006 TRADE_RETCODE_REJECT Yêu cầu bị từ chối Kiểm tra thông số giao dịch
10013 TRADE_RETCODE_INVALID_VOLUME Khối lượng không hợp lệ Điều chỉnh volume theo bội số lot step
10014 TRADE_RETCODE_INVALID_PRICE Giá không hợp lệ Normalize giá theo digits
10015 TRADE_RETCODE_INVALID_STOPS SL/TP không hợp lệ Kiểm tra SYMBOL_TRADE_STOPS_LEVEL

Best Practices

  1. Luôn kiểm tra giá trị trả về: OrderSend() trả về true không có nghĩa lệnh thành công. Phải kiểm tra result.retcode.
  2. Normalize giá trị: Sử dụng NormalizeDouble() cho price, SL, TP.
  3. Kiểm tra điều kiện symbol: Verify symbol is available và trading is allowed.
  4. Quản lý lỗi: Implement retry logic cho các lỗi tạm thời như REQUOTE.
  5. Validate volume: Đảm bảo volume nằm trong SYMBOL_VOLUME_MIN và SYMBOL_VOLUME_MAX.
  6. Sử dụng Magic Number: Để phân biệt các lệnh của EA khác nhau.
  7. Log đầy đủ: Print thông tin chi tiết khi có lỗi.

Kiểm Tra Trước Khi Gửi Lệnh

//+------------------------------------------------------------------+
//| Kiểm tra điều kiện trước khi OrderSend                          |
//+------------------------------------------------------------------+
bool CheckTradeConditions(string symbol)
{
   // Kiểm tra trading allowed
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
   {
      Print("Trading not allowed in terminal");
      return false;
   }

   // Kiểm tra expert advisor allowed
   if(!MQLInfoInteger(MQL_TRADE_ALLOWED))
   {
      Print("EA trading not allowed");
      return false;
   }

   // Kiểm tra symbol trading allowed
   if(!SymbolInfoInteger(symbol, SYMBOL_TRADE_MODE))
   {
      Print("Trading disabled for symbol: ", symbol);
      return false;
   }

   // Kiểm tra đủ margin
   double free_margin = AccountInfoDouble(ACCOUNT_MARGIN_FREE);
   if(free_margin < 100)  // Minimum margin requirement
   {
      Print("Not enough free margin: ", free_margin);
      return false;
   }

   return true;
}

Kết Luận

OrderSend() là hàm nền tảng trong giao dịch tự động với MQL5. Hiểu rõ cách sử dụng đúng hàm này, kết hợp với xử lý lỗi hợp lý và kiểm tra điều kiện kỹ lưỡng sẽ giúp EA của bạn hoạt động ổn định và hiệu quả.

Lưu ý quan trọng: Luôn test EA trên tài khoản demo trước khi sử dụng với tài khoản thật. OrderSend() trực tiếp tác động đến tài khoản giao dịch của bạn.