『EAの設計:ポジションのクローズオーダー』でポジションクローズの方法を紹介しました。
様々な決済ケース
クローズする場合、次のように様々なケースが考えられます。
・利益の一番多いもの
・一番時間経ったもの
・ロットサイズの一番大きい/小さいもの
・利益が閾値超えたもの
・損が一番大きい/小さいもの
ですので、『EAの設計:ポジションのクローズオーダー』での直接注文の前に、条件に合ったものを探し出す処理が必要になってきます。
チケット番号を用いての決済
まず、上記の記事のCloseOrder関数を呼び出すのに、次のような関数が想定しやすいです。
このCommon_CloseTicketでは、パラメータ指定で、どのチケットに対して、どのくらいのロットサイズで決済するのかを指定します。
bool Common_CloseTicket(const int ticket, const double size = 0) export { if (ticket > 0) { if (OrderSelect(ticket, SELECT_BY_TICKET)) { bool closed = false; if (0 == size) closed = CloseOrder(OrderType(), ticket, OrderLots(), OrderOpenPrice()); else closed = CloseOrder(OrderType(), ticket, size, OrderOpenPrice()); if (closed) { return true; } else { Print(__ERROR__, __FUNCTION__, ", Ticket:", ticket); } } else { Print(__ERROR__, __FUNCTION__, ", Select ticket error.", " Line:", __LINE__); } } else { Print(__ERROR__, __FUNCTION__, ", Ticket error:", ticket, " Line:", __LINE__); } return false; }
チケット番号の取得
では、オープン中のポジションのチケット番号はどのように分かるのでしょうか。
次の例では、すべてのオープン中のポジションを決済クローズする場合のものです。
void Common_CloseAllPosition(int type) export { int pos = 0; while (pos < OrdersTotal()) { if (OrderSelect(pos, SELECT_BY_POS) == false) { Print(__ERROR__, __FUNCTION__, ", Select error. pos = ", pos, " ticket = ", OrderTicket(), " ", ErrorDescription(GetLastError())); pos++; continue; // It will be stopped and break here in factly. } if ((OrderMagicNumber() == magicNumber) && (OrderSymbol() == symbol) && (OrderCloseTime() == 0)) { if ((type == OP_BUY) || (type == OP_SELL)) { if (OrderType() == type) { while (IsTradeContextBusy()) Sleep(50); if (CloseOrder(type, OrderTicket(), OrderLots(), OrderOpenPrice())) { pos = 0; } else { Print(__ERROR__, __FUNCTION__, ", Close failed. pos = ", pos, " ticket = ", OrderTicket()); pos++; } } else { pos++; } } else { pos++; } } else { Print(__ERROR__, __FUNCTION__, ", Order check failed. pos = ", pos, " ticket = ", OrderTicket()); pos++; } } }
上のコードでは、OrderSelect(pos, SELECT_BY_POS)により、チケット番号ではなく、一連のポジションから順番に取ってきます。
ほとんどの場合、独自にチケット管理用のデータ構造を持ってなければ、OrderSelect(pos, SELECT_BY_POS) と OrderCloseTime() == 0 の組み合わせて、オープン中のポジションを順に選択できます。
OrderMagicNumber と OrderSymbolなどの条件は必要に応じてご利用ください。複雑な設計でなければ、単一の通貨シンボルの利用であれば、これら要りません。
そして上の例での OrderTicket() は質問の「ポジションのチケット番号をどのように分かるのでしょうか。」の回答になります。ここでチケット番号取得できます。
確認したい情報の確認
ポジションのチケット番号があれば、そのポジションの各情報が調べられます。
オープン価格の取得
double Common_GetActivePositionOpenPriceByTicket(const int ticket) export { double price = 0; if (ticket > 0) { if (OrderSelect(ticket, SELECT_BY_TICKET)) { if ((OrderMagicNumber() == magicNumber) && (0 == OrderCloseTime()) && (OrderSymbol() == symbol)) { price = OrderOpenPrice(); } else { Print(__ERROR__, __FUNCTION__, ", Not active ticket. Ticket:", ticket, " magicNum:", magicNumber, " closeTime:", OrderCloseTime(), " Line:", __LINE__); } } else { Print(__ERROR__, __FUNCTION__, ", Select ticket error.", " Line:", __LINE__); } } else { Print(__ERROR__, __FUNCTION__, ", Ticket error:", ticket, " Line:", __LINE__); } return price; }
オープン時間の取得
datetime Common_GetActivePositionOpenTimeByTicket(const int ticket) export { datetime openTime = 0; if (ticket > 0) { if (OrderSelect(ticket, SELECT_BY_TICKET)) { if ((OrderMagicNumber() == magicNumber) && (0 == OrderCloseTime()) && (OrderSymbol() == symbol)) // TODO no need check ??? { openTime = OrderOpenTime(); } else { Print(__ERROR__, __FUNCTION__, ", Not active ticket. Ticket:", ticket, " magicNum:", magicNumber, " closeTime:", OrderCloseTime(), " Line:", __LINE__); } } else { Print(__ERROR__, __FUNCTION__, ", Select ticket error.", " Line:", __LINE__); } } else { Print(__ERROR__, __FUNCTION__, ", Ticket error:", ticket, " Line:", __LINE__); } return openTime; }
損益額の取得
double Common_GetActivePositionProfitLossByTicket(const int ticket) export { double profitLoss = 0; if (ticket > 0) { if (OrderSelect(ticket, SELECT_BY_TICKET)) { if ((OrderMagicNumber() == magicNumber) && (0 == OrderCloseTime()) && (OrderSymbol() == symbol)) // TODO no need check ??? { profitLoss += OrderProfit(); profitLoss += OrderSwap(); } else { Print(__ERROR__, __FUNCTION__, ", Not active ticket. Ticket:", ticket, " magicNum:", magicNumber, " closeTime:", OrderCloseTime(), " Line:", __LINE__); } } else { Print(__ERROR__, __FUNCTION__, ", Select ticket error.", " Line:", __LINE__); } } else { Print(__ERROR__, __FUNCTION__, ", Ticket error, ticket:", ticket, " Line:", __LINE__); } return profitLoss; }
上の例では全部単独の情報を取得しますが、もちろん、一度に複数の情報をまとめて取得することも可能で、必要に応じてアレンジしてください。
また、他に確認したい情報についてをリファレンスをご参考ください。
決済クローズの実施
最後に調べた情報を元に、文書の最初で想定された様々なケースに従って決済することができます。
つまり、オープン中のポジションに対して、次のプロセスで決済していきます。
①各ポジションのチケット番号取得
↓
②そのポジションの確認したい情報の確認
↓
③その情報を決済基準と照合、決済するか否かの判定
↓
④決済決定の場合、チケット番号を用いての決済
また、もう一つの考えとしては、次の順番での決済プロセスです。
①各ポジションの確認したい情報の確認
↓
②その情報を決済基準と照合、決済するか否かの判定
↓
③各ポジションのチケット番号取得
↓
④決済決定の場合、チケット番号を用いての決済
後者の場合、次の一例のように、決済条件に合ったポジションのチケット番号を割り出すことができます。後は、決済条件を各自アレンジしてください。
int Common_GetActivePositionTicketByOpenPrice(const int type, const double price, const double size = 0) export { int ticket = 0, n = OrdersTotal(); double s = 0; for (int pos = 0; pos < n; pos++) { if (OrderSelect(pos, SELECT_BY_POS) == false) continue; else { if ((MathAbs(price - OrderOpenPrice()) < Point) && (OrderType() == type) && (OrderMagicNumber() == magicNumber) && (OrderSymbol() == symbol) && (OrderCloseTime() == 0)) { if (MathAbs(OrderLots() - size) < Point) { ticket = OrderTicket(); break; } else { // Find max size ticket. if (OrderLots() > s) { ticket = OrderTicket(); } } } } } return ticket; }
EAファイルの作成の方法、関数の命名規格の設計などを別の記事をご参考ください。
|
|
コメント