Ho bisogno di aiuto con l'errore #130 stoploss non valido - pagina 4

 
Grazie per averlo notato Raptor.
Ho chiamato la mia funzione DoubleRound con MODE_TICKVALUE (che è 12,50) invece di MODE_TICKSIZE (0,25).

L'ho corretto, ma non ha fatto sparire il #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);

Ecco un log dell'errore con la linea DoubleRound aggiornata:

#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

per confronto, ecco un log dove ha funzionato:

#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

in ogni caso, sembra funzionare più spesso ora, ci stiamo sicuramente avvicinando :)
 
shinobi:

in ogni caso, sembra funzionare più spesso ora, ci stiamo sicuramente avvicinando :)

Non riesco a capire perché quella modifica è fallita... stai ricevendo un nuovo Bid/Ask tra OrderSend e OrderModify?

Tutto quello che posso suggerire ora è che quando ottieni un errore 130. . . stampi tutto di nuovo, Bid, Ask (usando MarketInfo), OOP, StopLevel, SL che stai cercando di impostare, ecc, ecc.

 
shinobi:
Ho chiamato la mia funzione DoubleRound con MODE_TICKVALUE (che è 12,50) invece di MODE_TICKSIZE (0,25).
Il valore di tick è sicuramente sbagliato. Prova questo invece con ticksize:
double DoubleRound(double number, double step){
   return( MathRound(number/step)*step );
}
 
Cari Raptor, WHRoeder e SDC,

L'errore #130 stoploss non appare più. Gli ultimi passi sembrano aver finalmente individuato il problema.
Pubblicherò un altro post dopo questo, riassumendo tutti i passi fatti. Così altri nel forum che combattono l'errore #130 possono usare questo thread come riferimento.


Grazie per il vostro continuo aiuto :).

shinobi
 
shinobi:

Grazie per il vostro continuo aiuto :).

shinobi
Ben fatto per aver continuato... c'è sempre una spiegazione, solo che a volte può essere difficile trovarla.
 
Riferimento per le possibili cause dell'errore #130: stoploss non valido.
  1. Suggerimenti generali
  2. Broker ECN
  3. Broker a 4/5 cifre
  4. Cambiare i tassi di mercato
  5. Spread
  6. Livello di stop
  7. Livello di congelamento
  8. Ticksize
  9. Esempio completo
  10. Riconoscimenti
  1. Suggerimenti generali
    La tecnica più importante per combattere gli errori è un log eccessivo. Fate output per tutto ciò che potrebbe essere collegato in modo remoto all'errore. Se definisci una funzione di log che puoi attivare e disattivare, puoi mantenere il codice dopo aver risolto il problema.
    Quando inizializzi il tuo consulente esperto dovresti registrare tutte le informazioni che MarketInfo può dirti: https://docs.mql4.com/constants/marketinfo
    Inoltre assicuratevi sempre di controllare i valori di ritorno delle funzioni, ad esempio per OrderModify:
    if (!OrderSelect(ticket, SELECT_BY_TICKET)) {
          int error_code = GetLastError();
          Print("Error: " + ErrorDescription(error_code));
          return(-1);
    }  


  2. Broker ECN
    ECN Broker richiede di fare ordini separati per comprare/vendere e stoploss/takeprofit. Quindi devi dividere il tuo codice in due ordini come questo:
    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);
    
    Per gli ordini di vendita dovete sostituire OP_BUY con OP_SELL. Dovresti anche controllare i valori di ritorno di OrderSelect e OrderModify (vedi Consigli generali sopra).

  3. Broker a 4/5 cifre
    Alcuni Broker richiedono che stoploss, takeprofit e slippage siano regolati a 4/5 cifre. Potete farlo mettendo il seguente codice nella vostra funzione init() (grazie a 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; 
    }
    Poi dovete moltiplicare stoploss, takeprofit e slippage con pips2db1 prima di inviarlo al Broker
    OrderModify(ticket, entry_price, stoploss * pips2points, takeprofit * pips2points, 0);

  4. Cambiamento dei tassi di mercato
    Un'altra possibile causa è che i tassi di mercato sono cambiati tra il tick attivato l'Expert Advisor (EA), e l'EA OrderSend() o OrderModify() è stato eseguito. Per evitare questo problema, ci sono due possibili soluzioni:
    La prima è quella di utilizzare : RefreshRates() prima di usare variabili di mercato predefinite come: Ask e Bid. (queste variabili ottengono i loro valori quando il tick attiva l'EA)
    La seconda è quella di non usare affatto le variabili di mercato predefinite. Invece puoi usare i valori attuali del mercato con MarketInfo(). Invece di Ask, Bid e Point usa
    MarketInfo(Symbol(), MODE_ASK)
    MarketInfo(Symbol(), MODE_BID)
    MarketInfo(Symbol(), MODE_POINT)
    

  5. Spread
    Se lo stoploss o il takeprofit sono troppo vicini al prezzo di entrata, l'ordine verrà rifiutato. Per evitare questo problema, si dovrebbe prendere in considerazione lo spread attuale tra Ask e Bid. Anche in questo caso ci sono due soluzioni:
    La prima è quella di calcolare lo spread e aggiungerlo/sottrarlo al vostro 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 seconda soluzione è quella di prendere implicitamente in considerazione lo spread usando Ask e Bid, quando si calcola lo stoploss o il 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. Livello di stop
    I broker hanno un certo livello di stop. Se il vostro stoploss è al di sotto di tale livello, il vostro ordine sarà rifiutato. Potete controllare il livello di stop con MarketInfo(Symbol(), MODE_STOPLEVEL).
    Per evitare questo, controllate il vostro stoploss rispetto al livello di stop del broker e regolatelo se necessario:
    double stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL);
    if(stoploss < stoplevel)
       stoploss = stoplevel + 1;

  7. Freeze Level
    Freeze Level è un concetto simile. Anche il vostro stopploss deve essere maggiore del livello di congelamento del broker. Potete controllare il livello di congelamento tramite MarketInfo(Symbol(), MODE_FREEZELEVEL).
    Per evitare questo, controllate di nuovo il vostro stoploss rispetto al livello di congelamento del broker:
    double freezelevel = MarketInfo(Symbol(), MODE_FREEZELEVEL);
    if(stoploss < freezelevel)
       stoploss = freezelevel + 1;

  8. Ticksize
    Infine il vostro stoploss o takeprofit potrebbe essere rifiutato, perché il simbolo supporta solo stoploss/takeprofit che corrispondono al suo ticksize. Il ticksize è la distanza minima che il premio del simbolo può salire e scendere. Per esempio, se il prezzo è 1000 e il ticksize 0.25, allora il prezzo può salire o scendere solo di un multiplo di 0.25 (0.25 * n, dove n è un numero naturale). Quindi il prezzo potrebbe salire di 0,25 a 1000,25 o scendere di 1,75 a 998,25.
    Per tenere conto del ticksize, avete bisogno di una funzione che arrotonda i valori doppi ad un certo valore di passo (ad esempio il più vicino 0,25). Ecco una tale funzione:
    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);
    }
    Ad esempio chiamando DoubleRound con numero = 1023.81234 e passo = 0.25 si ottiene 1023.75. Chiamandola con 1023.967834 restituirebbe 1024.00
    Ora, prima di inviare lo stoploss o il takeprofit, arrotondate al ticksize del Symbol con:
    stoploss = (stoploss, MarketInfo(Symbol(), MODE_TICKSIZE));
    takeprofit = (takeprofit, MarketInfo(Symbol(), MODE_TICKSIZE));

  9. Esempio completo
    Ecco un piccolo esempio completo che tiene conto di tutte le contromisure di cui sopra:
    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);
    }
    Spero che questo aiuti a sbarazzarsi di #130. Se la modifica del vostro codice non funziona, usate prima un esempio minimo, come quello sopra. E poi, quando l'errore scompare, riprendete la modifica nel vostro codice.

    Buona fortuna,
    shinobi

  10. Ringraziamenti
    I miei ringraziamenti a Raptor, WHRoeder, SDC, BigAl, gjol e 35806 per avermi aiutato ad eliminare l'errore e a mettere insieme questo riferimento.