MQL4のOrderSelectでFX自動売買の注文を正しく選ぶ手順

多数のカードから一枚を選び内容を確かめる作業机

MQL4のOrderSelectは、これから情報を読む注文を一つ選ぶ関数です。選択に成功したあとで銘柄、マジックナンバー、注文種別を確かめると、FX自動売買が調べたい注文だけを読み分けられます。関数を呼ぶだけで、新規注文や決済が行われるわけではありません。

間違えやすいのは、一覧の位置とチケット番号、保有・待機注文と履歴、選択したときの情報と現在の情報の違いです。「選べた」だけで自分のEAの注文だと決めつけると、別の注文を対象にする原因になります。

この記事ではMT4用のMQL4を対象に、引数と戻り値、再選択が必要な理由、銘柄・識別番号・種類による絞り込みを説明します。後半のコード例は注文を読み取り、結果を表示するだけの構成です。MQL5の注文・ポジションAPIとは分けて確認してください。

この記事のポイント
  • 一覧の位置とチケット番号で選ぶ方法の違い
  • poolと決済時刻から注文の状態を読み分ける方法
  • 選択したデータの古さと再選択の必要性
  • 銘柄・マジックナンバー・注文種別を確認する非発注例
目次

MQL4のOrderSelectをFX自動売買で使う基本

並べたカードのうち一枚だけを別のトレーへ移す手元
説明用の生成イメージです。実際のMT4画面ではありません。

OrderSelectは注文を選び戻り値で成否を返す

注文の情報を読む流れは、対象を選ぶ、選択の成功を確かめる、必要な属性を読むの順です。OrderLotsやOrderSymbolなどは、どの注文を読むかを毎回引数で渡す形ではありません。その前にOrderSelectで読み取り対象を決めます。

戻り値はbool型で、成功がtrue、失敗がfalseです。チケット番号が返る関数ではないため、「ticket=OrderSelectの結果」という扱いにすると、成功・失敗の値と注文番号を取り違えます。番号が必要なら、選択成功後にOrderTicketを読みます。

bool OrderSelect(int index, int select, int pool=MODE_TRADES);

書式の末尾にあるpoolは省略可能ですが、学習段階では何を調べる処理かが分かるよう、位置選択のコードに明示すると読みやすくなります。仕様の根拠はMetaQuotesのMQL4のOrderSelectリファレンスです。

選択に失敗した場合は、その注文の属性を読む処理へ進めない構造にします。過去に別の注文を選んだことがあっても、その結果を今回の成功の代わりには使いません。失敗時に戻る、または次の候補へ進む分岐を、読み取りの前へ置くことが基本です。

indexとselectとpoolを組み合わせて選ぶ

第一引数のindexは、名前だけ見ると一覧の添字に思えますが、第二引数によって意味が変わります。SELECT_BY_POSなら一覧内の位置、SELECT_BY_TICKETなら注文のチケット番号です。数字だけを見るのではなく、必ず第二引数と一緒に読みます。

スクロールできます
項目指定するもの読み違えやすい点
index一覧の位置、またはチケット番号意味はselectで変わる
SELECT_BY_POS一覧内の位置で選ぶ指定0から始まる位置を渡す
SELECT_BY_TICKETチケット番号で選ぶ指定位置の0や1を渡す方法ではない
MODE_TRADES保有中の成行注文と待機注文の一覧保有ポジションだけの一覧ではない
MODE_HISTORY決済済み・取消済み注文の履歴一覧口座の全期間を必ず読めるとは限らない

たとえば、一覧の先頭を読む意図で第一引数へ0を渡すならSELECT_BY_POSを組み合わせます。特定の注文番号を追う意図なら、実際に確認できたチケット番号とSELECT_BY_TICKETを使います。「番号」という日本語で二つをまとめると、ここを混同しやすくなります。

保有・待機注文と履歴のどちらを読むかを先に決めると、対応する件数関数も選びやすくなります。現在の一覧を調べるループと、過去の約定を集計するループを、目的が曖昧なまま一つに混ぜない方が確認しやすいです。

列に並べたカードと一枚についた形の異なる留め具
説明用の生成イメージです。実際のMT4画面ではありません。

SELECT_BY_POSは0から始まりOrdersTotalと組み合わせる

位置指定は0から始まります。読み取り開始時点の件数が3なら、その時点の有効な位置は0、1、2です。条件をpos<totalとするのはこのためで、pos=totalまで含めると件数の外を選ぼうとします。0始まりはMetaQuotesの公式MQL4教材でも説明されています。

OrdersTotalの公式説明が返すのは、口座内の成行注文と待機注文の合計です。チャートの通貨ペアだけ、自分のEAだけ、という絞り込みは行いません。EURUSDのチャートで動かした処理でも、別銘柄の注文が一覧に含まれます。

そのため、OrdersTotalが5でも、自分が読みたい注文が5件あるとは限りません。まず位置で一件ずつ選び、その後で銘柄や識別番号、種類を確かめます。口座全体の件数と、条件に一致した件数は別の変数として扱うと、表示結果の意味も分かりやすくなります。

なお、件数を変数へ保存しても、その後の一覧が固定されるわけではありません。別のEAや手動操作などで注文の状態が変わる可能性があります。列挙中の失敗を扱い、一覧が動き得ることを前提にする必要があります。位置は注文そのものの識別番号ではありません。

SELECT_BY_TICKETではpoolで保有中に限定できない

チケット番号で選ぶ場合、第三引数のpoolは無視されます。MODE_TRADESを付けたから履歴の注文を除外できる、という意味にはなりません。特定の番号を選べた後に、その注文がどの状態かを改めて確認します。

状態を見る手掛かりはOrderCloseTimeです。OrderCloseTimeの公式仕様では、未決済の注文と待機注文は0で、決済済み注文の決済時刻を返すと説明されています。履歴側には決済済み成行注文だけでなく、取り消された待機注文もあるため、種類も合わせて読み分けます。

「決済時刻が0なら買いポジション」と判断するのも誤りです。0で分かるのは履歴側の決済・取消済みかどうかの区別で、買い・売り・待機の違いはOrderTypeで確認します。状態と注文種別を分けて判定してください。

チケット番号が手元にある場合でも、取得先の口座を取り違えないことが前提です。別口座や以前の接続先で使った番号をそのまま持ち込まず、調べている口座と番号の対応を確認します。番号選択の成功を、そのEAが管理すべき注文である証明にはしません。

選択後の属性はコピーなので必要な時点で再選択する

OrderSelectは注文データをプログラム環境へコピーします。その後のOrderLots、OrderStopLossなどは、選択時にコピーされた情報を返します。ずっと最新の状態を参照し続ける仕組みとして考えないことが大切です。

たとえば、数量を読んだ後に時間のかかる処理を挟んだとします。その間に手動操作や別の処理で注文が変われば、前に読んだ数量と現在の数量が違う可能性があります。対象注文の識別にはチケット番号を保存し、改めて必要な時点で選択を試みます。

MetaQuotesはOrderSelectの注意事項で、データを要求する前の再選択を推奨しています。再選択したら、銘柄・識別番号・注文種別・決済時刻も必要に応じて確認し直します。前に対象条件を満たしたことだけで、今の処理を進めないようにします。

ただし、再選択してもその直後から注文が絶対に変わらなくなるわけではありません。一連の読み取りで口座の全状態を原子的に固定できる、という保証にはならない点も押さえておきましょう。これは再選択を省いてよいという意味ではなく、読み取り結果の限界を理解するための区別です。

重ねた二枚の半透明な用紙と横に置いた更新用の紙
説明用の生成イメージです。実際のMT4画面ではありません。

履歴件数と列挙順から最新の注文を決めつけない

履歴側を調べる場合はOrdersHistoryTotalとMODE_HISTORYを組み合わせます。OrdersHistoryTotalの公式説明によると、対象は端末へ読み込まれた口座履歴で、件数は「口座履歴」タブの設定に依存します。返ってきた件数を、その口座の全期間の取引数だと決めつけないでください。

また、位置で順番に選んだ結果が、チケット番号順、開始時刻順、決済時刻順になっているとは保証されません。先頭が最古、末尾が最新という前提で一本だけ読むコードは、意図した注文を選べないおそれがあります。

青とグレーの二つの資料トレーに分けた無地カード
説明用の生成イメージです。実際のMT4画面ではありません。

最新の決済を探すなら、対象条件を満たす履歴を列挙し、OrderCloseTimeの値を比較して候補を選ぶ、というように基準を明示します。同じ時刻がある場合の扱いも決めます。受け取った一覧の位置と、選びたい順序は別のものです。

配列へ保存して並べ直す場合も、保存したのはその時点のチケットや時刻です。後で注文属性を読み直すなら再選択が必要になります。添字の扱い自体を整理したい方は、MQL4の配列と添字の確認方法も参考にしてください。

MQL4のOrderSelectでFX自動売買の対象注文を読み分ける

色と形の異なる小さな部品を三つの区画へ分類したトレー
説明用の生成イメージです。実際のMT4画面ではありません。

銘柄とマジックナンバーと注文種別を別々に確認する

位置選択に成功したら、次は目的に合う注文かを判定します。典型的な条件は、OrderSymbolによる銘柄、OrderMagicNumberによる識別番号、OrderTypeによる種類です。この三つは役割が違うため、一つが一致しただけで全部を満たすとは扱いません。

スクロールできます
条件確認する関数一致だけでは分からないこと
対象の通貨ペアかOrderSymbol同じ銘柄にある別のEAの注文かどうか
想定した識別番号かOrderMagicNumber番号が重複する別処理の注文かどうか
買い・売りの成行注文かOrderType対象銘柄や想定EAの注文かどうか
保有・待機側かOrderCloseTime買い・売り・待機の区別

関数の戻り値は、それぞれOrderSymbol、OrderMagicNumberの公式資料で確認できます。銘柄の末尾記号も文字列の一部なので、USDJPYと末尾付きの銘柄を無条件に同じものとして扱わないようにします。

マジックナンバーは便利な識別情報ですが、番号の一致だけで管理元の唯一性が保証されるわけではありません。同じ番号を別の処理にも使えば、絞り込み条件として区別できなくなります。ここでは同時稼働の設定全般へ広げず、読み取り時に比較すべき情報として扱います。

注文種別はOrderTypeの公式一覧にある定数と比較します。買い・売りの保有注文だけを調べたいなら、OP_BUYまたはOP_SELLを許可し、指値・逆指値の待機注文を除きます。待機注文も必要な処理なら、その目的に合わせて条件を変えます。

読み取り専用スクリプトで対象注文を列挙する

次は、現在の成行注文のうち、指定銘柄とマジックナンバーが一致したものだけを読み、Printで表示する例です。注文の新規発注・変更・決済・取消を行う関数は含めていません。まずは対象の選び方を読むためのサンプルとして確認してください。

これは実際のMetaEditorでコンパイル・実行した検証結果ではありません。MT4用のスクリプト例として仕様に沿って記述しています。使用する場合は、デモ環境でコンパイル結果と表示内容を確認し、口座の状態に合うかを自分で照合してください。

#property strict
#property script_show_inputs

input string TargetSymbol = "";
input int TargetMagic = 123456;

void OnStart()
{
   string symbolToRead = TargetSymbol;
   if(symbolToRead == "")
      symbolToRead = Symbol();

   int totalAtStart = OrdersTotal();
   int matched = 0;
   int failed = 0;

   for(int pos = 0; pos < totalAtStart; pos++)
   {
      ResetLastError();
      if(!OrderSelect(pos, SELECT_BY_POS, MODE_TRADES))
      {
         int errorCode = GetLastError();
         Print("Select failed: pos=", pos,
               ", error=", errorCode);
         failed++;
         continue;
      }

      if(OrderCloseTime() != 0) continue;
      if(OrderSymbol() != symbolToRead) continue;
      if(OrderMagicNumber() != TargetMagic) continue;

      int type = OrderType();
      if(type != OP_BUY && type != OP_SELL) continue;

      int ticket = OrderTicket();
      double lots = OrderLots();
      Print("Matched: ticket=", ticket,
            ", symbol=", OrderSymbol(),
            ", magic=", OrderMagicNumber(),
            ", type=", type, ", lots=", lots);
      matched++;
   }

   Print("Read summary: total_at_start=", totalAtStart,
         ", matched=", matched, ", failed=", failed);
}

TargetSymbolを空欄にすると、スクリプトを実行するチャートの銘柄を使います。別の銘柄を読む場合は、気配値などで確認した正確な銘柄名を入力します。TargetMagicの123456は説明用の値なので、想定する注文の実際の識別番号へ合わせます。

出力するのは読み取った属性と集計値です。「Matched」が出ることと、その注文を売買ロジックで操作してよいことは同義ではありません。ここで確認するのは、指定した条件に沿って選択できているかどうかです。

キーボードの前で資料を確認する手元と閉じたノート
説明用の生成イメージです。実際のMT4画面ではありません。

サンプルの一致ゼロと選択失敗を分けて読む

上の例でmatchedが0でも、必ずしも関数の故障ではありません。注文がない、指定銘柄が違う、識別番号が違う、待機注文しかない、といった条件でも一致は0になります。まずtotal_at_startとfailedを合わせて読みましょう。

total_at_startはループを始める前の口座全体の件数、matchedはこのループで条件を満たして読めた回数、failedは位置選択に失敗した回数です。三つの数字は意味が違います。たとえば開始時に5件あって一致が2回でも、残り3件がエラーだったとは限りません。

銘柄や番号が違ってcontinueへ進むのは条件除外で、OrderSelectがfalseを返す選択失敗とは別です。調査するときは、いきなり条件を外すのではなく、必要に応じて除外した理由を短く表示し、どの比較で外れたかを確かめる方が意図を保てます。

また、列挙中に他の処理が注文一覧を変更すると、開始時の件数と終了時の状態が違うことがあります。成功が続いても同じ時点の一覧を完全に取得した証明にはならず、位置の移動による取りこぼしや重複の可能性も考慮します。このサンプルの集計は、口座を固定した厳密な監査結果ではありません。

「後ろからループすれば常に完全」「件数を最初に保存すれば必ず安全」といった理解もしないでください。読み取りの間に何が変わり得るかと、必要な正確さを先に決め、特定注文を追う場合はチケット番号による再確認を使います。

失敗時はGetLastErrorを一度読み結果を変数へ残す

失敗の詳細を調べるときは、OrderSelectがfalseを返した直後にGetLastErrorを読みます。GetLastErrorの公式仕様では、読み取った後に_LastErrorがリセットされると説明されています。同じエラーを二度表示したいなら、取得した値を変数へ保存して使います。

サンプルで選択前にResetLastErrorを呼んでいるのは、以前の失敗情報と区別するためです。ResetLastErrorは_LastErrorを0へ戻します。エラー番号だけを見て成否を推測するのではなく、まず関数の戻り値で失敗を判定する構造にしています。

注文が一覧から外れた、指定した位置が件数の範囲を超えた、想定したチケットを選べない、といった状況は、それぞれ発生時の条件と一緒に調べます。番号を見ずに「通信不良」と一括で決めたり、成功するまで無制限に繰り返したりしないようにしましょう。

選択失敗時には属性を読まずに先へ進む、または処理を終えるのが基本です。再試行を入れるなら、回数や停止条件を決めます。自動売買全体が動かない場合の切り分けは、MT4のEAが動かないときの確認表へ分けて確認できます。

小さな検査用ルーペと一枚だけ横へ分けたカード
説明用の生成イメージです。実際のMT4画面ではありません。

チケットで再選択するときも対象条件を読み直す

ある注文を後から読み直したい場合は、選択成功時のOrderTicketを保存し、その番号でSELECT_BY_TICKETを試みます。保存した位置を使い続ける方法ではありません。位置が同じでも、あとで同じ注文を指すとは限らないからです。

// Fragment inside a function: ticket must already be known.
ResetLastError();
if(!OrderSelect(ticket, SELECT_BY_TICKET))
{
   int errorCode = GetLastError();
   Print("Ticket selection failed: ", errorCode);
   return;
}
// Read the selected order again before using its properties.
if(OrderCloseTime() != 0) return;
if(OrderSymbol() != expectedSymbol) return;
if(OrderMagicNumber() != expectedMagic) return;
int type = OrderType();
if(type != OP_BUY && type != OP_SELL) return;
Print("Current lots: ", OrderLots());

これは関数内に置く断片で、ticket、expectedSymbol、expectedMagicは呼び出し側で用意する変数です。前の完全なスクリプトへそのまま追記する独立プログラムではありません。returnを使えるvoid関数内を想定し、チケットを渡す流れを示しています。

途中で別の補助関数がOrderSelectを呼ぶと、その後の属性取得が別の選択注文を対象にする可能性があります。注文Aを選択し、注文Bを選ぶ関数を呼び、そのままOrderLotsを読む構造は避けます。必要なら注文Aを再選択し、確認するデータを近い範囲でまとめて読みます。

関数の境界をまたぐ場合は、チケット番号や読み取った値を明示的に渡すと、どの注文の情報かを追いやすくなります。コピーした数値を渡す場合は取得時点の値であること、後で最新値が必要なら再選択することを、設計の中で区別してください。

デモ環境では条件を一つずつ変えて対象を照合する

確認したいのは「何か表示されたか」だけではなく、表示してよい注文だけが残るかです。下の表は説明用の判定例で、実際にこの条件の注文を作成して検証した結果ではありません。注文番号や口座情報を公開する必要もありません。

スクロールできます
確認ケースサンプルで期待する扱い見るべき条件
銘柄・識別番号が一致する成行注文読み取り対象にするsymbol、magic、type
同じ銘柄で識別番号だけが違う除外するmagic
同じ識別番号で銘柄だけが違う除外するsymbol
両方一致するが指値・逆指値の待機注文除外するtype
履歴へ移った注文をチケットで選べた現在の成行注文から除外するclose time、type
存在を確認できないチケット失敗を扱い属性を読まない戻り値、error

最初にデモ口座の銘柄名と対象識別番号を確認し、変える条件を一つに絞って比較します。実注文を増やして試すのではなく、すでに確認できるデータと表示内容を照合するところから始めてください。対象がない場合の出力も、正常な確認ケースの一つです。

コードを変更して取引処理へ組み込む場合は、読み取りが合ったことだけで完了にしません。注文条件、数量、価格、取引関数の結果などは別の確認が必要です。本記事のサンプルは、その前段である注文選択の理解に範囲を絞っています。

形と色の異なる小物を一つずつ照合する二つのトレー
説明用の生成イメージです。実際のMT4画面ではありません。

MQL4の説明をMQL5の注文処理へそのまま移さない

検索結果にはMQL4とMQL5を同じページで扱う説明もあります。この記事の三引数の書式、MODE_TRADESとMODE_HISTORY、OrderLotsなどの組み合わせはMQL4の説明です。別の言語のサンプルを部分的に混ぜると、関数名が似ていても意味や型が合わなくなることがあります。

MT5へ移す作業では、保有ポジション、注文、約定履歴をどう扱うかを、対象のAPI仕様から確認し直します。この関数の名前だけを置き換えて移植を終えたことにはできません。詳しい範囲はMQL4からMQL5へのEA移植手順で確認してください。

MQL4を読む段階でも、エディターで対象ファイルの拡張子と利用環境を確認し、関数の公式資料がdocs.mql4.comなのか別の資料なのかを確かめると、調べる途中の混同を減らせます。似たサンプルがコンパイルできたとしても、意図した注文だけを選ぶ条件まで同じとは限りません。

まとめ:MQL4のOrderSelectは選択後の確認までが基本

MQL4のOrderSelectでは、位置で選ぶのかチケット番号で選ぶのかを先に決め、成功後に注文の属性を読みます。位置選択では一覧の種類と件数、チケット選択ではpoolが無視される点と決済時刻を確認しましょう。

FX自動売買の対象注文を読み分けるには、銘柄・マジックナンバー・注文種別を組み合わせます。選択データの古さ、列挙順、一覧の変動も考慮し、必要な時点で再選択してください。まずは読み取り専用の例で対象の一致を確かめることが、後の処理を考える土台になります。

よかったらシェアしてね!
目次