الرئيسية > المدونة > الحل الشامل لخطأ Invalid stops (10016/130) — SL في MT5/MT4

MT5MQL5الأخطاءحل المشكلاتالإكسبيرت

الحل الشامل لخطأ Invalid stops (10016/130) — SL في MT5/MT4

نُشر: 2026-07-07وقت القراءة: حوالي 7 دقيقة
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

المحتوى

  1. ما هو Invalid stops (الفرق بين 10016 و130)
  2. ① TRADE_RETCODE_INVALID_STOPS = 10016 (MT5 / كود إرجاع `OrderSend()`)
  3. ② ERR_INVALID_STOPS = 130 (MT4 / `GetLastError()`)
  4. تشخيص سريع خلال 30 ثانية
  5. الأسباب والحلول (6 حالات)
  6. ① SL/TP أقرب من اللازم للسعر الحالي (أقل من مستوى التوقف)
  7. ② اتجاه SL/TP معكوس (اختلاط بين BUY وSELL)
  8. ③ تعديل أمر أو صفقة داخل نطاق مستوى التجميد
  9. ④ الخلط بين السعر والنقاط (المسافة)
  10. ⑤ وسطاء التنفيذ الفوري لا يقبلون SL/TP عند فتح الصفقة
  11. ⑥ خصائص خاصة بأدوات مالية معينة (الذهب والمؤشرات لها مستوى توقف أكبر)
  12. الاختلاف بين الوسطاء (تنبيه هام)
  13. كود بلغة MQL5 لمنع هذا الخطأ (لمطوري الإكسبيرت)
  14. التحقق من SL/TP وتثبيتها قبل الإرسال
  15. معالجة retcode 10016 بشكل منفصل
  16. تعديل التتبع (Trailing) بعد التحقق من مستوى التجميد
  17. قائمة تحقق حسب الأولوية
  18. الخلاصة
  19. الأسئلة الشائعة
  20. س: حساب SL/TP لدي صحيح تمامًا، لكن Invalid stops لا يزال يظهر. لماذا؟
  21. س: ما الفرق بين 10016 و130؟
  22. س: الخطأ Invalid stops لا يظهر عادة، لكنه يظهر فقط وقت صدور البيانات الاقتصادية.
  23. س: الأمر يُنفَّذ بدون SL/TP، لكنه يُرفض عند إرفاق SL/TP معه.
  24. س: إكسبيرت يعمل بلا مشاكل على EURUSD، لكنه يُطلق Invalid stops باستمرار على الذهب.

الحل الشامل لخطأ Invalid stops (10016/130)

عند تشغيل إكسبيرت (EA) وظهور Invalid stops أو OrderSend error 130 في تبويب Expert، يميل المتداول إلى الاعتقاد بأن قيمة SL خاطئة رغم أن الحسابات تبدو صحيحة. لكن الحقيقة أن معظم حالات هذا الخطأ ليست خطأً في حساب SL/TP، بل مخالفة لقاعدة «الحد الأدنى للمسافة» التي يفرضها الوسيط (Broker). القيمة نفسها قد تكون صحيحة تمامًا، لكنها تُرفض لأنها قريبة جدًا من السعر الحالي، أو لأن الاتجاه معكوس، أو لأنها تقع داخل منطقة محظور تعديلها.

هذا المقال موجّه لكل من يستخدم إكسبيرت على MT5/MT4 ومن يكتب إكسبيرت بلغة MQL5، ويجمع في مكان واحد ماهية خطأ Invalid stops، وأسبابه الستة، وطريقة تشخيص سريعة خلال 30 ثانية، والحلول البرمجية الدائمة. للاطلاع على قائمة شاملة بجميع أكواد الأخطاء، راجع الدليل الشامل لحل أكواد أخطاء MQL5 / MT5.

يفترض هذا المقال إصدار MT5 (سلسلة build 4xxx) اعتبارًا من يوليو 2026. القيم الفعلية لمستوى التوقف تختلف حسب الوسيط والأداة المالية.


ما هو Invalid stops (الفرق بين 10016 و130)

القيمة التي تشير إلى «توقف غير صالح» تأتي بشكلين حسب المنصة (والجيل): MT5 وMT4. تحديد المنصة والمرحلة التي ظهر فيها الخطأ يسرّع كثيرًا عملية التشخيص.

① TRADE_RETCODE_INVALID_STOPS = 10016 (MT5 / كود إرجاع OrderSend())

نتيجة استدعاء OrderSend() في MQL5 تُخزَّن في MqlTradeResult.retcode. إذا لم يتوافق SL/TP في الطلب (أو سعر أمر معلّق) مع قواعد الخادم، يُرفض الطلب بالكود 10016 (TRADE_RETCODE_INVALID_STOPS). هذا إشعار رفض صادر من خادم التداول نفسه.

المعنى: توقف غير صالح ضمن الطلب (Invalid stops in the request)
الثابت: TRADE_RETCODE_INVALID_STOPS
القيمة: 10016
// مثال نموذجي كما يظهر في السجل (Log)
2026.07.07 09:15:32.441 EA_NAME XAUUSD,M5: OrderSend error: retcode=10016 (invalid stops)

② ERR_INVALID_STOPS = 130 (MT4 / GetLastError())

في جيل MT4 (MQL4)، عندما يفشل OrderSend() / OrderModify() تُعيد GetLastError() القيمة 130 (ERR_INVALID_STOPS). رسالة OrderSend error 130 في تبويب Expert تشير إلى هذا الخطأ تحديدًا، وتظهر عند استخدام إكسبيرت مكتوب لـ MT4.

المعنى: توقف غير صالح (invalid stops)
الثابت: ERR_INVALID_STOPS
القيمة: 130

الفرق العملي بين الحالتين:

المنصةمصدر القيمةالقيمةمتى تظهر
MT5MqlTradeResult.retcode10016 (TRADE_RETCODE_INVALID_STOPS)رفض الخادم لطلب OrderSend / PositionModify
MT5CTrade.ResultRetcode()10016رفض طلب أو تعديل عبر CTrade
MT4GetLastError()130 (ERR_INVALID_STOPS)بعد فشل OrderSend / OrderModify

الأرقام مختلفة لكن المعنى والسبب متطابقان تقريبًا، وطريقة المعالجة موحّدة. وتجدر الإشارة إلى أن الخطأ 10015 (TRADE_RETCODE_INVALID_PRICE) الشائع الخلط به في MT5 يعني أن سعر الأمر نفسه غير صالح، وهو أمر مختلف تمامًا؛ أما 10016 فيتعلق حصرًا بموقع SL/TP (التوقف).


تشخيص سريع خلال 30 ثانية

افتح في MT5 «الأسعار (Market Watch) ← نقر يمين على الرمز ← المواصفات (Specification)»، وتحقق من هذين الحقلين:

مستوى التوقف (Stops level)   : أقل مسافة (بالنقاط) يجب أن يبعدها SL/TP عن السعر الحالي
مستوى التجميد (Freeze level) : المسافة التي يُمنع عندها تعديل أو إلغاء أمر قريب من التفعيل

بعد ذلك، قارن في السجل لحظة ظهور الخطأ بين قيمة SL/TP التي حاولت إرسالها وسعري Bid/Ask الحاليين.

  • SL أو TP أقرب من مستوى التوقف إلى السعر الحالي ← هذا هو السبب الأرجح (السبب ①).
  • صفقة شراء (BUY) لكن SL أعلى من Bid أو TP أدنى من Bid (والعكس في البيع SELL) ← اختلاط في الاتجاه (السبب ②).
  • فشل تعديل الصفقة المفتوحة فقط ← مستوى التجميد، أو نظام إضافة SL/TP لاحقًا (السببان ③ و⑤).
  • قيمة SL مثل «50» وواضح أنها ليست سعرًا ← خلط بين السعر والنقاط (السبب ④).

يمكن التحقق برمجيًا بسطر واحد فقط:

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

الأسباب والحلول (6 حالات)

① SL/TP أقرب من اللازم للسعر الحالي (أقل من مستوى التوقف)

الأعراض: شائع في إكسبيرت السكالبينج الذي يضع SL ضيقًا، أو الإكسبيرت ذو مسافة التتبع (Trailing) الصغيرة. حتى يدويًا، محاولة وضع SL قريب جدًا من السعر قد تمنع الضغط على زر التنفيذ أو تُرفض تلقائيًا.

السبب: يحدد الوسيط لكل أداة مالية قيمة SYMBOL_TRADE_STOPS_LEVEL (الحد الأدنى للمسافة بالنقاط)، وأي SL/TP أو سعر أمر معلّق أقل من هذه المسافة من السعر الحالي يُرفض تلقائيًا من الخادم. سعر المرجع المستخدم للتحقق هو Bid لصفقات الشراء (BUY) وAsk لصفقات البيع (SELL). عند اتساع السبريد يزداد الفارق بين Bid وAsk، لذا قد تُرفض فجأة مسافة كانت مقبولة في الأوقات العادية، خاصة عند صدور البيانات الاقتصادية أو في ساعات الصباح الباكر.

الحل:

  1. تحقق من مستوى التوقف في نافذة المواصفات، ووسّع إعدادات SL/TP أو مسافة التتبع في الإكسبيرت بما يتجاوزه
  2. اجعل الإكسبيرت يقوم بتثبيت (Clamp) القيمة قبل إرسال الأمر (الكود لاحقًا)
  3. إذا كان لا بد من SL ضيق، ابحث عن وسيط أو نوع حساب بمستوى توقف أصغر

② اتجاه SL/TP معكوس (اختلاط بين BUY وSELL)

الأعراض: يظهر Invalid stops دائمًا في اتجاه واحد فقط (الشراء فقط أو البيع فقط). هذا النمط هو الأكثر شيوعًا عند أول اختبار لإكسبيرت مكتوب حديثًا.

السبب: القاعدة بسيطة: في صفقة BUY يجب أن يكون SL أسفل السعر الحالي (Bid) وTP أعلاه، وفي صفقة SELL يجب أن يكون SL أعلى السعر الحالي (Ask) وTP أسفله. النسخ من معادلة BUY إلى SELL دون تصحيح الإشارة، أو الخلط بين price - sl وprice + sl، من الأخطاء الشائعة التي يرفضها الخادم فورًا بالكود 10016/130.

الحل:

  1. عند حدوث الخطأ، اطبع القيم الفعلية عبر PrintFormat("type=%s sl=%.5f tp=%.5f bid=%.5f ask=%.5f", ...) وتحقق من الاتجاه بصريًا
  2. اجعل حساب SL/TP في دالة موحّدة لكل من BUY وSELL، وركّز منطق الإشارة في مكان واحد فقط (تجنّب تكرار الكود بالنسخ واللصق)

③ تعديل أمر أو صفقة داخل نطاق مستوى التجميد

الأعراض: الأوامر الجديدة تعمل بلا مشاكل، لكن التعديل أو الإلغاء قبل تفعيل TP أو SL أو أمر معلّق مباشرة فقط هو ما يُرفض.

السبب: في الأدوات المالية التي تحدد SYMBOL_TRADE_FREEZE_LEVEL، عندما يقترب السعر الحالي من سعر التفعيل (TP/SL أو نقطة تنفيذ الأمر المعلّق) إلى مسافة معينة، يُجمَّد تعديل أو إلغاء ذلك الأمر. هذه قاعدة من الخادم لمنع تعارض معالجة التنفيذ مع طلبات التعديل، وتظهر عمليًا عندما يحاول نظام التتبع (Trailing) في الإكسبيرت تحديث SL/TP مرة أخيرة قبل التفعيل مباشرة فيُرفض.

الحل:

  1. قبل أي تعديل، اقرأ SYMBOL_TRADE_FREEZE_LEVEL، وإذا كانت المسافة حتى سعر التفعيل أقل من أو تساوي مستوى التجميد، تخطَّ عملية التعديل في تلك اللحظة
  2. وسّع فترة ومسافة تحديث نظام التتبع لتقليل طلبات التعديل غير الضرورية قرب التفعيل
  3. بما أن الرفض هنا غير حرج (فالصفقة على وشك التنفيذ أصلًا)، يكفي تجاهل الخطأ وتسجيله في السجل فقط

④ الخلط بين السعر والنقاط (المسافة)

الأعراض: قيمة SL تحتوي على رقم يُقصد به «مسافة» مثل 50 أو 0.0050 بدلًا من سعر فعلي. القيمة sl=50.00000 في السجل واضح أنها ليست سعرًا.

السبب: الحقلان MqlTradeRequest.sl / .tp يجب أن يحتويا على سعر مطلق (وليس «50 نقطة أسفل سعر الدخول»). الإكسبيرت الذي يدير SL/TP بالمسافة يجب أن يحوّلها إلى entry ± distance * _Point قبل إرسالها. وبالمثل، تمرير مسافة في موضع يُفترض أن يكون سعرًا مطلقًا (كما كان معتادًا في بعض دوال زمن MT4) يجعل القيمة غير صالحة كسعر فيؤدي إلى 10016/130.

كذلك الخلط بين pips والنقاط (Points) شائع جدًا. في الوسطاء ذوي 5 أرقام عشرية (مثل USDJPY بـ3 أرقام وEURUSD بـ5 أرقام)، 1 pip = 10 نقاط. إذا كانت قيمة «SL 50» يُقصد بها pips بينما يفترضها الكود نقاطًا (أو العكس)، تختلف المسافة الفعلية بمقدار 10 أضعاف، وقد تنخفض دون مستوى التوقف فيُرفض الأمر.

الحل:

  1. اجعل بناء SL/TP دائمًا بالصيغة NormalizeDouble(price ± dist * _Point, _Digits)
  2. وضّح وحدة معاملات الإدخال (pips أو points) في التعليقات، وركّز تحويل _Point في مكان واحد داخل الكود

⑤ وسطاء التنفيذ الفوري لا يقبلون SL/TP عند فتح الصفقة

الأعراض: الأمر يُنفَّذ بدون SL/TP، لكن الأمر الجديد المرفق بـ SL/TP يُرفض بخطأ Invalid stops. يحدث بشكل خاص في حسابات ECN / التنفيذ الفوري (Market Execution).

السبب: في التنفيذ الفوري، يختلف «السعر وقت الطلب» عن «سعر التنفيذ الفعلي»، لذا بعض الخوادم لا تقبل SL/TP ضمن طلب الفتح الجديد، وتشترط إضافته لاحقًا عبر تعديل الصفقة بعد التنفيذ. هذا سلوك كلاسيكي كان شائعًا في حسابات ECN زمن MT4 (السبب في تكرار الخطأ 130)، وما زالت بعض خوادم MT5 تسلك السلوك نفسه.

الحل:

  1. غيّر الأسلوب إلى مرحلتين: أرسل الأمر أولًا بدون SL/TP، وبعد تأكيد التنفيذ استخدم PositionModify() (أو trade.PositionModify() عند استخدام CTrade) لإضافة SL/TP
  2. بما أن هذا الأسلوب يُنشئ لحظة «تم تنفيذ الأمر لكن فشل ضبط SL»، يجب دائمًا وضع حماية: إعادة المحاولة حتى ينجح ضبط SL، وإغلاق الصفقة فورًا عند فشل عدد محدد من المحاولات (ترك الصفقة بلا SL هو أسوأ نتيجة ممكنة)
  3. يمكن التحقق من طريقة التنفيذ عبر SymbolInfoInteger(_Symbol, SYMBOL_TRADE_EXEMODE)

⑥ خصائص خاصة بأدوات مالية معينة (الذهب والمؤشرات لها مستوى توقف أكبر)

الأعراض: نفس الإكسبيرت يعمل بلا مشاكل على EURUSD، لكنه يُطلق أخطاء Invalid stops متكررة فور تطبيقه على XAUUSD (الذهب) أو مؤشرات الأسهم (CFD).

السبب: مستوى التوقف يُحدَّد بشكل منفصل لكل أداة مالية، ومن الطبيعي أن يكون مستوى التوقف في الذهب والمؤشرات والعملات النادرة أكبر بكثير من العملات الرئيسية. استخدام إعدادات SL/مسافة تتبع ضيقة مضبوطة أصلًا للعملات الرئيسية دون تعديل يجعلها لا تصل إلى الحد الأدنى المطلوب فتُرفض. كذلك يختلف عدد الأرقام العشرية حسب الأداة (الذهب مثلًا برقمين أو ثلاثة أرقام عشرية)، لذا فإن أي كود يفترض قيمة _Digits ثابتة سينكسر أيضًا.

الحل:

  1. عند تغيير الأداة المالية، تحقق دائمًا من مستوى التوقف وعدد الأرقام العشرية في نافذة المواصفات
  2. اجعل عرض SL/TP مبنيًا على مقياس تقلب مثل ATR بدلًا من نقاط ثابتة، فهذا يقلل احتمال الفشل عند تبديل الأداة المالية
  3. اجعل الكود يقرأ _Point / _Digits / SYMBOL_TRADE_STOPS_LEVEL ديناميكيًا دائمًا (ممنوع كتابتها كقيم ثابتة في الكود)

الاختلاف بين الوسطاء (تنبيه هام)

مستوى التوقف ومستوى التجميد يختلفان تمامًا حسب تركيبة الوسيط والأداة المالية. من الطبيعي جدًا أن يعمل نفس الإكسبيرت بنفس الإعدادات دون أي خطأ لدى الوسيط أ، بينما يظهر الخطأ يوميًا لدى الوسيط ب.

الأمر الذي يستحق انتباهًا خاصًا هو الوسطاء الذين يعرضون مستوى التوقف كـ «0». القيمة 0 لا تعني غالبًا «بلا حدود»، بل «يُحدَّد ديناميكيًا»، أي أن أي SL قريب جدًا يُقبل في الأوقات العادية، بينما يُرفض فقط في لحظات اتساع السبريد مثل صدور البيانات الاقتصادية أو الصباح الباكر. هذا هو السبب الحقيقي وراء ظهور Invalid stops «من حين لآخر فقط».

يجب التحقق دائمًا على الحساب الفعلي:

long stops  = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL);   // بالنقاط
long freeze = SymbolInfoInteger(_Symbol, SYMBOL_TRADE_FREEZE_LEVEL);  // بالنقاط

القيم الفعلية تعتمد على نوع الحساب ومواصفات الأداة لدى كل وسيط، لذا لن يذكر هذا المقال أرقامًا محددة. القيمة التي يعيدها الكود أعلاه على حسابك أنت هي الإجابة الوحيدة الصحيحة.


كود بلغة MQL5 لمنع هذا الخطأ (لمطوري الإكسبيرت)

التصميم الصحيح ليس «إصلاح الخطأ بعد ظهوره»، بل تثبيت (Clamp) قيمة SL/TP عند الحد الأدنى الذي يفرضه الوسيط قبل إرسال الأمر، بحيث لا يحدث الخطأ 10016 من الأساس.

التحقق من SL/TP وتثبيتها قبل الإرسال

// تثبيت SL/TP عند مسافة لا تقل عن مستوى التوقف قبل إرسال الأمر
// القيمة المعادة false = الاتجاه معكوس (خطأ تصميم)، لذا لا يجب إرسال الأمر
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);
   // هامش إضافي = مستوى التوقف + السبريد (احتياطًا للوسطاء ذوي 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 لصفقة BUY بناءً على Bid
      if(sl > 0 && sl >= bid) return false;              // الاتجاه معكوس
      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 لصفقة SELL بناءً على Ask
      if(sl > 0 && sl <= ask) return false;              // الاتجاه معكوس
      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;
}

النقاط الأساسية ثلاث:

  1. اقرأ SYMBOL_TRADE_STOPS_LEVEL وSYMBOL_POINT ديناميكيًا في كل مرة (بحيث يعمل الكود بغض النظر عن الأداة المالية أو الوسيط)
  2. أضف هامشًا يعادل السبريد (يساعد على تجاوز مشكلة الوسطاء ذوي مستوى التوقف 0 الديناميكي)
  3. لا تنسَ في النهاية NormalizeDouble(السعر, _Digits) لضبط عدد الأرقام العشرية (الأرقام الزائدة قد تكون سببًا إضافيًا للرفض)

معالجة retcode 10016 بشكل منفصل

عند الرفض، تسجيل «ماذا تم إرساله وما كانت المسافة في تلك اللحظة» في السجل يكشف فورًا أي سبب من الأسباب الستة هو المسؤول.

MqlTradeRequest req; MqlTradeResult res;
ZeroMemory(req); ZeroMemory(res);
// ... بناء req (بعد تمرير sl/tp عبر 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());
}

تعديل التتبع (Trailing) بعد التحقق من مستوى التجميد

// قبل تعديل الصفقة، تحقق من أن سعر التفعيل ليس داخل نطاق التجميد
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));
}

في إكسبيرت MT4، يمكن الحصول على نفس القيم عبر MarketInfo(Symbol(), MODE_STOPLEVEL) / MODE_FREEZELEVEL. الفكرة مطابقة تمامًا.

الإكسبيرت الذي توزّعه FXEA365 يطبّق كمعيار افتراضي التحقق من SL/TP قبل الإرسال، وتثبيت مستوى التوقف (Clamp)، والقراءة الديناميكية المستقلة عن الأداة المالية، وهو ما يجعله لا يتوقف بسبب Invalid stops حتى عند تغيير الوسيط أو الأداة المالية.


قائمة تحقق حسب الأولوية

الأولويةالتحققالحل
🚨 أولًاهل المسافة بين SL/TP والسعر الحالي أقل من مستوى التوقفتوسيع مسافة SL/TP / تطبيق التثبيت (Clamp)
🚨 أولًاهل اتجاه SL/TP معكوس بين BUY وSELLطباعة القيم الفعلية في السجل والتحقق البصري
⚠️ ثانيًافشل التعديل فقط ← هل هو داخل مستوى التجميدتخطي التعديل قرب لحظة التفعيل
⚠️ ثانيًاهل تم تمرير مسافة (بالنقاط) بدلًا من سعر في sl/tpالتحويل إلى سعر مطلق price ± dist*_Point
✅ تحققهل الحساب من نوع التنفيذ الفوري ويتطلب إضافة SL/TP لاحقًاأسلوب إرسال ثم PositionModify على مرحلتين
🛠 تطويرهل يتم قراءة مواصفات الأداة المالية ديناميكيًاتطبيق دالة ClampStops أعلاه

الخلاصة

  • Invalid stops هو 10016 (TRADE_RETCODE_INVALID_STOPS) في MT5، و130 (ERR_INVALID_STOPS) في MT4. الأرقام مختلفة لكن المعنى وطريقة المعالجة موحّدة.
  • معظم الأسباب ليست خطأ في الحساب، بل واحدة من ستة: أقل من مستوى التوقف، اتجاه معكوس، مستوى التجميد، الخلط بين السعر والنقاط، نظام إضافة SL/TP لاحقًا، وخصائص خاصة بأداة مالية معينة.
  • يمكن للمطورين حل المشكلة بشكل دائم عبر «قراءة SYMBOL_TRADE_STOPS_LEVEL قبل الإرسال ثم التثبيت (Clamp) + NormalizeDouble». حتى الوسطاء ذوو مستوى توقف 0 يمكن التعامل معهم بإضافة هامش يعادل السبريد.

للاطلاع على جميع أكواد الأخطاء، راجع الدليل الشامل لحل أكواد أخطاء MQL5 / MT5. كذلك خطأ رفض الأوامر الشائع الآخر «عدم كفاية الأموال» موثّق في شرح ERR_NO_MONEY (134/10019).


الأسئلة الشائعة

س: حساب SL/TP لدي صحيح تمامًا، لكن Invalid stops لا يزال يظهر. لماذا؟

الاحتمال الأكبر أن الرفض ليس بسبب خطأ في القيمة، بل بسبب المسافة من السعر الحالي. أي SL/TP أقل من الحد الأدنى لمسافة التوقف الذي يفرضه الوسيط يُرفض تلقائيًا حتى لو كانت القيمة دقيقة تمامًا. تحقق من الحد الأدنى عبر نافذة المواصفات أو SymbolInfoInteger(_Symbol, SYMBOL_TRADE_STOPS_LEVEL).

س: ما الفرق بين 10016 و130؟

10016 (TRADE_RETCODE_INVALID_STOPS) هو كود النتيجة الذي تعيده OrderSend() / PositionModify() في MT5، بينما 130 (ERR_INVALID_STOPS) هو القيمة التي تعيدها GetLastError() في MT4. الفرق فقط في المنصة؛ المعنى (موقع SL/TP غير صالح) وطريقة المعالجة متطابقان.

س: الخطأ Invalid stops لا يظهر عادة، لكنه يظهر فقط وقت صدور البيانات الاقتصادية.

السبب هو اتساع السبريد. بما أن SL/TP لصفقة BUY يُتحقق منها بناءً على Bid وصفقة SELL بناءً على Ask، فإن اتساع السبريد المفاجئ يجعل المسافة غير كافية في تلك اللحظة فقط. حتى الوسطاء الذين يعرضون مستوى توقف بقيمة 0 قد يرفضون الأمر ديناميكيًا فقط عند التقلبات الحادة. أضف هامشًا يعادل السبريد إلى مسافة SL/TP (راجع الكود في المقال).

س: الأمر يُنفَّذ بدون SL/TP، لكنه يُرفض عند إرفاق SL/TP معه.

من المحتمل أن الحساب من نوع التنفيذ الفوري (Market Execution) وأن الخادم لا يقبل SL/TP ضمن طلب الفتح الجديد. غيّر الأسلوب إلى إرسال الأمر بدون SL/TP أولًا، ثم ضبطهما بعد التنفيذ عبر PositionModify(). مع ذلك، احرص دائمًا على وضع آلية إعادة محاولة عند فشل ضبط SL، وحماية بإغلاق فوري عند استمرار الفشل.

س: إكسبيرت يعمل بلا مشاكل على EURUSD، لكنه يُطلق Invalid stops باستمرار على الذهب.

من الطبيعي أن يكون مستوى التوقف في الذهب والمؤشرات أكبر من العملات الرئيسية، كما يختلف عدد الأرقام العشرية. وسّع مسافة SL/التتبع بما يتناسب مع مواصفات الأداة المالية، أو اعتمد مسافة مرتبطة بالتقلب مثل ATR.

📧 تنبيهات قبل رفع الأسعار + دورة مجانية عبر البريد لمدة 5 أيام

جميع الروبوتات متاحة الآن بسعر الإطلاق وترتفع تدريجياً مع المبيعات. تلقَّ إشعاراً قبل كل زيادة، إضافة إلى رسالة يومية عن أساسيات التداول الآلي وقراءة الاختبارات الخلفية واختيار الوسيط.

* الخصوصية محمية بشكل صارم. يمكنك إلغاء الاشتراك في أي وقت.

التعليقات والأسئلة