エラー#130 invalid stoplossに関するヘルプが必要です。 - ページ 4

 
Raptorさん、お気づきいただきありがとうございます。
MODE_TICKSIZE(0.25)ではなく、MODE_TICKVALUE(12.50です)でDoubleRound関数を呼び出して いました。

直したのですが、#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:

いずれにせよ、今はもっと頻繁に動いているようで、確実に近づいています。)

修正に失敗した理由がわかりません ... OrderSend と OrderModify の間に新しい Bid/Ask を取得していますか?

私が今提案できるのは、エラー130が 出たときに、Bid, Ask (using MarketInfo), OOP, StopLevel, 設定しようとしているSLなど、すべてを新しくプリントすることです。

 
shinobi:
MODE_TICKSIZE (0.25) の代わりに MODE_TICKVALUE (12.50) を指定して DoubleRound 関数を呼び出したのですが、どうすればよいですか?
ティックバリューは間違いなく間違っています。代わりにticksizeでこれを試してみてください。
double DoubleRound(double number, double step){
   return( MathRound(number/step)*step );
}
 
Raptorさん、WHRoederさん、SDCさんへ。

130のストップロス・エラーは出なくなりました。最後のステップでようやく問題を突き止めたようです。
この後、すべてのステップをまとめた別の投稿をします。そうすれば、フォーラムでエラー#130と戦っている他の人たちは、このスレッドを参考として使うことができます。


継続的な助けに感謝します :).

shinobi
 
shinobi:

これからもよろしくお願いします :)

シノビ
よく頑張りましたね。 ...必ず説明はあるのですが、それを見つけるのが難しいことがある、というだけです。
 
Error #130: invalid stoplossの考えられる原因についての参考資料です。
  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ブローカー
    ECNブローカーは、買い/売りとストップロス/テイクプロフィットのための別々の注文を行う必要があります。そこで、次のようにコードを2つの注文に分割する必要があります。
    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()関数に入れれば、それが可能になります(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; 
    }
    次に、ブローカーに送信する前に、stoploss、takeprofit、slippageにpips2db1を乗じる必要があります。
    OrderModify(ticket, entry_price, stoploss * pips2points, takeprofit * pips2points, 0);

  4. 市場レートの変更
    もう1つの考えられる原因は、ティックがExpert Advisor(EA)をアクティブにしてから、EA OrderSend()またはOrderModify()が実行される間に市場レートが変更されたことです。この問題を回避するために、2つの解決策があります。
    1つ目は、RefreshRates()を使用することです。1つ目は、以下のような定義済みの市場変数を使用する前に、RefreshRates() を使用することです。アスクやビッドなどの定義済み市場変数を使用する前に、RefreshRates()を使用することです。(これらの変数は、ティックがEAをアクティブにしたときに値を取得します)
    もう一つは、定義済みの市場変数を全く使用しないことです。その代わりに、MarketInfo()で現在の市場の値を使用することができます。アスク、ビッド、ポイントの代わりに
    MarketInfo(Symbol(), MODE_ASK)
    MarketInfo(Symbol(), MODE_BID)
    MarketInfo(Symbol(), MODE_POINT)
    

  5. スプレッド
    ストップロスやテイクプロフィットがエントリー価格に近すぎる場合、注文は拒否されます。この問題を回避するためには、AskとBidの間の現在のスプレッドを考慮する必要があります。ここでも2つの解決策があります。
    1つ目は、スプレッドを計算し、それをストップロス/テイクプロフィットに加算/減算する方法です。
    double spread = MarketInfo(Symbol(), MODE_ASK) - MarketInfo(Symbol(), MODE_BID);
    //buy
    stoploss = stoploss - spread;
    takeprofit = takeprofit + spread;
    //sell
    stoploss = stoploss + spread;
    takeprofit = takeprofit - spread;
    もう一つは、ストップロスやテイクプロフィットを計算する際に、アスクとビッドを用いて暗黙のうちにスプレッドを考慮する方法です。
    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. ティックサイズ
    最後に、ストップロスやテイクプロフィットは拒否されるかもしれません。なぜなら、シンボルはそのティックサイズに一致するストップロスやテイクプロフィットしかサポートしていないからです。ティックサイズとは、シンボルの価格が上下する最小距離のことです。例えば、価格が1000でticksizeが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);
    }
    例えば、数値 = 1023.81234 とステップ = 0.25 で DoubleRound を呼び出すと、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番を取り除くのに役立つことを願っています。もし、コードを変更してもうまくいかない場合は、まず、上記のような最小限の例を使ってみてください。そして、エラーが出なくなったら、変更したものを自分のコードに取り込んでください。

    幸運を祈ります。
    shinobi

  10. 謝辞
    Raptorさん、WHRoederさん、SDCさん、BigAlさん、gjolさん、35806さん、エラーの解消とこのリファレンスをまとめるのに協力していただきありがとうございました。