バックテストでは正常に稼働するけど、リアル口座では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回ほどリトライさせてます。やってみると分かるのですが、結構失敗します。
上記は、以下の方の処理を参考にさせて頂きました。
損切り、利益の価格が狭い時も発生
現在価格と比べて、損切りや、利益の金額設定が近すぎる時も、エラーコード130が発生します。ここで関係があるのが、ストップレベルです。
MQL4の公式ページに、これについて言及があります。


結構盲点だったかも。
ストップレベルの確認方法は通貨ごと
最小設定値は、取引所ごと、通貨毎に異なります。
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のままなので、オーダーが残ったままになります。


うーん、困ったね。みんなどうしてんだろ。。
多少スリープかませるかとか、色々実験中です。








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