Necesito ayuda con el error #130 stoploss inválido - página 4

 
Gracias por notarlo Raptor.
Llamé a mi función DoubleRound con MODE_TICKVALUE (que es 12,50) en lugar de MODE_TICKSIZE (0,25).

Lo arreglé, pero no hizo desaparecer el #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);

Aquí hay un registro del error con la línea actualizada de 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

para comparar, aquí hay un registro, donde funcionó:

#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

en cualquier caso, parece que funciona más a menudo ahora, definitivamente estamos acercando. :)
 
shinobi:

en cualquier caso, parece que ahora funciona más a menudo, definitivamente nos estamos acercando. :)

No veo por qué ha fallado la modificación... ¿obtienes un Bid/Ask nuevo entre el OrderSend y el OrderModify?

Todo lo que puedo sugerir ahora es que cuando se obtiene un error 130. . . imprima todo de nuevo, Bid, Ask (usando MarketInfo), OOP, StopLevel, SL que está tratando de establecer, etc, etc.

 
shinobi:
Llamé a mi función DoubleRound con MODE_TICKVALUE (que es 12,50) en lugar de MODE_TICKSIZE (0,25).
El valor del tick es definitivamente incorrecto. Pruebe esto en su lugar con ticksize:
double DoubleRound(double number, double step){
   return( MathRound(number/step)*step );
}
 
Estimados Raptor, WHRoeder y SDC,

El error de stoploss #130 ya no aparece. Los últimos pasos parecían haber solucionado finalmente el problema.
Voy a publicar otro post después de esto, resumiendo todos los pasos realizados. Así que otros en el foro que luchan contra el error # 130 puede utilizar este hilo como una referencia.


Gracias por su ayuda continua :).

shinobi
 
shinobi:

Gracias por tu ayuda continua :).

shinobi
Bien hecho por seguir con ello... siempre hay una explicación, sólo que a veces puede ser difícil encontrarla.
 
Referencia de las posibles causas del Error #130: stoploss inválido.
  1. Consejos generales
  2. Corredor ECN
  3. Broker de 4/5 dígitos
  4. Cambios en los tipos de mercado
  5. Spread
  6. Nivel de parada
  7. Nivel de congelación
  8. Tamaño de los Ticks
  9. Ejemplo completo
  10. Agradecimientos
  1. Consejos generales
    La técnica más importante para combatir los errores es el registro excesivo. Haga una salida para todo lo que pueda estar remotamente relacionado con el error. Si define una función de registro que pueda activar y desactivar, podrá conservar el código después de haber resuelto el problema.
    Al inicializar su asesor experto debe registrar toda la información que MarketInfo le pueda decir: https://docs.mql4.com/constants/marketinfo
    Además, asegúrese siempre de comprobar los valores de retorno de las funciones, por ejemplo, para OrderModify:
    if (!OrderSelect(ticket, SELECT_BY_TICKET)) {
          int error_code = GetLastError();
          Print("Error: " + ErrorDescription(error_code));
          return(-1);
    }  


  2. ECN Broker
    ECN Broker requiere que usted haga órdenes separadas para comprar/vender y stoploss/takeprofit. Por lo tanto, usted necesita dividir su código en dos órdenes como esta:
    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);
    
    Para las órdenes de venta necesitas reemplazar OP_BUY por OP_SELL. También debe comprobar los valores de retorno de OrderSelect y OrderModify (ver Consejos Generales más arriba).

  3. Broker de 4/5 dígitos
    Algunos Brokers exigen que el stoploss, el takeprofit y el slippage se ajusten a 4/5 dígitos. Puede hacerlo poniendo el siguiente código en su función init() (thx 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; 
    }
    Entonces necesitas multiplicar stoploss, takeprofit y slippage con pips2db1 antes de enviarlo al Broker
    OrderModify(ticket, entry_price, stoploss * pips2points, takeprofit * pips2points, 0);

  4. Cambio de las tasas de mercado
    Otra posible causa es que las tasas de mercado cambiaron entre el tick activado el Asesor Experto (EA), y el EA OrderSend() o OrderModify() fue ejecutado. Para evitar este problema, hay dos posibles soluciones:
    La primera es utilizar RefreshRates() antes de utilizar variables de mercado predefinidas como: Ask y Bid. (estas variables obtienen sus valores cuando el tick activa el EA)
    La segunda es no utilizar las variables de mercado predefinidas en absoluto. En su lugar puede utilizar los valores actuales del mercado con MarketInfo(). En lugar de Ask, Bid y Point utilice
    MarketInfo(Symbol(), MODE_ASK)
    MarketInfo(Symbol(), MODE_BID)
    MarketInfo(Symbol(), MODE_POINT)
    

  5. Spread
    Si el stoploss o el takeprofit están demasiado cerca del precio de entrada, la orden será rechazada. Para evitar este problema, debe tener en cuenta el spread actual entre Ask y Bid. De nuevo hay dos soluciones:
    La primera es calcular el spread y sumarlo/restarlo a su stoploss/takeprofit.
    double spread = MarketInfo(Symbol(), MODE_ASK) - MarketInfo(Symbol(), MODE_BID);
    //buy
    stoploss = stoploss - spread;
    takeprofit = takeprofit + spread;
    //sell
    stoploss = stoploss + spread;
    takeprofit = takeprofit - spread;
    La segunda solución es tener en cuenta implícitamente el spread utilizando el Ask y el Bid, al calcular el stoploss o el takeprofit:
    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. Nivel de Stop
    Los corredores tienen un determinado nivel de stop. Si su stoploss está por debajo de ese nivel, su orden será rechazada. Puede comprobar el nivel de stop con MarketInfo(Symbol(), MODE_STOPLEVEL).
    Para evitar esto compruebe su stoploss con el nivel de stop del broker y ajústelo si es necesario:
    double stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
    if(stoploss < stoplevel)
       stoploss = stoplevel + 1;

  7. Nivel de congelación
    Freeze Level es un concepto similar. Su stoploss también tiene que ser mayor que el nivel de congelación del broker. Puede comprobar el nivel de congelación mediante MarketInfo(Symbol(), MODE_FREEZELEVEL).
    Para evitar esto, compruebe de nuevo su stoploss con el nivel de congelación del broker:
    double freezelevel = MarketInfo(Symbol(), MODE_FREEZELEVEL);
    if(stoploss < freezelevel)
       stoploss = freezelevel + 1;

  8. Ticksize
    Finalmente su stoploss o takeprofit podría ser rechazado, porque el símbolo sólo admite stoploss/takeprofit que coincidan con su ticksize. El ticksize es la distancia mínima que el precio del símbolo puede subir y bajar. Por ejemplo, si el precio es 1000 y el tamaño del ticksize 0,25, entonces el precio sólo puede subir o bajar un múltiplo de 0,25 (0,25 * n, donde n es un número natural). Así que el precio puede subir 0,25 hasta 1000,25 o bajar 1,75 hasta 998,25.
    Para tener en cuenta el tamaño de los ticks, se necesita una función que redondee los valores dobles a un determinado valor de paso (por ejemplo, el 0,25 más cercano). Esta es una función de este tipo:
    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);
    }
    Por ejemplo, si se llama a DoubleRound con number = 1023.81234 y step = 0.25, se obtendrá 1023.75. Llamándola con 1023.967834 devolvería 1024.00
    Ahora, antes de enviar el stoploss o el takeprofit, redondea al tamaño de los ticks del símbolo con:
    stoploss = (stoploss, MarketInfo(Symbol(), MODE_TICKSIZE));
    takeprofit = (takeprofit, MarketInfo(Symbol(), MODE_TICKSIZE));

  9. Ejemplo completo
    Aquí hay un pequeño ejemplo completo teniendo en cuenta todas las medidas de contador anteriores:
    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);
    }
    Espero que esto ayude a deshacerse del #130. Si la modificación de tu código no funciona, utiliza primero un ejemplo mínimo, como el de arriba. Y luego, cuando el error desaparezca, retoma lo modificado en tu código.

    Buena suerte,
    shinobi

  10. Agradecimientos
    Mi agradecimiento a Raptor, WHRoeder, SDC, BigAl, gjol y 35806 por ayudarme a deshacerme del error y a elaborar esta referencia.