こんにちは、潤奈です( ゚Д゚)!
前回の記事では、標準ライブラリの CTrade クラスを使って、コピペで簡単に注文(エントリー)を出す方法を解説しました。
注文ができるようになったら、次はいよいよ「ポジションを決済(クローズ)する処理」の実装です!
実は、MQL5の決済処理も、MQL4から移行してきた人が非常に混乱しやすいポイントの1つです。MQL4では OrderClose() という関数にチケット番号やロット数を渡すだけでしたが、MQL5ではMT5独自の「ポジション管理システム」を理解していないと、思わぬバグを生んでしまいます。
今回も、標準ライブラリの CTrade をフル活用して、最も安全かつシンプルな「成行決済」と「全決済(一括クローズ)」の書き方を分かりやすく解説します!
1. MQL5の決済はなぜ難しい?(MQL4との違い)
まずは、MQL4とMQL5の決済に関する考え方の違いをサラッと整理しておきましょう。
MQL4では、注文も保有中のポジションもすべて「オーダー(Order)」として一元管理されていました。そのため、決済する際も以下のように OrderClose 関数を呼ぶだけでシンプルに完結していました。
|
1 2 |
// MQL4での決済(シンプル!) OrderClose(ticket, 0.1, Bid, 10, clrRed); |
一方、MQL5では「注文(Order)」「約定(Deal)」「ポジション(Position)」が完全に分離されています。
* 注文 (Order): 注文を出したというリクエスト(まだ約定していない状態も含む)
* 約定 (Deal): 注文が通り、取引が成立した履歴
* ポジション (Position): 約定の結果として、現在保有している未決済の玉
決済処理とは、このうち「ポジション(Position)を閉じる処理」を指します。MQL5でライブラリを使わずに決済しようとすると、エントリー時と同様に MqlTradeRequest 構造体に非常に多くのパラメータをセットしなければならず、初心者にはかなりハードルが高いコードになってしまいます。
そこで、今回も救世主 CTrade の出番です!
2. CTradeを使った「個別決済」の書き方
CTrade クラスには、ポジションを決済するための便利な関数 PositionClose が用意されています。
まずは基本となる、1つのポジションを指定して決済する方法です。最も安全で推奨されるのは、ポジションのチケット番号を指定して決済する方法です。
基本コード
|
1 2 |
// チケット番号を指定して決済する trade.PositionClose(ticket); |
これだけで、指定したチケット番号のポジションを現在の市場価格(成行)で全ロット決済してくれます。スリッページなどの細かな設定は、発注時と同様に OnInit() などで設定した内容が自動的に適用されます。
ポジションのチケット番号はどうやって取得する?
保有しているポジションのチケット番号を取得するには、通常はループ処理と PositionGetTicket() という関数を組み合わせて取得します。これについては次の「全決済」のセクションで詳しく解説します。
3. MT5の2つの取引システム(ネットティング vs ヘッジング)
全決済のコードを見る前に、MT5の重要な仕様である「取引システム」について理解しておく必要があります。MT5には以下の2つのシステムが存在し、ブローカー(FX会社)や口座タイプによってどちらかが適用されています。
- ネットティング(Netting)システム
同じ通貨ペアのポジションを1つしか持てないシステムです。買いポジションを0.1ロット持っている状態で、さらに0.1ロット買い増しすると、ポジションは「0.2ロットのポジションが1つ」に合算されます。 - ヘッジング(Hedging)システム
同じ通貨ペアで複数のポジションを同時に個別に持てるシステムです(両建てが可能です)。MQL4(MT4)と同じ感覚でトレードできるため、日本のFX会社の多くや、一般的なEA開発ではこのヘッジングシステムが前提となっています。
今回の全決済コードは、より一般的で考慮が必要な「ヘッジングシステム(複数ポジションを同時に保有できる環境)」を前提に解説します。
4. コピペで動く!全決済(一括決済)のループ処理
「保有している特定の通貨ペアのポジションをすべて成行決済する」という処理を実装してみましょう。
ここで、プログラミング初心者(そしてMT4開発者)が最もハマりやすい「逆順ループの罠」が登場します。
⚠️ 超重要:なぜループを「逆順」で回す必要があるのか?
通常、プログラミングで配列などを処理する時は、0 から順に 1, 2, 3… とループを回します(正順ループ)。
しかし、ポジションの決済処理で正順ループを使うと、決済漏れが発生します。
例えば、ポジションが3つあるとします。
* インデックス0: 買いポジションA
* インデックス1: 買いポジションB
* インデックス2: 買いポジションC
正順ループで i = 0 のポジションAを決済した瞬間、残ったポジションBとCが自動的に「インデックス0と1」へ前に詰められます。
次にループが i = 1 に進んだとき、現在インデックス1になっているポジションCを決済します。
その結果、インデックス0にズレたポジションBが決済されずに取り残されてしまうのです。
このバグを防ぐために、決済ループは必ず「最後のインデックスから順に(逆順に)デクリメント(減算)しながら処理する」のが鉄則です。
全決済のテンプレートコード
以下は、チャートに設定されている通貨ペアと同じポジションをすべて決済する関数例です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
void CloseAllPositions() { // 保有中の全ポジション数を取得し、最後のインデックスから逆順にループを回す for(int i = PositionsTotal() - 1; i >= 0; i--) { // インデックス i 番目のポジションチケットを取得(同時にポジションを選択状態にする) ulong ticket = PositionGetTicket(i); if(ticket > 0) { // 選択されたポジションの通貨ペア(シンボル)を取得 string symbol = PositionGetString(POSITION_SYMBOL); // チャートの通貨ペアと一致する場合のみ決済を実行 if(symbol == _Symbol) { Print("ポジションを決済します。チケットID: ", ticket); // CTradeを使って決済を実行 if(!trade.PositionClose(ticket)) { Print("決済失敗。エラーコード: ", trade.ResultRetcode()); } } } } } |
5. 【応用】自分のEAのポジションだけを決済する(マジックナンバー判定)
実際のEA開発では、手動で裁量トレードをしているポジションや、他のEAが持っているポジションを巻き込んで勝手に決済してしまっては困りますよね。
ため、「自分のEAが持ったポジション(=同じマジックナンバーを持つポジション)だけを決済する」というフィルタリング処理を追加するのが一般的です。
先ほどのコードに、マジックナンバーの判定処理を追加すると以下のようになります。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// 外部パラメータで設定するマジックナンバー input int MagicNumber = 888888; void CloseMyEAPositions() { for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket > 0) { string symbol = PositionGetString(POSITION_SYMBOL); // ポジションのマジックナンバーを取得 long positionMagic = PositionGetInteger(POSITION_MAGIC); // 「通貨ペア」と「マジックナンバー」の両方が一致したときだけ決済 if(symbol == _Symbol && positionMagic == MagicNumber) { Print("EAのポジションを決済します。チケットID: ", ticket); if(!trade.PositionClose(ticket)) { Print("決済失敗。エラーコード: ", trade.ResultRetcode()); } } } } } |
PositionGetInteger(POSITION_MAGIC) を使うことで、そのポジションがどのマジックナンバーで発注されたかを識別できます。この1行を追加するだけで、EAの安全性が劇的に向上します!
6. まとめ&次のステップ
今回は、MQL5でのポジション決済の基本と、実用的な全決済ループの書き方について解説しました。
- MQL5の決済は、保有中の「ポジション(Position)」を対象に行う。
CTradeのPositionClose(ticket)関数を使えば1行で成行決済ができる。- 複数ポジションを決済するループ処理では、インデックスのズレを防ぐために必ず「逆順ループ」で回す。
- 誤決済を防ぐため、マジックナンバー (
POSITION_MAGIC) のチェックを必ず入れる。
これで、「注文(エントリー)」と「決済(エグジット)」という、EAの心臓部となる2つの処理をマスターしました!
ここまでの知識を組み合わせれば、例えば「移動平均線がゴールデンクロスしたら買い、デッドクロスしたら決済する」といったシンプルな自動売買EAが作れるようになります。
次回は、EAが売買判断を下すために必要な「インジケーター(移動平均線やRSIなど)の数値をプログラム内で取得する方法」について解説します。MQL5ではインジケーターの値の取得方法もMQL4から大きく変更されているため、ここを乗り越えればオリジナルのEA作成まであと一歩です!
今回のコードでうまく決済が動かない場合や、エラーが発生した際などは、YouTubeのコメント欄やXでお気軽にご質問くださいね!


コメント