Нужна помощь с ошибкой #130 недействительный стоплосс - страница 4

 
Спасибо, что обратили внимание на Raptor.
Я вызвал свою функцию DoubleRound с MODE_TICKVALUE (который равен 12.50) вместо MODE_TICKSIZE (0.25).

Я исправил это, но это не заставило #130 исчезнуть

.
   if(long)
      SL = MarketInfo(Symbol(), MODE_BID) - (stoploss * MarketInfo(Symbol(), MODE_POINT));
   else
      SL = MarketInfo(Symbol(), MODE_ASK) + (stoploss * MarketInfo(Symbol(), MODE_POINT));
   Log("SL: " + SL);   
   //round to nearest Tickvalue   
   SL = DoubleRound(SL, MarketInfo(Symbol(), MODE_TICKSIZE));
   Log("SL rounded: " + SL);

Вот лог ошибки с обновленной строкой DoubleRound:

#ESZ1,M5: loaded successfully 
#ESZ1,M5: Date: 2011/11/16 21:54
#ESZ1,M5: Symbol: #ESZ1
#ESZ1,M5: Depot: 56127.45000000
#ESZ1,M5: Stop Level [Points]: 75.00000000
#ESZ1,M5: Freeze Level [Points]: 0.00000000
#ESZ1,M5: Spread [Points]: 25.00000000
#ESZ1,M5: Min/Max Lot: 0.01000000/1000.00000000
#ESZ1,M5: Point: 0.01000000
#ESZ1,M5: Tick Size: 0.25000000
#ESZ1,M5: Tick Value: 12.50000000
#ESZ1,M5: Digits: 2.00000000
#ESZ1,M5: Contract: 2011.09.14 00:00-2011.12.16 23:59
#ESZ1,M5: Expert ID: 35698390 
#ESZ1,M5: Init successfully completed.
#ESZ1,M5: initialized

#ESZ1,M5: Opening Position: Short
#ESZ1,M5: pos size: 1.00000000
#ESZ1,M5: Ask/Bid 1251.00000000/1250.75000000
#ESZ1,M5: Spread 0.25000000
#ESZ1,M5: open #13719226 sell 1.00 #ESZ1 at 1250.75 ok
#ESZ1,M5: Order 13719226 Successfully Opened
#ESZ1,M5: Stoplevel: 75.00000000
#ESZ1,M5: Freezelevel: 0.00000000
#ESZ1,M5: stoploss: 100.00000000
#ESZ1,M5: SL: 1252.00000000
#ESZ1,M5: SL rounded: 1252.00000000
#ESZ1,M5: error=130

Для сравнения, вот лог, где все работало:

#ESZ1,M5: Opening Position: Long
#ESZ1,M5: pos size: 1.00000000
#ESZ1,M5: Ask/Bid 1249.25000000/1249.00000000
#ESZ1,M5: Spread 0.25000000
#ESZ1,M5: open #13719321 buy 1.00 #ESZ1 at 1249.25 ok 
#ESZ1,M5: Order 13719321 Successfully Opened 
#ESZ1,M5: Stoplevel: 75.00000000
#ESZ1,M5: Freezelevel: 0.00000000
#ESZ1,M5: stoploss: 100.00000000
#ESZ1,M5: SL: 1248.00000000
#ESZ1,M5: SL rounded: 1248.00000000
#ESZ1,M5: modify #13719321 buy 1.00 #ESZ1 at 1249.25 sl: 1248.00 tp: 0.00 ok 
#ESZ1,M5: Stoploss successfully set

В любом случае, похоже, теперь это работает чаще, мы определенно приближаемся :)
 
shinobi:

В любом случае, кажется, что теперь это работает чаще, мы определенно приближаемся :)

Я не могу понять, почему модификация не удалась ... Вы получаете свежий Bid/Ask между OrderSend и OrderModify?

Все, что я могу предложить сейчас, это то, что когда вы получаете ошибку 130... печатайте все заново, Bid, Ask (используя MarketInfo), OOP, StopLevel, SL, который вы пытаетесь установить, и т.д. и т.п.

 
shinobi:
Я вызвал свою функцию DoubleRound с MODE_TICKVALUE (который равен 12,50) вместо MODE_TICKSIZE (0,25).
Значение тика определенно неправильное. Попробуйте вместо этого использовать ticksize:
double DoubleRound(double number, double step){
   return( MathRound(number/step)*step );
}
 
Уважаемые Raptor, WHRoeder и SDC,

Ошибка #130 stoploss больше не появляется. Последние шаги, похоже, окончательно определили проблему.
После этого я опубликую еще одно сообщение, в котором подытожу все предпринятые шаги. Чтобы другие участники форума, столкнувшиеся с ошибкой #130, могли использовать эту тему в качестве справочника.


Спасибо за вашу постоянную помощь :).

shinobi
 
shinobi:

Спасибо за вашу постоянную помощь :).

шиноби
Молодец, что не сдаешься... всегда есть объяснение, просто иногда бывает трудно его найти.
 
Ссылка на возможные причины ошибки #130: недействительный стоплосс.
  1. Общие советы
  2. ECN-брокер
  3. 4/5-значный брокер
  4. Изменение рыночных ставок
  5. Спред
  6. Уровень остановки
  7. Уровень заморозки
  8. Размер тика
  9. Полный пример
  10. Благодарности
  1. Общие советы
    Самым важным приемом борьбы с ошибками является чрезмерное протоколирование. Делайте вывод для всего, что может быть удаленно связано с ошибкой. Если вы определите функцию логирования, которую можно включать и выключать, вы сможете сохранить код после решения проблемы.
    При инициализации вашего эксперта вы должны записывать в журнал всю информацию, которую может сообщить вам MarketInfo: https://docs.mql4.com/constants/marketinfo.
    Также всегда проверяйте возвращаемые значения функций, например, для OrderModify:
    if (!OrderSelect(ticket, SELECT_BY_TICKET)) {
          int error_code = GetLastError();
          Print("Error: " + ErrorDescription(error_code));
          return(-1);
    }  


  2. ECN Broker
    ECN Broker требует, чтобы вы создавали отдельные ордера на покупку/продажу и стоплосс/тейкпрофит. Поэтому вам нужно разделить ваш код на два ордера следующим образом:
    int ticket = OrderSend(Symbol(), OP_BUY, 1, MarketInfo(Symbol(), MODE_ASK), 2, 0, 0, "", 12345);
    OrderSelect(ticket, SELECT_BY_TICKET);
    entry_price = OrderOpenPrice();
    OrderModify(ticket, entry_price, stoploss, takeprofit, 0);
    
    Для ордеров на продажу вам нужно заменить OP_BUY на OP_SELL. Вы также должны проверить возвращаемые значения OrderSelect и OrderModify (см. Общие советы выше).

  3. 4/5-значный брокер
    Некоторые брокеры требуют, чтобы стоплосс, тейкпрофит и проскальзывание были скорректированы до 4/5 цифр. Вы можете сделать это, поместив следующий код в функцию init() (спасибо WHRoeder):
    int     pips2points;    // slippage  3 pips    3=points    30=points
    double  pips2dbl;       // Stoploss 15 pips    0.0015      0.00150
    int     Digits.pips;    // DoubleToStr(dbl/pips2dbl, Digits.pips)
    
    //init digit adjustment
    if (Digits % 2 == 1) {      // DE30=1/JPY=3/EURUSD=5 forum.mql4.com/43064#515262
        pips2dbl    = Point*10; pips2points = 10;   Digits.pips = 1;
    } else {
        pips2dbl    = Point;    pips2points =  1;   Digits.pips = 0; 
    }
    Затем вам нужно умножить стоплосс, тейкпрофит и проскальзывание на pips2db1 перед отправкой брокеру.
    OrderModify(ticket, entry_price, stoploss * pips2points, takeprofit * pips2points, 0);

  4. Изменение рыночных курсов
    Другая возможная причина заключается в том, что рыночные курсы изменились между тиком, активировавшим советника (EA), и выполнением советником OrderSend() или OrderModify(). Чтобы избежать этой проблемы, есть два возможных решения:
    Первое - использовать: RefreshRates() перед использованием предопределенных рыночных переменных, таких как: Ask и Bid. (эти переменные получают свои значения, когда тик активирует советника).
    Второй - не использовать предопределенные рыночные переменные вообще. Вместо этого вы можете использовать текущие рыночные значения с помощью функции MarketInfo(). Вместо Ask, Bid и Point используйте
    MarketInfo(Symbol(), MODE_ASK)
    MarketInfo(Symbol(), MODE_BID)
    MarketInfo(Symbol(), MODE_POINT)
    

  5. Spread
    Если стоплосс или тейкпрофит находятся слишком близко к цене входа, ордер будет отклонен. Чтобы избежать этой проблемы, необходимо учитывать текущий спред между Ask и Bid. И снова есть два решения:
    Первое - рассчитать спред и прибавить/вычесть его к стоплоссу/такепрофиту.
    double spread = MarketInfo(Symbol(), MODE_ASK) - MarketInfo(Symbol(), MODE_BID);
    //buy
    stoploss = stoploss - spread;
    takeprofit = takeprofit + spread;
    //sell
    stoploss = stoploss + spread;
    takeprofit = takeprofit - spread;
    Второе решение - неявно учитывать спред, используя Ask и Bid, при расчете стоплосса или тейкпрофита:
    stoploss = 50
    takeprofit = 50
    //buy
    SL = MarketInfo(Symbol(), MODE_BID) - (stoploss * MarketInfo(Symbol(), MODE_POINT))
    TP = MarketInfo(Symbol(), MODE_ASK) + (takeprofit * MarketInfo(Symbol(), MODE_POINT))
    //sell
    SL = MarketInfo(Symbol(), MODE_ASK) + (stoploss * MarketInfo(Symbol(), MODE_POINT))
    TP = MarketInfo(Symbol(), MODE_BID) -  (takeprofit * MarketInfo(Symbol(), MODE_POINT))

  6. Уровень стопа
    У брокеров есть определенный уровень стопа. Если ваш стоплосс ниже этого уровня, ваш ордер будет отклонен. Вы можете проверить уровень стопа с помощью MarketInfo(Symbol(), MODE_STOPLEVEL).
    Чтобы избежать этого, сверьте свой стоплосс с уровнем стопа брокера и при необходимости скорректируйте его:
    double stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
    if(stoploss < stoplevel)
       stoploss = stoplevel + 1;

  7. Уровень заморозки
    Freeze Level - это аналогичная концепция. Ваш стоплосс также должен быть больше, чем уровень заморозки брокера. Вы можете проверить уровень заморозки с помощью MarketInfo(Symbol(), MODE_FREEZELEVEL).
    Чтобы избежать этого, снова проверьте свой стоплосс на соответствие уровню заморозки брокера:
    double freezelevel = MarketInfo(Symbol(), MODE_FREEZELEVEL);
    if(stoploss < freezelevel)
       stoploss = freezelevel + 1;

  8. Ticksize
    Наконец, ваш стоплосс или тейкпрофит может быть отклонен, потому что символ поддерживает только те стоплоссы/тейкпрофиты, которые соответствуют его тиковому размеру. Тиковый размер - это минимальное расстояние, на которое цена символа может подниматься и опускаться. Например, если цена равна 1000, а размер тика 0,25, то цена может подняться или опуститься только на величину, кратную 0,25 (0,25 * n, где n - натуральное число). Таким образом, цена может вырасти на 0,25 до 1000,25 или упасть на 1,75 до 998,25.
    Чтобы учесть размер тиков, нужна функция для округления двойных значений до определенного шага (например, ближайшего 0,25). Вот такая функция:
    double DoubleRound(double number, double step)
    {
        double mod = MathMod(number, step);
        if(mod < step/2.0)
          step = 0;
        double rounded = number - mod + step;
        return (rounded);
    }
    Например, вызов DoubleRound с числом = 1023.81234 и шагом = 0.25 вернет 1023.75. Вызов функции с числом 1023.967834 вернет 1024.00.
    Теперь перед отправкой стоплосса или тейкпрофита округлите его до размера тика символа с помощью:
    stoploss = (stoploss, MarketInfo(Symbol(), MODE_TICKSIZE));
    takeprofit = (takeprofit, MarketInfo(Symbol(), MODE_TICKSIZE));

  9. Полный пример
    Вот полный небольшой пример, учитывающий все вышеперечисленные меры противодействия:
    int init()
    {
        //for 4/5 Digits-Broker adjustment
        int     pips2points;    // slippage  3 pips    3=points    30=points
        double  pips2dbl;       // Stoploss 15 pips    0.0015      0.00150
        int     Digits.pips;    // DoubleToStr(dbl/pips2dbl, Digits.pips)
    
       //init digit adjustment
       if (Digits % 2 == 1) {      // DE30=1/JPY=3/EURUSD=5 forum.mql4.com/43064#515262
                   pips2dbl    = Point*10; pips2points = 10;   Digits.pips = 1;
       } else {
                   pips2dbl    = Point;    pips2points =  1;   Digits.pips = 0; 
       }
    
       Print("Date: " + Year() + "/" + Month() + "/" + Day() + " " + Hour() + ":" + Minute());
       Print("Symbol: " + Symbol());
       Print("Depot: " + AccountBalance());
       Print("Stop Level [Points]: " + MarketInfo(Symbol(), MODE_STOPLEVEL));
       Print("Freeze Level [Points]: " + MarketInfo(Symbol(), MODE_FREEZELEVEL));
       Print("Spread [Points]: " + MarketInfo(Symbol(), MODE_SPREAD));
       Print("Min/Max Lot: " + MarketInfo(Symbol(), MODE_MINLOT) + "/" + MarketInfo(Symbol(), MODE_MAXLOT));
       Print("Point: " + MarketInfo(Symbol(), MODE_POINT));
       Print("Tick Size: " + MarketInfo(Symbol(), MODE_TICKSIZE));
       Print("Tick Value: " + MarketInfo(Symbol(), MODE_TICKVALUE));
       Print("Digits: " + MarketInfo(Symbol(), MODE_DIGITS));
       Print("Contract: " + TimeToStr(MarketInfo(Symbol(), MODE_STARTING)) + "-" + TimeToStr(MarketInfo(Symbol(), MODE_EXPIRATION)));
    }
    
    //long = true: buy; long = false: sell
    int take_position(bool long)
    {
       int stoploss = 50;
       double SL = 0.0;
       int ticket = -1;
       
       //send order
       if(long)  //buy
          ticket = OrderSend(Symbol(), OP_BUY, 1, MarketInfo(Symbol(), MODE_ASK), 2, 0, 0, "", 1234);  
       else      //sell
          ticket = OrderSend(Symbol(), OP_SELL, 1, MarketInfo(Symbol(), MODE_BID), 2, 0, 0, "", 1234); 
    
       //check for errors
       if(result_ticket == -1) {
          int error_code = GetLastError();
          Print("Error: " + ErrorDescription(error_code));
          return(-1);
       }
       Print("order "+ticket+" successfully opened");
    
       //select order
       if (!OrderSelect(result_ticket, SELECT_BY_TICKET)) {
          int error_code = GetLastError();
          Print("Error: " + ErrorDescription(error_code));
          return(-1);
       }    
       double entry_price = OrderOpenPrice();
       
       //check stoplevel
       double stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
       Print("Stoplevel: " + stoplevel);
       if(stoploss < stoplevel)
          stoploss = stoplevel + 1;
    
       //check freezelevel
       double freezelevel = MarketInfo(Symbol(), MODE_FREEZELEVEL);
       Print("Freezelevel: " + freezelevel);
       if(stoploss < freezelevel)
          stoploss = freezelevel + 1;
    
       Print("adjusted stoploss: " + stoploss);
       
       //account for spread AND account for 4/5-Digit Brokers
       if(long)
          SL = MarketInfo(Symbol(), MODE_BID) - (stoploss * pips2dbl);
       else
          SL = MarketInfo(Symbol(), MODE_ASK) + (stoploss * pips2dbl);
       Print("SL: " + SL);
       
       //round to nearest Tickvalue   
       SL = DoubleRound(SL, MarketInfo(Symbol(), MODE_TICKSIZE));
       Print("SL rounded: " + SL);
       
       //set stoploss
       if(!OrderModify(result_ticket, entry_price, SL, 0, Red)) {
          int error_code = GetLastError();
          Print("Error: " + ErrorDescription(error_code));
          return(-1);
       }
    
       Print("Stoploss successfully set");
       return(0);
    }
    Надеюсь, это поможет избавиться от #130. Если модификация кода не помогает, используйте сначала минимальный пример, подобный приведенному выше. А затем, когда ошибка исчезнет, перенесите измененный пример в свой код.

    Удачи,
    шиноби

  10. Благодарности
    Моя благодарность Raptor, WHRoeder, SDC, BigAl, gjol и 35806 за помощь в избавлении от ошибки и составлении этой справки.