Trang chủ > Blog > Lỗi Invalid stops (10016/130) — SL trên MT5/MT4

MT5MQL5LỗiXử lý sự cốEA

Lỗi Invalid stops (10016/130) — SL trên MT5/MT4

Đăng: 2026-07-07Thời gian đọc: khoảng 10 phút
This article reflects information as of its publish date. EA performance figures (PF, DD, annual return) change with live trading and re-validation — check the latest on the EA pages. See the latest EA results

Mục lục

  1. Invalid stops là gì (Sự khác biệt giữa 10016 và 130)
  2. ① TRADE_RETCODE_INVALID_STOPS = 10016 (MT5 / mã trả về của `OrderSend()`)
  3. ② ERR_INVALID_STOPS = 130 (MT4 / `GetLastError()`)
  4. Chẩn đoán nhanh trong 30 giây
  5. Nguyên nhân và cách xử lý (6 kiểu)
  6. ① SL/TP quá gần giá hiện tại (nhỏ hơn Stops Level)
  7. ② Đặt sai hướng SL/TP (nhầm lẫn giữa BUY/SELL)
  8. ③ Sửa lệnh hoặc thay đổi vị thế trong vùng Freeze Level
  9. ④ Nhầm lẫn giữa giá và điểm (khoảng cách - point)
  10. ⑤ Broker thực thi lệnh thị trường không cho phép đặt SL/TP ngay khi mở lệnh
  11. ⑥ Đặc thù riêng của từng symbol (vàng, chỉ số có Stops Level lớn)
  12. Sự khác biệt giữa các broker (lưu ý)
  13. Code MQL5 để phòng tránh lỗi này (dành cho lập trình viên EA)
  14. Kiểm tra và clamp SL/TP trước khi gửi lệnh
  15. Xử lý riêng mã retcode 10016
  16. Kiểm tra Freeze Level trước khi sửa trailing
  17. Danh sách kiểm tra theo mức độ ưu tiên
  18. Tổng kết
  19. Câu hỏi thường gặp (FAQ)
  20. Hỏi: Tôi chắc chắn phép tính SL/TP của mình đúng, nhưng vẫn bị Invalid stops. Tại sao?
  21. Hỏi: 10016 và 130 khác nhau ở điểm nào?
  22. Hỏi: Bình thường không sao, nhưng chỉ khi có tin tức mới bị Invalid stops.
  23. Hỏi: Nếu không có SL/TP thì lệnh khớp bình thường, nhưng có kèm SL/TP thì bị từ chối.
  24. Hỏi: EA hoạt động bình thường trên EURUSD nhưng liên tục bị Invalid stops trên vàng.

Giải quyết triệt để lỗi Invalid stops (10016/130)

Khi chạy EA, nếu tab Expert hiện ra Invalid stops hoặc OrderSend error 130, nhiều người sẽ hoang mang nghĩ rằng "giá trị SL có vấn đề gì đó? Nhưng phép tính chắc chắn đúng mà…". Tuy nhiên, phần lớn lỗi này không phải do tính sai SL/TP, mà là vi phạm "quy tắc khoảng cách tối thiểu" do broker quy định. Ngay cả khi giá trị hoàn toàn chính xác, lệnh vẫn có thể bị từ chối vì một trong ba lý do: quá gần giá hiện tại, đặt sai hướng, hoặc rơi vào vùng cấm sửa đổi.

Bài viết này dành cho cả những người dùng EA trên MT5/MT4 lẫn những người viết EA bằng MQL5, tổng hợp toàn diện về bản chất của lỗi Invalid stops, 6 nguyên nhân, cách chẩn đoán trong 30 giây, và giải pháp phòng ngừa vĩnh viễn ở phía code. Để xem danh sách đầy đủ các mã lỗi, hãy tham khảo Hướng dẫn tổng hợp xử lý mã lỗi MQL5 / MT5.

Bài viết này dựa trên nền tảng MT5 (dòng build 4xxx) tính đến tháng 7 năm 2026. Giá trị Stops Level cụ thể sẽ khác nhau tùy theo broker và từng cặp giao dịch.


Invalid stops là gì (Sự khác biệt giữa 10016 và 130)

Giá trị biểu thị "stop không hợp lệ" có 2 loại tùy theo MT5 và MT4 (thế hệ nền tảng). Việc phân biệt lỗi xuất hiện trên nền tảng nào, ở giai đoạn nào sẽ giúp việc tìm ra nguyên nhân nhanh hơn rất nhiều.

① TRADE_RETCODE_INVALID_STOPS = 10016 (MT5 / mã trả về của OrderSend())

Kết quả của hàm OrderSend() trong MQL5 được lưu trong MqlTradeResult.retcode. Nếu SL/TP trong yêu cầu (hoặc mối quan hệ với giá của lệnh chờ) không phù hợp với quy tắc của server, lệnh sẽ bị từ chối với mã 10016 (TRADE_RETCODE_INVALID_STOPS). Đây là thông báo từ chối từ phía server giao dịch.

Ý nghĩa: Stop (SL/TP) trong yêu cầu không hợp lệ (Invalid stops in the request)
Hằng số: TRADE_RETCODE_INVALID_STOPS
Giá trị: 10016
// Ví dụ log điển hình có thể thấy
2026.07.07 09:15:32.441 EA_NAME XAUUSD,M5: OrderSend error: retcode=10016 (invalid stops)

② ERR_INVALID_STOPS = 130 (MT4 / GetLastError())

Ở thế hệ MT4 (MQL4), khi OrderSend() / OrderModify() thất bại, hàm GetLastError() sẽ trả về 130 (ERR_INVALID_STOPS). Đây chính là OrderSend error 130 xuất hiện trên tab Expert. Nếu bạn đang dùng song song EA phiên bản MT4, đây là lỗi bạn sẽ gặp.

Ý nghĩa: Stop không hợp lệ (invalid stops)
Hằng số: ERR_INVALID_STOPS
Giá trị: 130

Cách phân biệt trong thực tế:

Nền tảngNguồn lấyGiá trịTrường hợp xuất hiện
MT5MqlTradeResult.retcode10016 (TRADE_RETCODE_INVALID_STOPS)OrderSend / PositionModify bị server từ chối
MT5CTrade.ResultRetcode()10016Đặt lệnh/sửa lệnh bị từ chối qua CTrade
MT4GetLastError()130 (ERR_INVALID_STOPS)Sau khi OrderSend / OrderModify thất bại

Tuy số hiệu khác nhau nhưng ý nghĩa và nguyên nhân gần như giống hệt nhau, cách xử lý cũng chung. Lưu ý, mã 10015 (TRADE_RETCODE_INVALID_PRICE) trên MT5 thường bị nhầm lẫn với lỗi này nhưng thực chất là "bản thân giá đặt lệnh không hợp lệ" – một vấn đề hoàn toàn khác. Lỗi 10016 chỉ liên quan đến "vị trí của SL/TP (stop)".


Chẩn đoán nhanh trong 30 giây

Mở "Market Watch → chuột phải vào symbol → Specification" trên MT5 và xem 2 mục sau.

Stops level (Mức stop)   : Khoảng cách tối thiểu (tính bằng điểm/point) mà SL/TP phải cách giá hiện tại
Freeze level (Mức đóng băng)  : Khoảng cách (điểm/point) mà trong phạm vi đó việc sửa/hủy lệnh sắp khớp bị cấm

Sau đó, hãy đối chiếu giá trị SL/TP định gửi và Bid/Ask hiện tại ngay tại thời điểm lỗi xảy ra trong log.

  • SL hoặc TP có khoảng cách với giá hiện tại nhỏ hơn Stops Level → gần như chắc chắn là nguyên nhân này (Nguyên nhân ①).
  • Lệnh BUY nhưng SL cao hơn Bid / TP thấp hơn Bid (ngược lại với SELL) → đặt sai hướng (Nguyên nhân ②).
  • Chỉ sửa lệnh của vị thế đang giữ mới thất bại → do Freeze Level hoặc do quy định đặt SL/TP sau (Nguyên nhân ③ · ⑤).
  • Giá trị SL là con số rõ ràng không phải là giá, ví dụ "50" → nhầm lẫn giữa giá và điểm (point) (Nguyên nhân ④).

Nếu muốn kiểm tra từ code, chỉ cần 1 dòng.

Print("StopsLevel=", SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL),
      " FreezeLevel=", SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL));

Nguyên nhân và cách xử lý (6 kiểu)

① SL/TP quá gần giá hiện tại (nhỏ hơn Stops Level)

Triệu chứng: Thường xảy ra với EA scalping đặt SL sát giá, hoặc EA có biên độ trailing nhỏ. Ngay cả khi thao tác thủ công, việc cố đặt SL "ngay sát giá" cũng khiến nút đặt lệnh không bấm được hoặc bị từ chối.

Nguyên nhân: Broker thiết lập SYMBOL_TRADE_STOPS_LEVEL (khoảng cách stop tối thiểu tính bằng điểm) cho từng symbol, và server sẽ từ chối hàng loạt các lệnh SL/TP hoặc giá lệnh chờ có khoảng cách nhỏ hơn mức này so với giá hiện tại. Giá tham chiếu để kiểm tra là Bid đối với SL/TP của lệnh BUY, và Ask đối với lệnh SELL. Khi spread giãn ra, khoảng cách giữa Bid và Ask cũng mở rộng, nên có những lúc bình thường vẫn qua được nhưng bất ngờ bị từ chối khi có tin tức hoặc vào sáng sớm.

Cách xử lý:

  1. Kiểm tra Stops Level trong cửa sổ Specification, rồi mở rộng cấu hình SL/TP hoặc biên độ trailing của EA sao cho lớn hơn giá trị này
  2. Thực hiện clamp (giới hạn) ở phía EA trước khi gửi lệnh (xem code phía dưới)
  3. Nếu bắt buộc cần SL sát giá, hãy cân nhắc chuyển sang broker hoặc loại tài khoản có Stops Level nhỏ hơn

② Đặt sai hướng SL/TP (nhầm lẫn giữa BUY/SELL)

Triệu chứng: Luôn bị Invalid stops ở một hướng cụ thể (chỉ mua hoặc chỉ bán). Đây là lỗi phổ biến nhất khi test lần đầu với EA tự viết.

Nguyên nhân: Quy tắc rất đơn giản: SL của lệnh BUY phải thấp hơn giá hiện tại (Bid), TP phải cao hơn; SL của lệnh SELL phải cao hơn giá hiện tại (Ask), TP phải thấp hơn. Lỗi điển hình là copy công thức tính của BUY sang cho SELL nhưng quên đổi dấu, hoặc nhầm lẫn giữa price - slprice + sl — server sẽ ngay lập tức trả về lỗi 10016/130.

Cách xử lý:

  1. Khi xảy ra lỗi, in ra giá trị thực tế bằng PrintFormat("type=%s sl=%.5f tp=%.5f bid=%.5f ask=%.5f", ...) để kiểm tra trực quan hướng đặt
  2. Gộp phép tính SL/TP của BUY/SELL thành một hàm dùng chung, tập trung nhánh xử lý dấu vào một chỗ duy nhất (tránh việc phân nhánh do copy-paste)

③ Sửa lệnh hoặc thay đổi vị thế trong vùng Freeze Level

Triệu chứng: Lệnh mới thì không vấn đề gì, nhưng chỉ riêng việc sửa/hủy lệnh khi gần chạm TP, gần chạm SL, hoặc gần đến giá kích hoạt lệnh chờ thì bị từ chối.

Nguyên nhân: Với những symbol có thiết lập SYMBOL_TRADE_FREEZE_LEVEL, khi giá hiện tại tiến gần đến một khoảng cách nhất định so với giá kích hoạt (TP/SL/giá trigger của lệnh chờ), việc sửa hoặc hủy lệnh đó sẽ bị đóng băng. Đây là quy định của server nhằm ngăn xung đột giữa quá trình khớp lệnh và yêu cầu sửa lệnh, và nó thường lộ diện dưới dạng trailing của EA "cố cập nhật thêm một nấc nữa ngay sát TP nhưng bị từ chối".

Cách xử lý:

  1. Trước khi sửa lệnh, đọc giá trị SYMBOL_TRADE_FREEZE_LEVEL, nếu khoảng cách đến giá kích hoạt nhỏ hơn hoặc bằng Freeze Level thì bỏ qua lần sửa đó
  2. Nới rộng khoảng thời gian và biên độ cập nhật của trailing để giảm bớt các yêu cầu sửa lệnh vô ích khi gần chạm điểm kích hoạt
  3. Việc bị từ chối không gây hậu quả nghiêm trọng (vì gần chạm điểm kích hoạt nghĩa là sắp khớp lệnh rồi), nên có thể thiết kế theo hướng bỏ qua lỗi và chỉ ghi log

④ Nhầm lẫn giữa giá và điểm (khoảng cách - point)

Triệu chứng: Giá trị SL được nhập trực tiếp như một "con số biểu thị khoảng cách", ví dụ 50 hoặc 0.0050. Trong log hiện sl=50.00000 rõ ràng không phải là giá.

Nguyên nhân: Giá trị đưa vào MqlTradeRequest.sl / .tp phải là giá tuyệt đối (không phải "thấp hơn giá vào lệnh 50 điểm"). Những EA quản lý theo khoảng cách cần chuyển đổi sang dạng entry ± distance * _Point trước khi truyền vào. Ngược lại, nếu theo thói quen của một số hàm thời MT4 mà truyền khoảng cách vào nơi cần giá tuyệt đối, giá trị đó sẽ không hợp lệ như một mức giá và gây ra lỗi 10016/130.

Ngoài ra, việc nhầm lẫn giữa pips và point cũng rất phổ biến. Với broker hiển thị 5 chữ số (ví dụ: USDJPY hiển thị 3 chữ số, EURUSD hiển thị 5 chữ số), 1 pip = 10 point. Nếu "SL 50" được hiểu nhầm là pips hay là point, khoảng cách sẽ chênh lệch gấp 10 lần, dẫn đến việc bị co lại dưới mức Stops Level và bị từ chối.

Cách xử lý:

  1. Luôn xây dựng SL/TP theo dạng NormalizeDouble(price ± dist * _Point, _Digits)
  2. Ghi rõ đơn vị của tham số đầu vào (pips / points) trong comment, và tập trung việc quy đổi _Point vào một chỗ duy nhất trong code

⑤ Broker thực thi lệnh thị trường không cho phép đặt SL/TP ngay khi mở lệnh

Triệu chứng: Nếu không có SL/TP thì lệnh khớp bình thường, nhưng chỉ lệnh mới kèm SL/TP mới bị Invalid stops. Đặc biệt hay xảy ra với tài khoản ECN/thực thi thị trường (Market Execution).

Nguyên nhân: Với hình thức thực thi thị trường, "giá tại thời điểm yêu cầu" và "giá khớp lệnh thực tế" có thể chênh lệch nhau, nên một số server không chấp nhận SL/TP trong yêu cầu đặt lệnh mới, mà yêu cầu phải đặt sau khi khớp lệnh thông qua việc sửa vị thế. Đây là quy định kinh điển thường gây ra lỗi 130 ở các tài khoản ECN thời MT4, và vẫn còn một số server trên MT5 giữ hành vi tương tự.

Cách xử lý:

  1. Chuyển sang cách làm 2 bước: đặt lệnh không kèm SL/TP trước → sau khi xác nhận khớp lệnh, dùng PositionModify() (hoặc trade.PositionModify() nếu dùng CTrade) để thêm SL/TP
  2. Với cách này sẽ có khoảnh khắc "lệnh đã khớp thành công nhưng đặt SL bị thất bại", vì vậy bắt buộc phải có cơ chế bảo vệ: thử lại cho đến khi đặt SL thành công, và nếu thất bại đủ số lần quy định thì đóng lệnh ngay lập tức (để lệnh không có SL là kết quả tồi tệ nhất)
  3. Có thể kiểm tra hình thức thực thi bằng SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE)

⑥ Đặc thù riêng của từng symbol (vàng, chỉ số có Stops Level lớn)

Triệu chứng: Cùng một EA hoạt động bình thường trên EURUSD, nhưng khi chuyển sang XAUUSD (vàng) hoặc CFD chỉ số chứng khoán thì liên tục bị Invalid stops.

Nguyên nhân: Stops Level được thiết lập riêng cho từng symbol, và thông thường vàng, chỉ số, các cặp tiền ngoại lai (exotic) thường có mức lớn hơn nhiều so với các cặp tiền tệ chính. Nếu dùng nguyên SL/biên độ trailing đã tinh chỉnh sát cho FX chính, nó sẽ không đạt được khoảng cách tối thiểu của symbol đó và bị từ chối. Số chữ số thập phân (digits) cũng khác nhau tùy symbol (vàng thường có 2-3 chữ số), nên đoạn code cố định _Digits cũng có thể bị lỗi.

Cách xử lý:

  1. Mỗi khi đổi symbol, luôn kiểm tra Stops Level và số chữ số thập phân trong cửa sổ Specification
  2. Thay vì cố định biên độ SL/TP theo số điểm, hãy chuyển sang dùng tiêu chuẩn biến động như ATR để hạn chế lỗi khi áp dụng cho nhiều symbol khác nhau
  3. Trong code, luôn lấy động các giá trị _Point / _Digits / SYMBOL_TRADE_STOPS_LEVEL (cấm hardcode)

Sự khác biệt giữa các broker (lưu ý)

Stops Level và Freeze Level hoàn toàn khác nhau tùy theo từng cặp broker và symbol. Cùng một EA, cùng một cấu hình, nhưng lỗi chưa từng xuất hiện ở broker A lại xảy ra hàng ngày ở broker B — đây là chuyện hết sức bình thường.

Một điểm cần lưu ý thêm là những broker hiển thị Stops Level bằng "0". Giá trị 0 không có nghĩa là "không giới hạn" mà thường mang nghĩa là "xét động", nên bình thường dù SL đặt sát giá đến đâu cũng vẫn qua được, nhưng chỉ bị từ chối vào đúng thời điểm spread giãn rộng, như khi có tin tức hoặc vào sáng sớm. Đây thường chính là nguyên nhân của những lỗi "Invalid stops hiếm khi xảy ra".

Việc kiểm tra nhất định phải thực hiện trên tài khoản thực tế.

long stops  = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);   // đơn vị point
long freeze = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL);  // đơn vị point

Giá trị cụ thể phụ thuộc vào loại tài khoản và thông số kỹ thuật của từng symbol theo từng broker, nên bài viết này sẽ không nêu ra con số cụ thể. Kết quả bạn chạy đoạn code trên tại chính tài khoản của mình mới là câu trả lời duy nhất đúng.


Code MQL5 để phòng tránh lỗi này (dành cho lập trình viên EA)

Thiết kế đúng đắn không phải là "sửa khi lỗi xảy ra", mà là clamp (giới hạn) SL/TP về khoảng cách tối thiểu của broker trước khi gửi lệnh, để ngay từ đầu không phát sinh lỗi 10016.

Kiểm tra và clamp SL/TP trước khi gửi lệnh

// Clamp SL/TP về khoảng cách lớn hơn hoặc bằng Stops Level trước khi gửi lệnh
// Giá trị trả về false = hướng bị ngược (lỗi thiết kế), nên không gửi lệnh
bool ClampStops(ENUM_ORDER_TYPE type, double &sl, double &tp)
{
   double point   = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
   int    digits  = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   long   stopsPt = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);
   double spread  = SymbolInfoDouble(_Symbol, SYMBOL_ASK)
                  - SymbolInfoDouble(_Symbol, SYMBOL_BID);
   // Khoảng dự phòng = Stops Level + spread (đối phó với broker xét động khi stops=0)
   double minDist = stopsPt * point + spread;

   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   if(type == ORDER_TYPE_BUY)
   {
      // SL/TP của lệnh BUY được kiểm tra dựa trên Bid
      if(sl > 0 && sl >= bid) return false;              // hướng bị ngược
      if(tp > 0 && tp <= bid) return false;
      if(sl > 0 && (bid - sl) < minDist) sl = bid - minDist;
      if(tp > 0 && (tp - bid) < minDist) tp = bid + minDist;
   }
   else if(type == ORDER_TYPE_SELL)
   {
      // SL/TP của lệnh SELL được kiểm tra dựa trên Ask
      if(sl > 0 && sl <= ask) return false;              // hướng bị ngược
      if(tp > 0 && tp >= ask) return false;
      if(sl > 0 && (sl - ask) < minDist) sl = ask + minDist;
      if(tp > 0 && (ask - tp) < minDist) tp = ask - minDist;
   }
   sl = NormalizeDouble(sl, digits);
   tp = NormalizeDouble(tp, digits);
   return true;
}

Có 3 điểm mấu chốt.

  1. Luôn lấy động SYMBOL_TRADE_STOPS_LEVELSYMBOL_POINT mỗi lần (giúp không phụ thuộc vào symbol/broker cụ thể)
  2. Cộng thêm khoảng dự phòng bằng spread (giúp dễ qua hơn ngay cả với broker xét động khi Stops Level bằng 0)
  3. Cuối cùng luôn dùng NormalizeDouble(giá, _Digits) để căn chỉnh số chữ số thập phân (số thập phân dư thừa cũng có thể là nguyên nhân bị từ chối)

Xử lý riêng mã retcode 10016

Khi bị từ chối, nếu ghi log lại "đã gửi giá trị gì, khoảng cách lúc đó là bao nhiêu", bạn có thể nhận ra ngay đó là nguyên nhân nào trong số 6 nguyên nhân ①~⑥.

MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
// ... xây dựng req (sl/tp đã qua ClampStops) ...
if(!OrderSend(req, res) || res.retcode != TRADE_RETCODE_DONE)
{
   if(res.retcode == TRADE_RETCODE_INVALID_STOPS)   // 10016
      PrintFormat("Invalid stops: sl=%s tp=%s bid=%s stopsLevel=%d",
                  DoubleToString(req.sl, _Digits),
                  DoubleToString(req.tp, _Digits),
                  DoubleToString(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits),
                  (int)SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL));
   else
      PrintFormat("OrderSend failed: retcode=%d, lastError=%d", res.retcode, GetLastError());
}

Kiểm tra Freeze Level trước khi sửa trailing

// Trước khi sửa vị thế, kiểm tra xem giá kích hoạt có nằm trong vùng freeze hay không
bool CanModify(double triggerPrice)
{
   long freeze = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL);
   if(freeze <= 0) return true;
   double dist = MathAbs(SymbolInfoDouble(_Symbol, SYMBOL_BID) - triggerPrice);
   return (dist > freeze * SymbolInfoDouble(_Symbol, SYMBOL_POINT));
}

Với EA phiên bản MT4, bạn có thể lấy các giá trị tương đương thông qua MarketInfo(Symbol(), MODE_STOPLEVEL) / MODE_FREEZELEVEL. Cách tư duy hoàn toàn giống nhau.

Các EA do FXEA365 phân phối đều được tích hợp sẵn cơ chế kiểm tra SL/TP trước khi gửi lệnh, clamp Stops Level, và lấy động giá trị không phụ thuộc vào symbol như tiêu chuẩn, nên dù thay đổi broker hay symbol, EA vẫn không bị dừng lại vì lỗi Invalid stops.


Danh sách kiểm tra theo mức độ ưu tiên

Ưu tiênKiểm traCách xử lý
🚨 Đầu tiênKhoảng cách giữa SL/TP và giá hiện tại có nhỏ hơn Stops Level khôngMở rộng biên độ SL/TP / triển khai clamp
🚨 Đầu tiênHướng SL/TP của BUY/SELL có bị ngược khôngIn giá trị thực ra log để kiểm tra trực quan
⚠️ Tiếp theoChỉ việc sửa lệnh bị thất bại → có nằm trong Freeze Level khôngBỏ qua việc sửa lệnh khi gần đến điểm kích hoạt
⚠️ Tiếp theoCó đang nhập khoảng cách (point) vào sl/tp khôngChuyển đổi sang giá tuyệt đối price ± dist*_Point
✅ Kiểm traCó phải tài khoản thực thi thị trường cần đặt SL/TP sau khôngĐặt lệnh → thực hiện theo cách 2 bước với PositionModify
🛠 Phát triểnCó đang lấy động thông số kỹ thuật của symbol khôngTriển khai ClampStops như trên

Tổng kết

  • Invalid stops là mã 10016 (TRADE_RETCODE_INVALID_STOPS) trên MT5 và mã 130 (ERR_INVALID_STOPS) trên MT4. Số hiệu khác nhau nhưng ý nghĩa và cách xử lý là chung.
  • Phần lớn nguyên nhân không phải do tính toán sai, mà là 6 lý do: nhỏ hơn Stops Level, đặt sai hướng, Freeze Level, nhầm lẫn giữa giá và điểm, quy định đặt SL/TP sau, và đặc thù riêng của từng symbol.
  • Lập trình viên có thể phòng tránh vĩnh viễn bằng cách "đọc SYMBOL_TRADE_STOPS_LEVEL trước khi đặt lệnh để clamp + dùng NormalizeDouble". Với broker có Stops Level bằng 0, hãy hấp thụ rủi ro bằng khoảng dự phòng tương ứng với spread.

Để xem toàn bộ mã lỗi, hãy tham khảo Hướng dẫn tổng hợp xử lý mã lỗi MQL5 / MT5. Về một lỗi kinh điển khác cũng khiến lệnh bị từ chối — "không đủ vốn" — bạn có thể xem thêm tại Bài viết giải thích về ERR_NO_MONEY (134/10019).


Câu hỏi thường gặp (FAQ)

Hỏi: Tôi chắc chắn phép tính SL/TP của mình đúng, nhưng vẫn bị Invalid stops. Tại sao?

Rất có thể lệnh bị từ chối không phải do giá trị sai, mà do khoảng cách so với giá hiện tại. SL/TP có khoảng cách nhỏ hơn mức stop tối thiểu của broker (Stops Level) sẽ bị từ chối hàng loạt dù giá trị có chính xác đến đâu. Hãy kiểm tra khoảng cách tối thiểu qua cửa sổ Specification hoặc bằng SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL).

Hỏi: 10016 và 130 khác nhau ở điểm nào?

10016 (TRADE_RETCODE_INVALID_STOPS) là mã kết quả trả về từ OrderSend() / PositionModify() trên MT5, còn 130 (ERR_INVALID_STOPS) là giá trị được GetLastError() trả về trên MT4. Chúng chỉ khác nhau về nền tảng, còn ý nghĩa (vị trí SL/TP không hợp lệ) và cách xử lý là hoàn toàn giống nhau.

Hỏi: Bình thường không sao, nhưng chỉ khi có tin tức mới bị Invalid stops.

Nguyên nhân là do spread giãn rộng. Vì SL/TP của lệnh BUY được kiểm tra dựa trên Bid, còn SELL dựa trên Ask, nên chỉ ngay khoảnh khắc spread giãn ra, khoảng cách mới trở nên không đủ. Ngay cả với broker có Stops Level bằng 0, vẫn có hành vi từ chối động chỉ khi thị trường biến động đột ngột. Hãy cộng thêm khoảng dự phòng tương ứng với spread vào khoảng cách SL/TP (tham khảo đoạn code trong bài).

Hỏi: Nếu không có SL/TP thì lệnh khớp bình thường, nhưng có kèm SL/TP thì bị từ chối.

Có khả năng đây là tài khoản thực thi thị trường (Market Execution) mà server không chấp nhận SL/TP trong yêu cầu đặt lệnh mới. Hãy chuyển sang đặt lệnh không kèm SL/TP, sau đó dùng PositionModify() để thiết lập sau khi khớp lệnh. Tuy nhiên, nhất định phải có cơ chế thử lại nếu đặt SL thất bại, và đóng lệnh ngay lập tức nếu liên tục thất bại.

Hỏi: EA hoạt động bình thường trên EURUSD nhưng liên tục bị Invalid stops trên vàng.

Thông thường, vàng và chỉ số chứng khoán có Stops Level lớn hơn so với các cặp tiền tệ chính, và số chữ số thập phân cũng khác nhau. Hãy mở rộng biên độ SL/trailing cho phù hợp với thông số kỹ thuật của symbol, hoặc chuyển sang biên độ liên động theo biến động như ATR.

📧 Cảnh báo trước khi tăng giá + khóa học email miễn phí 5 ngày

Tất cả EA đang ở giá ra mắt và tăng dần theo doanh số. Nhận thông báo trước mỗi lần tăng giá, cùng email hằng ngày về giao dịch thuật toán, cách đọc backtest và chọn sàn.

* Quyền riêng tư được bảo vệ nghiêm ngặt. Bạn có thể hủy đăng ký bất cứ lúc nào.

Bình luận & câu hỏi