【MQL4関数】OrderSelect関数の使い方!保有ポジションの選択のやり方

【中級編】MQLプログラムの読み方・書き方
朝日奈りさ
朝日奈りさ

自動売買で保有ポジションを選択するにはどうしたらいいの?

OrderSelect関数とは

自動売買システムに保有ポジションを決済させたいですよね!

決済するためには、保有ポジションを選択する必要があります。

そこで OrderSelect関数を使いましょう。

 

OrderSelect関数は、保有ポジションを1つ選択する関数です。

選択することで、そのポジションの情報を取得することができます。

例えば、以下の情報を取得できます。

・注文種別
・ロット数
・チケット番号
・注文日時   etc…

 

ちなみに OrderSelect関数は、あくまで保有ポジションを選択するだけの関数です。

OrderSelect関数を使って、情報を取得することはできないので、ご注意ください。

 

またOrderSelect関数は、保有ポジションの情報を取得するだけでなく、決済するときにも必ず使用する関数です。

自動売買ではトレードの基本となる関数なので、基本的な書き方をマスターしましょう。

 

OrderSelect関数の書き方

OrderSelect関数の書き方は、関数の書き方と同じです。

もし関数の使い方をマスターしていない方は、こちらの記事が参考になります。

 

基本的な書き方

OrderSelect関数の基本的な書き方は以下の通りです。

分かりやすいように、引数は省略しています。

bool  OrderSelect( ①, ②, ③);

 

返り値は bool型で、引数は3つあります。

まずは返り値から見ていきましょう。

 

返り値(戻り値)

OrderSelect関数の返り値は、bool型です。

「true」または「false」が返ってきます。

数値にすると「1」または「0」が返ってきます。

 

正常にポジションを選択できた場合は、「true」が返ってきます。

正常にポジションを選択できなかった場合は、「false」が返ってきます。

 

このように OrderSelect関数は、bool型が返り値となっています。

 

引数

OrderSelect関数の引数は3つです。

まずは一覧で見てみましょう。

番号データ型引数名内容
intindex以下のどちらかを設定
・インデックス
・チケット番号
intselect以下から選択方法を設定(上記のindexに合わせる)
・インデックス
・チケット番号
intpool以下のどちらかを設定
・現在保有しているポジション
・過去保有していたポジション

 

1つ1つ見ていきながら、一緒に OrderSelect関数を作っていきましょう。

 

①index

indexは、ポジションを選択するために、ポジションの番号を設定します。

番号には以下の2種類があります。

・インデックス
・チケット番号

 

インデックスとは、注文するときに自動的に割り振られた識別番号です。

保有しているポジションが1つの場合、「0」が割り振られます。

その後、ポジションが増えるごとに 1、2、3・・・と順番に割り振られる番号になります。

 

チケット番号とは、現在・過去に関わらず、ポジションに自動的に割り振られた固有番号です。

チケット番号は、ポジションによって全て異なっているため、同じ番号のポジションはありません。

そのため桁数が多く、FX会社によって異なりますが、8桁くらいの番号になります。

 

たいていの自動売買システムは、インデックスを使用しています。

インデックスの方が分かりやすいので、インデックスを使用すると良いでしょう。

 

bool select = OrderSelect( 0, ②, ③);

 

②select

selectは OrderSelect関数がポジションを選択するときの、選択方法を設定します。

こちらも以下の2つから選びます。

・インデックス(SELECT_BY_POS)
・チケット番号(SELECT_BY_TICKET)

 

もし ①index の引数で、インデックス番号を設定している場合、「SELECT_BY_POS」を選択します。

チケット番号を設定している場合、「SELECT_BY_TICKET」を選択します。

 

このように ①index の設定内容によって決まるので、してほしい選択方法を設定しましょう。

ここでは、インデックス番号を設定しますので、以下のように書きます。

bool select = OrderSelect( 0, SELECT_BY_POS, ③);

 

③pool

poolは、どんな状態のポジションから選択したいのかを設定します。

設定値は以下の2つです。

・現在のポジションから選択(MODE_TRADES)
・過去のポジションから選択(MODE_HISTORY)

 

例えば、現在保有しているポジションまたは、予約しているポジションから選択したい場合は、「MODE_TRADES」を設定します。

過去に決済したポジションまたは、キャンセルしたポジションから選択したい場合は、「MODE_HISTORY」を設定します。

 

ここでは、保有ポジションから選択したいので、以下のように書きます。

bool select = OrderSelect( 0, SELECT_BY_POS, MODE_TRADES);

 

OrderSelect関数の具体的な使い方(サンプルあり)

OrderSelect関数の基本的な書き方を解説しましたが、ここからは具体的な使い方について解説していきます。

OrderSelect関数はポジションを1つだけ選択する関数なので、for文を使って全てのポジションを選択する方法がよく使われます。

そのとき、for分の条件式に保有ポジション数が必要となりますので、OrdersTotal関数と組み合わせて使う場合が多いです。

例えば以下のようなプログラムです。

//保有ポジションを一つずつチェックしていく
for( int i = OrdersTotal() - 1; i >= 0; i--)
{
   //保有ポジションを一つ選択
   if( OrderSelect( i, SELECT_BY_POS, MODE_TRADES))
   {
      //ここにポジションを操作するプログラムを書く
   }
}

サンプルプログラムはこちら

 

上記のように、for文で1つずつポジションを選択し、ポジションを決済させたり、情報を取得したりします。

この書き方は、自動売買を作るときによく使う書き方なので、どこかにコピーしておくと良いでしょう。

 

OrdersTotal関数の詳しい使い方は、こちらの記事が参考になります。

 

OrderSelect関数の実用的なプログラム例

ここからは、OrderSelect関数を使った実用的なプログラム例をいくつかご紹介します。

実際のEA開発でよく使うパターンなので、ぜひ参考にしてみてください。

 

例1:自分のEAのポジションだけを選択する

複数のEAを同時に稼働させている場合、自分のEAが出した注文だけを対象にしたいですよね。

そんなときは、マジックナンバーと通貨ペアで絞り込む方法が定番です。

// マジックナンバーの定義(EAごとに固有の番号を設定する)
#define MAGIC_NUMBER 12345

//+------------------------------------------------------------------+
//| 自分のEAが保有しているポジション数をカウントする関数             |
//+------------------------------------------------------------------+
int CountMyPositions()
{
   int count = 0; // カウント用の変数を初期化

   // 保有ポジションを後ろから順にチェックしていく
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      // ポジションを1つ選択する
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // マジックナンバーが自分のEAのものかチェック
         if(OrderMagicNumber() != MAGIC_NUMBER) continue;

         // 通貨ペアが現在のチャートと一致しているかチェック
         if(OrderSymbol() != Symbol()) continue;

         // 両方一致した場合のみカウントを増やす
         count++;
      }
   }

   return count; // 自分のEAのポジション数を返す
}

//+------------------------------------------------------------------+
//| OnTick:ティックごとに呼ばれる関数                               |
//+------------------------------------------------------------------+
void OnTick()
{
   // 自分のEAのポジション数を取得
   int myPositions = CountMyPositions();

   // ログに出力して確認する
   Print("自分のEAの保有ポジション数: ", myPositions);

   // ポジションがなければ新規注文を検討する、など
   if(myPositions == 0)
   {
      // ここにエントリー条件を書く
   }
}

 

このようにマジックナンバー通貨ペアの2つでフィルタリングすることで、他のEAや手動トレードのポジションを誤って操作するのを防ぐことができます。

EA開発では必須テクニックなので、覚えておきましょう。

 

例2:保有ポジションをすべて決済する

特定の条件になったときに、自分のEAの保有ポジションをすべて一括決済したい場面はよくあります。

以下は、OrderSelect関数とOrderClose関数を組み合わせた全決済のプログラムです。

// マジックナンバーの定義
#define MAGIC_NUMBER 12345

//+------------------------------------------------------------------+
//| 自分のEAの保有ポジションをすべて決済する関数                     |
//+------------------------------------------------------------------+
void CloseAllMyPositions()
{
   // 後ろから順にループする(決済するとインデックスがずれるため)
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      // ポジションを1つ選択する
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;

      // 自分のEAのマジックナンバーでなければスキップ
      if(OrderMagicNumber() != MAGIC_NUMBER) continue;

      // 現在のチャートの通貨ペアでなければスキップ
      if(OrderSymbol() != Symbol()) continue;

      // 注文種別を取得する
      int type = OrderType();

      // 買いポジション(OP_BUY)の場合
      if(type == OP_BUY)
      {
         // Bid価格で決済する
         bool result = OrderClose(
            OrderTicket(),   // チケット番号
            OrderLots(),     // ロット数
            MarketInfo(Symbol(), MODE_BID), // 現在のBid価格
            3,               // スリッページ(3ポイント)
            clrRed           // チャート上の矢印の色
         );

         // 決済結果をログに出力
         if(result)
            Print("買いポジション決済成功: チケット=", OrderTicket());
         else
            Print("買いポジション決済失敗: エラー=", GetLastError());
      }
      // 売りポジション(OP_SELL)の場合
      else if(type == OP_SELL)
      {
         // Ask価格で決済する
         bool result = OrderClose(
            OrderTicket(),   // チケット番号
            OrderLots(),     // ロット数
            MarketInfo(Symbol(), MODE_ASK), // 現在のAsk価格
            3,               // スリッページ(3ポイント)
            clrBlue          // チャート上の矢印の色
         );

         // 決済結果をログに出力
         if(result)
            Print("売りポジション決済成功: チケット=", OrderTicket());
         else
            Print("売りポジション決済失敗: エラー=", GetLastError());
      }
   }
}

//+------------------------------------------------------------------+
//| OnTick:ティックごとに呼ばれる関数                               |
//+------------------------------------------------------------------+
void OnTick()
{
   // 例:金曜日の22時以降になったら全決済する(週末持ち越し防止)
   if(DayOfWeek() == 5 && Hour() >= 22)
   {
      CloseAllMyPositions();
   }
}

 

ポイントは、for文を後ろから回している点です。

決済するとインデックス番号がずれるため、前から回すとポジションを飛ばしてしまう場合があります。

必ず後ろから(OrdersTotal() – 1 から 0 に向かって)ループさせましょう。

 

例3:保有ポジションの合計損益を計算する

自分のEAの保有ポジション全体の損益を把握して、一定の利益・損失に達したら全決済する──そんなロジックを組むときに使えるプログラムです。

// マジックナンバーの定義
#define MAGIC_NUMBER 12345

//+------------------------------------------------------------------+
//| 自分のEAの保有ポジション合計損益を取得する関数                   |
//| 戻り値:合計損益(通貨単位。例:ドル口座なら米ドル)             |
//+------------------------------------------------------------------+
double GetTotalProfit()
{
   double totalProfit = 0.0; // 合計損益を格納する変数

   // 保有ポジションを後ろから順にチェック
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      // ポジションを選択する
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;

      // マジックナンバーが異なればスキップ
      if(OrderMagicNumber() != MAGIC_NUMBER) continue;

      // 通貨ペアが異なればスキップ
      if(OrderSymbol() != Symbol()) continue;

      // 買い or 売りポジションのみ対象(待機注文は除外する)
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;

      // OrderProfit()で含み損益、OrderSwap()でスワップ、
      // OrderCommission()で手数料を取得し、すべて合算する
      totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
   }

   return totalProfit; // 合計損益を返す
}

//+------------------------------------------------------------------+
//| OnTick:ティックごとに呼ばれる関数                               |
//+------------------------------------------------------------------+
void OnTick()
{
   // 合計損益を取得
   double profit = GetTotalProfit();

   // チャート左上にコメントとして表示
   Comment("合計損益: ", DoubleToString(profit, 2), " ", AccountCurrency());

   // 例:合計利益が5000円以上になったら全決済
   if(profit >= 5000.0)
   {
      Print("目標利益に到達!全決済を実行します。合計損益=", profit);
      // ここで全決済関数(例2のCloseAllMyPositions)を呼び出す
      // CloseAllMyPositions();
   }

   // 例:合計損失が-3000円以下になったら損切り全決済
   if(profit <= -3000.0)
   {
      Print("損切りラインに到達!全決済を実行します。合計損益=", profit);
      // ここで全決済関数(例2のCloseAllMyPositions)を呼び出す
      // CloseAllMyPositions();
   }
}

 

OrderProfit()で含み損益、OrderSwap()でスワップポイント、OrderCommission()で取引手数料を取得できます。

これら3つを合算することで、実質的な損益を正確に把握することができます。

 

まとめ

OrderSelect関数は、保有ポジションを1つ選択する関数です。

選択したポジションの情報取得や決済を行うために、必ず使用する重要な関数です。

 

今回のポイントをまとめると以下の通りです。

・OrderSelect関数は保有ポジションを1つ選択する関数
・返り値はbool型(true / false)
・引数は「インデックスまたはチケット番号」「選択方法」「ポジションの状態」の3つ
・for文とOrdersTotal関数を組み合わせて使うのが基本
・マジックナンバーと通貨ペアでフィルタリングするのが実践的
・ループは必ず後ろから回す(決済時のインデックスずれ防止)

 

OrderSelect関数は自動売買の基本中の基本となる関数です。

ぜひ今回ご紹介したサンプルコードを参考に、実際にプログラムを書いて動かしてみてください。