【MQL4関数】OrderSymbol関数の使い方!正しくポジションを決済する方法

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

別の通貨ペアのポジションを、自動売買が勝手に決済しちゃった!どうしたら防げるの?

OrderSymbol関数とは

自動売買が勝手に別のポジションを決済することはありませんか?

そういうときは、自動売買のプログラム内で、通貨ペアの設定ができていない可能性があります。

 

通貨ペアの設定ができていない場合、別の通貨ペアのポジションを決済してしまうことがあります。

例えば、自動売買を「USDJPY」で動かしているのに、「EURUSD」のポジションを決済してしまったり、「AUDJPY」のポジションを決済してしまったりします。

そこで、別のポジションを決済してしまうことを防ぐために、OrderSymbol関数を使いましょう。

 

OrderSymbol関数とは、保有ポジションの通貨ペアの情報を取得する関数です。

保有ポジションの通貨ペアを取得することで、正しい通貨ペアのポジションだけを決済させることができます。

例えば、自動売買が「USDJPY」で動いているなら、「USDJPY」のポジションだけを決済させることができます。

このように OrderSymbol関数を使って正しい通貨ペアを設定することで、別の通貨ペアのポジションを勝手に決済してしまうことを防ぐことができます。

 

OrderSymbol関数の書き方

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

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


 

基本的な書き方

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

string orderSymbol = OrderSymbol();

 

返り値は string型で、引数はありません。

 

返り値(戻り値)

OrderSymbol関数の返り値は、string型です。

保有ポジションの通貨ペア名が返ってきます。

 

例えば、保有ポジションがドル円の場合、「USDJPY」という値が返ってきます。

 

このように OrderSymbol関数は、string型が返り値となっていて、保有ポジションの通貨ペア名が返ってきます。

 

事前にポジションを選択しておく

OrderSymbol関数は、ポジションを選択しないと使うことができません。

そのため OrderSymbol関数を実行する前に、ポジションを選択しておきましょう。

ポジションを選択するには、OrderSelect関数を使います。

 

必ず OrderSelect関数 → OrderSymbol関数 の順にプログラムするので、以下のようなプログラムになります。

//保有ポジションを一つ選択
if(OrderSelect(0,SELECT_BY_POS,MODE_TRADES))
   {

   //選択したポジションが、実行されている通貨ペアと同じかどうかチェック
   if(OrderSymbol() == Symbol())
   {

      //ここにポジションを決済するプログラムを書く

   }
}

 

このように、OrderSymbol関数を実行する前に、ポジションを選択しておくようにしましょう。

ちなみに if文の条件式に「Symbol( )」と書いていますが、Symbol関数は自動売買が動いている通貨ペアの情報が返ってきます。

OrderSymbol関数でポジションの通貨ペアを取得し、Symbol関数で自動売買が動いている通貨ペアを取得します。

通貨ペアを一致させることで、別のポジションを決済してしまうことを防いでいます。

 

OrderSelect関数は、こちらの記事が参考になります。

 

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

先ほど、OrderSelect関数と組み合わせましたが、さらに他の関数とも組み合わせます。

上記の例では、ポジションを1つだけ選択して、通貨ペアを取得していましたが、全てのポジションの情報を取得してみます。

全てのポジションの情報を取得するためには、for文を使って全てのポジションをチェックします。

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

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

//保有ポジションを一つずつチェックしていく
  for( int i = OrdersTotal() - 1; i >= 0; i--)
     {

      //保有ポジションを一つ選択
      if( OrderSelect( i, SELECT_BY_POS, MODE_TRADES))
          {

              //選択したポジションが、実行されている通貨ペアと同じかどうかチェック
              if( OrderSymbol() == Symbol())
              {

              //ここにポジションを決済するプログラムを書く

              }
          }
     }

 

 

このように書くことで、全てのポジションをチェックし、その中から自動売買が動いている通貨ペアだけを選択することができます。

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

 

OrdersTotal関数の使い方は、以下の記事が参考になります。

 

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

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

実際のEA(自動売買)で使える形になっていますので、ぜひ参考にしてください。

 

例1:自分の通貨ペアの買いポジションだけを全決済するEA

OrderSymbol関数とOrderType関数を組み合わせることで、特定の通貨ペアの買いポジションだけを決済することができます。

以下の例では、ボタンを押す代わりにOnTick内で条件を満たしたときに、買いポジションだけを全決済します。

//+------------------------------------------------------------------+
//| 自分の通貨ペアの買いポジションだけを全決済する関数               |
//+------------------------------------------------------------------+
void CloseAllBuyPositions()
{
   // 保有ポジションを後ろからループ(決済するとインデックスがずれるため)
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      // ポジションを選択
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 通貨ペアが一致しているかチェック
         if(OrderSymbol() == Symbol())
         {
            // 買いポジション(OP_BUY)かどうかチェック
            if(OrderType() == OP_BUY)
            {
               // 買いポジションを決済(Bid価格で決済する)
               bool result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(), MODE_BID), 10, clrRed);

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

//+------------------------------------------------------------------+
//| OnTick関数での使用例                                              |
//+------------------------------------------------------------------+
void OnTick()
{
   // 例:RSIが70を超えたら買いポジションを全決済する
   double rsi = iRSI(Symbol(), 0, 14, PRICE_CLOSE, 0);

   if(rsi > 70)
   {
      CloseAllBuyPositions();
   }
}

このように、OrderSymbol関数で通貨ペアをチェックし、さらにOrderType関数で売買の種類をチェックすることで、買いポジションだけを狙って決済することができます。

 

例2:自分の通貨ペアのポジション数をカウントする

自動売買では、「今いくつポジションを持っているか」を確認したい場面がよくあります。

OrderSymbol関数を使えば、自分のEAが動いている通貨ペアのポジション数だけを正確にカウントできます。

//+------------------------------------------------------------------+
//| 自分の通貨ペアのポジション数をカウントする関数                   |
//| buyCount: 買いポジション数(参照渡しで返す)                     |
//| sellCount: 売りポジション数(参照渡しで返す)                    |
//+------------------------------------------------------------------+
void CountMyPositions(int &buyCount, int &sellCount)
{
   // カウンターを初期化
   buyCount  = 0;
   sellCount = 0;

   // 全ポジションをループしてチェック
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      // ポジションを選択
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 自分の通貨ペアかどうかチェック
         if(OrderSymbol() == Symbol())
         {
            // 買いポジションならbuyCountを加算
            if(OrderType() == OP_BUY)
               buyCount++;

            // 売りポジションならsellCountを加算
            if(OrderType() == OP_SELL)
               sellCount++;
         }
      }
   }
}

//+------------------------------------------------------------------+
//| OnTick関数での使用例                                              |
//+------------------------------------------------------------------+
void OnTick()
{
   int buyCount, sellCount;

   // 自分の通貨ペアのポジション数を取得
   CountMyPositions(buyCount, sellCount);

   // ポジション数をログに出力
   Print("買いポジション数=", buyCount, " 売りポジション数=", sellCount);

   // 例:買いポジションが0のときだけ新規エントリーする
   if(buyCount == 0)
   {
      // ここに新規注文のプログラムを書く
   }
}

このように参照渡しを使うことで、買いと売りのポジション数を一度に取得できます。

ポジション数を管理することで、「最大○個までしかポジションを持たない」といったルールも簡単に実装できます。

 

例3:マジックナンバーとOrderSymbolを組み合わせて安全に決済するEA

実際のEA開発では、OrderSymbol関数だけでなくマジックナンバー(OrderMagicNumber関数)も組み合わせることで、より安全にポジションを管理できます。

同じ通貨ペアで複数のEAを動かす場合、マジックナンバーで自分のEAが建てたポジションだけを識別する必要があります。

//+------------------------------------------------------------------+
//| マジックナンバーの設定                                           |
//+------------------------------------------------------------------+
#define MAGIC_NUMBER 123456  // このEA専用のマジックナンバー

//+------------------------------------------------------------------+
//| 通貨ペア+マジックナンバーで自分のポジションだけを全決済する関数 |
//+------------------------------------------------------------------+
void CloseMyAllPositions()
{
   // 保有ポジションを後ろからループ
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      // ポジションを選択
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 通貨ペアが一致しているかチェック
         if(OrderSymbol() != Symbol()) continue;

         // マジックナンバーが一致しているかチェック(自分のEAが建てたポジションか)
         if(OrderMagicNumber() != MAGIC_NUMBER) continue;

         // 決済価格を決定(買いならBid、売りならAsk)
         double closePrice = 0;
         if(OrderType() == OP_BUY)
            closePrice = MarketInfo(OrderSymbol(), MODE_BID);
         else if(OrderType() == OP_SELL)
            closePrice = MarketInfo(OrderSymbol(), MODE_ASK);
         else
            continue;  // 指値・逆指値注文はスキップ

         // ポジションを決済
         bool result = OrderClose(OrderTicket(), OrderLots(), closePrice, 10, clrYellow);

         // 決済結果をログに出力
         if(result)
            Print("決済成功: チケット=", OrderTicket(), " 通貨ペア=", OrderSymbol());
         else
            Print("決済失敗: チケット=", OrderTicket(), " エラー=", GetLastError());
      }
   }
}

//+------------------------------------------------------------------+
//| OnTick関数での使用例                                              |
//+------------------------------------------------------------------+
void OnTick()
{
   // 例:金曜日の22時を過ぎたら週末リスク回避のため全決済する
   if(DayOfWeek() == 5 && Hour() >= 22)
   {
      CloseMyAllPositions();
      return;  // 決済後は新規エントリーしない
   }

   // ここに通常のエントリーロジックを書く
}

このように、OrderSymbol関数とOrderMagicNumber関数をダブルチェックすることで、他のEAが建てたポジションを誤って決済してしまうことを完全に防ぐことができます。

 

例4:自分の通貨ペアの合計損益をリアルタイムで表示するインジケーター

OrderSymbol関数は、EAだけでなくインジケーターでも活用できます。

以下の例では、自分の通貨ペアの保有ポジションの合計損益をチャート上にリアルタイム表示します。

//+------------------------------------------------------------------+
//| 自分の通貨ペアの合計損益をチャートに表示するインジケーター       |
//+------------------------------------------------------------------+
#property indicator_chart_window  // チャートウィンドウに表示

//+------------------------------------------------------------------+
//| 初期化関数                                                        |
//+------------------------------------------------------------------+
int OnInit()
{
   // タイマーを1秒間隔で設定(リアルタイム更新用)
   EventSetTimer(1);
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 終了処理関数                                                      |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // タイマーを停止
   EventKillTimer();

   // 表示したオブジェクトを削除
   ObjectDelete(0, "ProfitLabel");
   ObjectDelete(0, "ProfitValue");
}

//+------------------------------------------------------------------+
//| 自分の通貨ペアの合計損益を計算する関数                           |
//+------------------------------------------------------------------+
double CalcMyProfit()
{
   double totalProfit = 0;

   // 全ポジションをループ
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 自分の通貨ペアのポジションだけを合計する
         if(OrderSymbol() == Symbol())
         {
            // OrderProfit()で損益、OrderSwap()でスワップ、OrderCommission()で手数料を取得
            totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
         }
      }
   }

   return(totalProfit);
}

//+------------------------------------------------------------------+
//| タイマーイベント(1秒ごとに実行)                                |
//+------------------------------------------------------------------+
void OnTimer()
{
   // 自分の通貨ペアの合計損益を計算
   double profit = CalcMyProfit();

   // 損益の文字列を作成
   string profitText = Symbol() + " 合計損益: " + DoubleToString(profit, 2) + " " + AccountCurrency();

   // 損益に応じて色を変える(プラスなら青、マイナスなら赤)
   color textColor = (profit >= 0) ? clrDodgerBlue : clrRed;

   // チャート左上にテキストを表示
   if(ObjectFind(0, "ProfitValue") < 0)
   {
      // オブジェクトが存在しない場合は新規作成
      ObjectCreate(0, "ProfitValue", OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, "ProfitValue", OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, "ProfitValue", OBJPROP_XDISTANCE, 20);
      ObjectSetInteger(0, "ProfitValue", OBJPROP_YDISTANCE, 30);
      ObjectSetInteger(0, "ProfitValue", OBJPROP_FONTSIZE, 14);
   }

   // テキストと色を更新
   ObjectSetString(0, "ProfitValue", OBJPROP_TEXT, profitText);
   ObjectSetInteger(0, "ProfitValue", OBJPROP_COLOR, textColor);

   // チャートを再描画
   ChartRedraw();
}

//+------------------------------------------------------------------+
//| OnCalculate関数(インジケーターに必須)                           |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   return(rates_total);
}

このインジケーターでは、OrderSymbol関数を使って自分の通貨ペアのポジションだけの損益を合計しています。

スワップや手数料も含めた正確な損益を表示できるので、複数の通貨ペアでポジションを持っている場合でも、通貨ペアごとの損益を把握することができます。

 

まとめ

今回は、OrderSymbol関数の使い方について解説しました。

 

OrderSymbol関数のポイントをまとめると、以下の通りです。

  • OrderSymbol関数は、保有ポジションの通貨ペア名を取得する関数
  • 返り値はstring型で、引数はない
  • 使用する前に必ずOrderSelect関数でポジションを選択しておく
  • Symbol関数と組み合わせることで、自動売買が動いている通貨ペアのポジションだけを操作できる
  • OrderMagicNumber関数と組み合わせることで、さらに安全にポジションを管理できる

 

OrderSymbol関数を正しく使うことで、別の通貨ペアのポジションを誤って決済してしまうトラブルを防ぐことができます。

自動売買を作るときは、必ずOrderSymbol関数で通貨ペアのチェックを入れるようにしましょう。