MQL4で動いていたEAをMQL5へ移植するとき、「ポジションを持っているか」

の判定をそのまま`if(OrdersTotal() > 0)`のように書き換えて、

なぜかポジションがあるのに0が返ってくる、あるいは逆に予約注文しか出していないのに数が合わない——という現象に遭遇したことはないでしょうか。

原因は、MQL4とMQL5で`OrdersTotal()`という同じ名前の関数が、

まったく別のものを数えるように変わっているためです。

この記事では、MQL4とMQL5で`OrdersTotal()`が数える対象がどう変わったか、

MQL5でポジション数と予約注文数を正しく分けて数える方法を、

実際に動くコードで解説します。

MQL4のOrdersTotal()は「ポジション+予約注文」の合計

Order系関数の記事で解説した通り、MQL4の`OrdersTotal()`は、

保有中の成行ポジションと、まだ約定していない有効な予約注文(指値・逆指値)の両方を合計した数を返します。

int OrdersTotal();

MQL4では「ポジション」と「予約注文」を区別せず、どちらも`OrderSelect(i, SELECT_BY_POS, MODE_TRADES)`という同じ仕組みで扱うため、

`OrdersTotal()`もその合計になるのが自然でした。

MQL5のOrdersTotal()は「予約注文だけ」

MQL5にも同名の`OrdersTotal()`という関数が存在します。

しかし、MQL5では保有中のポジションと予約注文がそもそも別の管理対象として設計し直されており、

`OrdersTotal()`が数えるのは予約注文だけです。

int OrdersTotal();  //MQL5版: 有効な予約注文(指値・逆指値)の総数のみ。保有中ポジションは含まない

保有中のポジション数を知りたい場合は、まったく別の関数である`PositionsTotal()`を使います。

int PositionsTotal();  //保有中ポジションの総数
MQL4のOrdersTotal() = ポジション数 + 予約注文数(合計1つの関数)
MQL5のOrdersTotal() = 予約注文数のみ
MQL5のPositionsTotal() = ポジション数のみ(別関数)

名前が同じ`OrdersTotal()`のまま中身が変わっているため、

「関数名が同じだから同じ動作のはず」という思い込みが最も事故りやすいポイントです。

PositionSelect・PositionGetDoubleの記事で解説した`PositionsTotal()`+`PositionGetTicket()`が、

MQL5でポジションを数える正しい方法です。

典型的な事故: ポジション有無の判定がすり抜ける

EAで「既にポジションを持っていれば新規エントリーしない」という判定を、

MQL4時代の感覚のまま次のように書いてしまうケースがあります。

//誤り: MQL5でこれを書くと予約注文の数しか見ていない
if(OrdersTotal() > 0)
   return;//実際にはポジションを持っていても素通りしてしまう

この条件は、予約注文を1件も出していなければ常に`false`になります。

つまり、成行でポジションを保有していても`OrdersTotal()`は0のままなので、

この判定はすり抜けて新規エントリーが実行されてしまいます。

正しくは、ポジションの有無を確認したいなら`PositionsTotal()`(またはPositionSelect)を使う必要があります。

//正しい: ポジションの有無を確認したい場合
if(PositionsTotal() > 0)
   return;

予約注文を1件ずつ扱う関数群

`OrdersTotal()`で数えた予約注文を1件ずつ参照するには、

`PositionGetTicket()`とよく似た形の関数を使います。

ulong  OrderGetTicket(int index);              //index番目の予約注文のチケットを取得し、選択状態にする
bool   OrderSelect(ulong ticket);               //チケット番号を指定して予約注文を選択状態にする
double OrderGetDouble(ENUM_ORDER_PROPERTY_DOUBLE property);   //価格・SL・TP等
long   OrderGetInteger(ENUM_ORDER_PROPERTY_INTEGER property); //種別・マジックナンバー等
string OrderGetString(ENUM_ORDER_PROPERTY_STRING property);   //通貨ペア・コメント等

よく使うプロパティは以下の通りです。

  • ORDER_PRICE_OPEN(double) — 予約注文の指定価格
  • ORDER_SL/ORDER_TP(double) — 損切り・利確価格
  • ORDER_TYPE(long、実体はENUM_ORDER_TYPE) — ORDER_TYPE_BUY_LIMIT/ORDER_TYPE_SELL_LIMIT/ORDER_TYPE_BUY_STOP/ORDER_TYPE_SELL_STOP
  • ORDER_MAGIC(long) — マジックナンバー
  • ORDER_TICKET(long) — チケット番号

実際に動くコード全体

ポジション数(PositionsTotal)と予約注文数(OrdersTotal)を分けて数え、

予約注文の種別・価格を1件ずつログへ出力する、実際にMetaEditorでコンパイルできるスクリプトです。

//+------------------------------------------------------------------+
//|                                       PositionsVsOrdersTotal.mq5  |
//|                     Copyright 2026, FX-EA System Project Creator |
//|                        https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link      "https://creator.fx-ea-system-project.com/"
#property version   "1.00"
#property script_show_inputs

input long MagicFilter = 0;//マジックナンバーで絞り込む(0なら全件対象)

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int positionCount = PositionsTotal();
   int pendingCount  = OrdersTotal();

   Print("保有中ポジション数(PositionsTotal)=", positionCount,
         " / 有効な予約注文数(OrdersTotal)=", pendingCount);

   for(int i = pendingCount - 1; i >= 0; i--)
     {
      ulong ticket = OrderGetTicket(i);//このインデックスの予約注文を選択状態にする
      if(ticket == 0)
         continue;

      if(MagicFilter != 0 && OrderGetInteger(ORDER_MAGIC) != MagicFilter)
         continue;//マジックナンバーが一致しなければスキップ

      string symbol    = OrderGetString(ORDER_SYMBOL);
      double priceOpen = OrderGetDouble(ORDER_PRICE_OPEN);
      double sl        = OrderGetDouble(ORDER_SL);
      double tp        = OrderGetDouble(ORDER_TP);
      long   type      = OrderGetInteger(ORDER_TYPE);

      PrintFormat("#%d %s type=%d 指定価格=%.5f SL=%.5f TP=%.5f",
                  (int)ticket, symbol, (int)type, priceOpen, sl, tp);
     }
  }
//+------------------------------------------------------------------+
Copy

MetaEditorで実際に動かす手順

  1. MetaTrader 5の「ツール」→「MetaQuotes Language Editor」でMetaEditorを開く
  2. 「ファイル」→「新規作成」→「スクリプト」を選び、名前を「PositionsVsOrdersTotal」にして作成する(中身は空のテンプレートで構いません)
  3. テンプレートの中身を全て削除し、上のコードを丸ごと貼り付ける
  4. F7キー(またはコンパイルボタン)でコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
  5. ポジションと予約注文を1件ずつ手動で出した状態のチャートへドラッグ&ドロップし、「エキスパート」タブに2つの数が別々に表示されることを確認する

コピペしてコンパイルが通らない・数が合わないときに確認すること

  • 拡張子が「.mq5」になっているか(このコードはMQL5専用で、MQL4環境ではコンパイルできません)
  • ポジションの有無を判定したいのに`OrdersTotal()`を使っていないか(予約注文がなければ常に0を返すため、判定がすり抜ける)
  • 予約注文の総数が想定より少ない場合、既に約定してポジションに変わった注文まで数えようとしていないか(約定後は`OrdersTotal()`の対象から外れ、`PositionsTotal()`側に移る)
  • `OrderGetTicket()`の戻り値が0のままスキップしていないか(選択に失敗している)

まとめ

MQL4の`OrdersTotal()`はポジションと予約注文の合計でしたが、

MQL5では予約注文だけを数える関数に変わり、ポジション数は`PositionsTotal()`という別の関数で取得します。

関数名が同じだからと移植時に読み替えず流用すると、「ポジションを持っているのに0が返る」

判定漏れに直結します。

EAの新規エントリー判定には必ず`PositionsTotal()`(またはPositionSelect)を使い、

`OrdersTotal()`は予約注文だけを扱うときに使う、

と役割を分けて覚えてください。

関連記事