複数のポジションを持つ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"); } } }