MQL4でOrderSendエラーコード130 invalid stopsの解決策

※本ページはプロモーションが含まれています

バックテストでは正常に稼働するけど、リアル口座ではOrderSend時に、エラーコード130(Invalid Stops)が出てしまう。かなりあれこれ調べまくって、なんとかある程度は解決しました。記事に残しておこうと思います。普通に仕様通りにプログラム組むだけではだめで、対処は必須ですね。

目次

エラーコード130の意味

主に以下です。

  • 損切りや利益の設定価格が今現在価格にとても近い
  • 損切り、利益の計算が正しくない
  • 損切り、利益の小数点の桁数が多すぎる

取引所によってはOrderSend時にSL、TPを設定するとエラー

なんと、取引所によっては、OrderSend時に、引数でSL、TPを設定するとエラーになるそうです。マジかよ~。

矢野テック
矢野テック

XMはたまに通るけどエラーが帰って来るときもありました。

 

その場合は、損切り、利益は0で設定して、OrderModifyで変更するのが鉄板らしい。

ただし、成功しないときもある(マジかよ~)

 

以下のようにする事で対処しました。Long、Short、それぞれ用でオリジナル関数を作りました。こうすることで、メイン処理がごちゃつかない。

//+------------------------------------------------------------------+
//| ロング
//| OP_BUYのエントリー。リトライあり
//| 引数: my_lot = ロット
//|       my_slipage = スリッページ
//|       my_sl = 損切り(pips)
//|       my_tp = 利益(pips)
//+------------------------------------------------------------------+
void Org_Long(double my_lot,int my_slipage , double my_sl, double my_tp){

   //ticket no
   int ticket_no=0;
   int errorcode=0;               // エラーコード

   double losscut_normalize=0;
   double profit_normalize=0;
   double losscut_rate=0;
   double profit_rate=0;

   // ロスカット価格
   losscut_rate  = Ask - ( 10 * Point() * my_sl); 

   // 決済価格
   profit_rate   = Ask + ( 10 * Point() * my_tp); 


   //正規化
   losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
   profit_normalize  = NormalizeDouble(profit_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));


   //ロングエントリー処理
   ticket_no = OrderSend(Symbol(),OP_BUY,my_lot,Ask,my_slipage,losscut_normalize,profit_normalize,"Buy order",MAGIC,0,clrBlue);
   printf("OrderSend OP_BUY , price=%f , sl=%f , tp=%f",Ask,losscut_normalize,profit_normalize);

   if(ticket_no < 0){
      errorcode = GetLastError();      // エラーコード取得
      printf("Send Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode));

      //再設定
      losscut_rate  = Ask - ( 10 * Point() * my_sl); 
      profit_rate   = Ask + ( 10 * Point() * my_tp); 
      losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
      profit_normalize  = NormalizeDouble(profit_normalize,int(MarketInfo(Symbol(),MODE_DIGITS)));

      //オーダー送信と同時に損切り、利益設定エラー対策
      ticket_no = OrderSend(Symbol(),OP_BUY,my_lot,Ask,my_slipage,0,0,"Buy order",MAGIC,0,clrBlue);
      printf("Resend OrderSend OP_BUY , price=%f , sl=%f , tp=%f",Ask,losscut_normalize,profit_normalize);

      //オーダー修正
      LimitStop_Set(ticket_no,OP_BUY,clrBlue);

   }else {
      printf("Send Done. Ticket NO = %d",ticket_no);
   }
}

//+------------------------------------------------------------------+
//| ショート
//| OP_SELLのエントリー。リトライあり
//| 引数: my_lot = ロット
//|       my_slipage = スリッページ
//|       my_sl = 損切り
//|       my_tp = 利益
//+------------------------------------------------------------------+
void Org_Short(double my_lot,int my_slipage , double my_sl, double my_tp){

   //ticket no
   int ticket_no=0;
   int errorcode=0;               // エラーコード

   double losscut_normalize=0;
   double profit_normalize=0;
   double losscut_rate=0;
   double profit_rate=0;

  // ロスカット価格
   losscut_rate  = Bid + ( 10 * Point() * my_sl); 

   // 決済価格
   profit_rate   = Bid - ( 10 * Point() * my_tp); 


   //正規化
   losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
   profit_normalize  = NormalizeDouble(profit_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));


   //shortエントリー処理
   ticket_no = OrderSend(Symbol(),OP_SELL,my_lot,Bid,my_slipage,losscut_normalize,profit_normalize,"Sell order",MAGIC,0,clrRed);
   printf("OrderSend OP_SELL , price=%f , sl=%f , tp=%f",Bid,losscut_normalize,profit_normalize);

   //エラー?
   if(ticket_no < 0){
      errorcode = GetLastError();      // エラーコード取得
      printf("Send Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode));
 
     // 再設定
      losscut_rate  = Bid + ( 10 * Point() * my_sl); 
      profit_rate   = Bid - ( 10 * Point() * my_tp); 
      losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
      profit_normalize  = NormalizeDouble(profit_normalize,int(MarketInfo(Symbol(),MODE_DIGITS)));

      //オーダー送信と同時に損切り、利益設定エラー対策
      ticket_no = OrderSend(Symbol(),OP_SELL,my_lot,Bid,my_slipage,0,0,"Sell order",MAGIC,0,clrRed);
      printf("Resend sOrderSend OP_SELL , price=%f , sl=%f , tp=%f",Bid,losscut_normalize,profit_normalize);

      //オーダー修正
      LimitStop_Set(ticket_no,OP_SELL,clrRed);


   }else {
      printf("Send Done. Ticket NO = %d",ticket_no);
   }

}

 

オーダー修正するリトライ部分は以下のような関数を作りました。

//+------------------------------------------------------------------+
//| エントリー中のポジションのリミット・ストップを変更
//| 引数 int in_ticket_no = Ticket no
//|     double my_sl = Stopp Loss
//|     double my_tp = Take Profit
//+------------------------------------------------------------------+
// 
void LimitStop_Set( int in_ticket_no, int buysell_type , color mycolor) {

    int    modify_resend_num;       // 変更試行回数
    bool   modify_ret;              // 変更判定
    int    errorcode;
    bool   selbool;
    double limit_rate,stop_rate;
    int    my_ticket_no;

    // オーダー中のチケット選択(チケットNo指定)
    selbool = OrderSelect(in_ticket_no, SELECT_BY_TICKET); 

    if (buysell_type == OP_BUY){
       limit_rate = OrderOpenPrice() + ( 10 * Point() * Profitrate);
       stop_rate  = OrderOpenPrice() - ( 10 * Point() * SLrate);
     }else{
       limit_rate = OrderOpenPrice() - ( 10 * Point() * Profitrate);
       stop_rate  = OrderOpenPrice() + ( 10 * Point() * SLrate);
    }

    limit_rate = NormalizeDouble(limit_rate , int(MarketInfo(Symbol(),MODE_DIGITS)));  // リミット価格    を正規化
    stop_rate  = NormalizeDouble(stop_rate  , int(MarketInfo(Symbol(),MODE_DIGITS)) );  // ストップロス価格を正規化

    my_ticket_no = OrderTicket();

    for( modify_resend_num = 0; modify_resend_num < 30; modify_resend_num++ ) {
        modify_ret = OrderModify(
                                 my_ticket_no,      // チケットNo
                                 OrderOpenPrice(),  // 注文価格
                                 stop_rate,            // ストップロス価格
                                 limit_rate,           // リミット価格
                                 OrderExpiration(), // 有効期限
                                 mycolor               // 色

                     );

        printf("OrderModify ticket_no:%d , sl=%f , tp=%f",my_ticket_no , stop_rate,limit_rate);

        if ( modify_ret == false ) {             // 注文変更拒否
            Sleep(300);                         // 300msec待ち
            errorcode = GetLastError();        // エラーコード取得
            printf( "[%d]Modify Error! error_code:%d ,detail:%s ",
                                        modify_resend_num+1, errorcode ,  ErrorDescription(errorcode));
        } else {                                 // 決済注文約定
            Print("Done. Ticket NO=",in_ticket_no);
            break;
        }
    }
}
矢野テック
矢野テック

30回ほどリトライさせてます。やってみると分かるのですが、結構失敗します。

 

上記は、以下の方の処理を参考にさせて頂きました。

あわせて読みたい
OrderModify | MT4でEA自作しちゃお~ 当サイトはMetaQuotes Software社のMT4(メタトレーダー4)で、EA(自動売買)やカスタムインジケータを作成したいけど・・・ まず何をやったらいいのか分からずスタート地点で...

損切り、利益の価格が狭い時も発生

現在価格と比べて、損切りや、利益の金額設定が近すぎる時も、エラーコード130が発生します。ここで関係があるのが、ストップレベルです。

 

MQL4の公式ページに、これについて言及があります。

あわせて読みたい
Requirements and Limitations in Making Trades - Appendixes - MQL4 Tutorial Requirements and Limitations in Making Trades - Appendixes - MQL4 Tutorial
矢野テック
矢野テック

結構盲点だったかも。

ストップレベルの確認方法は通貨ごと

最小設定値は、取引所ごと、通貨毎に異なります。

 

MT4上で、該当通貨にて「右クリック」⇒「仕様

 

ストップレベルは40と表示されています。これは、単位はポイントです。10分の1にすれば、pipsで表せます。

上記はXMTradingのUSDJPYのペアの表示。OrderSend時に損切り、利確最低ともに、4pipsは空けないといけないということが分かります。

選択通貨のストップレベルの取得

MarketInfo関数を使います。

int my_stop_level = MarketInfo(Symbol(), MODE_STOPLEVEL);

小数点の桁数も重要

同じく小数点の桁数もかなり重要です。XMTradingのUSDJPYでは、3桁です。

ところが、普通にMQL4でdouble型で扱うと、小数点はdoubleの型の有効桁数で扱われます。桁数は15桁。

これも、桁数を揃えないと、リアルトレードでエラー130が発生します。

選択した通貨の桁数をチェックするには?

MarketInfoを使って、2番めの引数に、DIGITSを渡すと、チャート上の通貨の有効桁数が帰ってきます。

int ketasuu = MarketInfo(Symbol(),MODE_DIGITS);

小数点の桁数を丸めるには?

NormalizeDouble関数を使います。1番めの引数は丸めたい数値、2番めは桁数です。

double my_normalize = NormalizeDouble(数値,int(MarketInfo(Symbol(),MODE_DIGITS)));

 

それでもポジションが残る事もあり

これで解決かと思ったんですが、30回リトライしても、SL、TPが設定できないときがあります。その場合は、逆指値、指値、ともに0のままなので、オーダーが残ったままになります。

 

矢野テック
矢野テック

うーん、困ったね。みんなどうしてんだろ。。

多少スリープかませるかとか、色々実験中です。

 

ブログランキングに参加してます。この記事が少しでもお役に立ちましたら、応援ポチっとお願いします。

にほんブログ村 為替ブログ システムトレード 自作EA派へ
にほんブログ村

お友達にMT4インジケータープレゼント中

機械学習使った日々の予測結果や、細かい試行錯誤の結果はLINEで公開しています。パスワード付き記事もこちらから。

また、今ならお友達には矢野テック自作のMT4用のインジケーターをプレゼント中です。

友だち追加

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

プログラマー。FXのMT4を使った自動売買EA作成やBOT作成などが趣味。2016年から元本10万円をどこまで増やせるか挑戦中。一旦は10万⇒700万⇒2017暴落 20万。ガチホからFXトレードに変更。 現在1000万円。その過程やノウハウは無料メール講座にまとめました。1か月で学べます。→無料メール講座

ご質問はコメント欄からお願いします

コメントする

目次