複数のポジションを持つEAに使う
ナンピン等を行うEAの場合、複数のポジションを持つことになります。複数のポジションを纏めて1つの動きになるようなEAの場合、一括決済が必要になることがあります。
そんな時のために、複数のポジションを全て決済する関数を紹介します。
//+------------------------------------------------------------------+
//|【関数】指定マジックナンバーのポジション全決済 |
//| |
//|【引数】 IN OUT 引数名 説明 |
//| --------------------------------------------------------- |
//| ○ aMagic マジックナンバー |
//| ○ aSlippage 許容スリッページ |
//| △ aComment 対象コメント |
//| |
//|【戻値】なし |
//| |
//|【備考】△:既定値あり |
//+------------------------------------------------------------------+
void allOrderClose(int aMagic, int aSlippage, string aComment = "")
{
for(int i = OrdersTotal() - 1; i >= 0; i--){
if(OrderSelect(i, SELECT_BY_POS) == false){
break;
}
if(OrderSymbol() != Symbol() || OrderMagicNumber() != aMagic){
continue;
}
if(aComment != "" && OrderComment() != aComment){
continue;
}
int type = OrderType();
if(type != OP_BUY && type != OP_SELL){
continue;
}
int ticket = OrderTicket();
Print("Attempted allOrderClose(" + aMagic + ", " + aSlippage + ", Comment:" + aComment + ")");
bool result = orderCloseReliable(ticket, OrderLots(), OrderClosePrice(), aSlippage);
if(result == false){
Print("allOrderClose: Ticket #", ticket, ", failed to close");
}
}
}
上記の関数を「OrderHandle.mqh」に追加しました。
特に難しい仕組みはありません。OrdersTotal()で現在持っているオーダー数を取得し、約定済のオーダー(ポジション)だけに絞り込んだ上で、仕切り注文関数を繰り返し実行するだけです。
ただし、注意しなければならないことが1つあります。それは、ポジションを決済するまたは待機注文を削除すると、その注文より後に出した注文のインデックスが1だけ小さくなることです。そのため、複数のポジションを決済するか複数の待機注文を削除する場合は、後の注文から順(降順)に処理する必要があります。古いものから順(昇順)に処理すると、1つずつ注文がスキップされることになります。
例えば、0,1,2という3つのポジションがあったと仮定しましょう。0番のポジションを決済した時に、残りの1,2が0,1になります。そして、次の1番のポジションを決済しようとするので、結果として0(最初の1)のポジションが決済されずに残ることになります。
また、注文時のコメントが引数にあるのには疑問を抱くかもしれません。これは、同じマジックナンバーのポジションの中で各ポジションを識別しなければならない時に、その識別用にコメントを使うことがあるためです。まぁ普段はあまり使いませんので、気にしなくても良いかと思います。
上記の関数とほぼ同じ作りで、複数の待機注文を全て削除(取消し)する関数も作れます。
//+------------------------------------------------------------------+
//|【関数】指定マジックナンバーの待機注文全削除 |
//| |
//|【引数】 IN OUT 引数名 説明 |
//| --------------------------------------------------------- |
//| ○ aMagic マジックナンバー |
//| △ aComment 対象コメント |
//| |
//|【戻値】なし |
//| |
//|【備考】△:既定値あり |
//+------------------------------------------------------------------+
void allOrderDelete(int aMagic, string aComment = "")
{
for(int i = OrdersTotal() - 1; i >= 0; i--){
if(OrderSelect(i, SELECT_BY_POS) == false){
break;
}
if(OrderSymbol() != Symbol() || OrderMagicNumber() != aMagic){
continue;
}
if(aComment != "" && OrderComment() != aComment){
continue;
}
int type = OrderType();
if(type == OP_BUY || type == OP_SELL){
continue;
}
int ticket = OrderTicket();
Print("Attempted allOrderDelete(" + aMagic + ", Comment:" + aComment + ")");
bool result = orderDeleteReliable(ticket);
if(result == false){
Print("allOrderDelete: Ticket #", ticket, ", failed to delete");
}
}
}
