【MQL4関数】OrderClosePrice関数の使い方!決済価格の取得方法

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

ポジションを決済するには、希望する決済価格を設定する必要があるよ!

OrderClosePrice関数とは

ポジションを決済するときには、OrderClose関数を使います。

OrderClose関数を実行するためには、引数に「希望する決済価格」を設定する必要があります。

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

 

OrderClosePrice関数とは、選択したポジションの決済価格を返す関数です。

決済価格を返すといっても難しいことはなく、現在の買値や売値の価格を返してくれます。

このように、ポジションを決済する関数(OrderClose関数)を実行するときに使う関数なので、覚えておくと良いでしょう。

 

OrderClosePrice関数の書き方

OrderClosePrice関数の使い方は、基本的な関数と同じです。

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

 

基本的な書き方

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

double orderClosePrice = OrderClosePrice();

 

返り値は double型で、引数は必要ありません。

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

 

返り値(戻り値)

OrderClosePrice関数の返り値は double型です。

具体的には、自動売買を動かしている通貨ペアの価格が返ってきます。

例えばドル円の場合、現在の買値が「105.000円」の時、OrderClosePrice関数は「105.000」を返します。

ちなみに、売りポジションの場合は買値が返ってきて、買いポジションの場合は売値が返ってきます。

そのため、いちいちスプレッドを意識しなくても、決済価格を決めることができます。

 

OrderClosePrice関数の具体的な使い方

それでは、OrderClosePrice関数の具体的な使い方を見ていきましょう。

OrderClosePrice関数は、主に決済注文(OrderClose関数)を実行するときに使います。

具体的には以下の通りです。

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

      //決済価格を取得
      double orderClosePrice = OrderClosePrice();

      //ポジションを決済
      bool orderClose = OrderClose( OrderTicket(), OrderLots(), orderClosePrice, 10, clrNONE);

   }

 

 

初めに、OrderSelect関数でポジションを選択します。

その後 OrderClosePrice関数で、決済価格を取得します。

取得した決済価格を、OrderClose関数の引数として使います。

このように、決済注文(OrderClose関数)を出すときに便利な関数なので、覚えておくと良いでしょう。

 

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

ここからは、OrderClosePrice関数を使った実用的なプログラム例を紹介します。実際のEA開発でよく使われるパターンなので、ぜひ参考にしてください。

 

例1:保有中の全ポジションを一括決済するEA

複数のポジションを保有しているときに、すべてのポジションを一括で決済する処理です。ループの中でOrderClosePriceを使って、各ポジションに合った決済価格を自動で取得しています。

//+------------------------------------------------------------------+
//| 全ポジション一括決済関数                                           |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
   // ポジション数を取得(後ろからループすることで番号のズレを防ぐ)
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      // ポジションを選択
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 現在のチャートと同じ通貨ペアのポジションのみ対象
         if(OrderSymbol() == Symbol())
         {
            // OrderClosePriceで決済価格を自動取得(買い/売り問わず正しい価格が返る)
            double closePrice = OrderClosePrice();
            
            // ポジションを決済
            bool result = OrderClose(OrderTicket(), OrderLots(), closePrice, 10, clrRed);
            
            // 決済結果をログに出力
            if(result)
               Print("チケット番号 ", OrderTicket(), " を ", closePrice, " で決済しました");
            else
               Print("チケット番号 ", OrderTicket(), " の決済に失敗しました。エラー: ", GetLastError());
         }
      }
   }
}

ポイントは、ループを後ろから回す(デクリメント)ことです。前から回すと、決済時にポジション番号がズレてしまうので注意しましょう。

 

例2:指定pips以上の利益が出たら利確するEA

保有ポジションの含み益が一定のpips以上になったら、自動で利確する処理です。OrderClosePriceとOrderOpenPriceを組み合わせて、現在の損益pipsを計算しています。

//+------------------------------------------------------------------+
//| 利確pipsの設定                                                     |
//+------------------------------------------------------------------+
input double TakeProfitPips = 30.0;  // 利確するpips数

//+------------------------------------------------------------------+
//| OnTick関数:ティックごとに利確判定を行う                             |
//+------------------------------------------------------------------+
void OnTick()
{
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 現在のチャートの通貨ペアのみ対象
         if(OrderSymbol() != Symbol()) continue;
         
         // 決済価格を取得(売りならAsk、買いならBidが自動で返る)
         double closePrice = OrderClosePrice();
         
         // エントリー価格を取得
         double openPrice = OrderOpenPrice();
         
         // 含み損益をpipsで計算
         double profitPips = 0;
         
         if(OrderType() == OP_BUY)
         {
            // 買いポジション:決済価格(Bid)- エントリー価格
            profitPips = (closePrice - openPrice) / Point / 10;
         }
         else if(OrderType() == OP_SELL)
         {
            // 売りポジション:エントリー価格 - 決済価格(Ask)
            profitPips = (openPrice - closePrice) / Point / 10;
         }
         
         // 設定したpips以上の利益が出たら決済
         if(profitPips >= TakeProfitPips)
         {
            bool result = OrderClose(OrderTicket(), OrderLots(), closePrice, 10, clrBlue);
            if(result)
               Print("利確決済! 利益: ", profitPips, " pips");
         }
      }
   }
}

OrderClosePriceが買い・売りに応じて正しい決済価格を返してくれるので、損益計算と決済の両方で活用できます。

 

例3:合計損益がマイナスになったら全決済する損切りEA

複数ポジションの合計損失額が設定値を超えた場合に、全ポジションを一括で損切りする処理です。OrderClosePriceを使って各ポジションのリアルタイムな損益を確認しています。

//+------------------------------------------------------------------+
//| 最大許容損失額の設定(口座通貨ベース)                               |
//+------------------------------------------------------------------+
input double MaxLossAmount = -10000;  // これ以上の損失で全決済(例:-10,000円)

//+------------------------------------------------------------------+
//| OnTick関数:ティックごとに合計損益をチェック                         |
//+------------------------------------------------------------------+
void OnTick()
{
   double totalProfit = 0;
   
   // 全ポジションの合計損益を計算
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol())
         {
            // OrderProfitで現在の含み損益(口座通貨ベース)を取得
            totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
         }
      }
   }
   
   // 合計損失が許容額を超えたら全決済
   if(totalProfit <= MaxLossAmount)
   {
      Print("合計損失が ", totalProfit, " に達したため、全ポジションを決済します");
      
      for(int i = OrdersTotal() - 1; i >= 0; i--)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         {
            if(OrderSymbol() == Symbol())
            {
               // OrderClosePriceで正しい決済価格を取得
               double closePrice = OrderClosePrice();
               
               bool result = OrderClose(OrderTicket(), OrderLots(), closePrice, 10, clrRed);
               if(result)
                  Print("損切り決済完了:チケット ", OrderTicket());
               else
                  Print("決済失敗:チケット ", OrderTicket(), " エラー: ", GetLastError());
            }
         }
      }
   }
}

合計損益の計算にはOrderProfit関数を使い、決済の実行時にOrderClosePriceで正確な価格を取得しています。スワップや手数料も含めた判定にすることで、より実践的な損切りロジックになっています。

 

例4:トレーリングストップ(利益を追従する決済)EA

一定の利益が出たらストップロスを引き上げ、利益を追従しながら決済を狙うトレーリングストップの処理です。OrderClosePriceで現在の決済価格を取得し、ストップロスの更新判定に活用しています。

//+------------------------------------------------------------------+
//| トレーリングストップの設定                                          |
//+------------------------------------------------------------------+
input double TrailingStartPips = 20.0;  // トレーリング開始の利益pips
input double TrailingStopPips  = 10.0;  // ストップロスを何pips離すか

//+------------------------------------------------------------------+
//| OnTick関数:ティックごとにトレーリングストップを判定                  |
//+------------------------------------------------------------------+
void OnTick()
{
   // pipsをポイントに変換する倍率(5桁/3桁ブローカー対応)
   double pipPoint = Point * 10;
   
   for(int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 現在のチャートの通貨ペアのみ対象
         if(OrderSymbol() != Symbol()) continue;
         
         // OrderClosePriceで現在の決済価格を取得
         double closePrice = OrderClosePrice();
         double openPrice  = OrderOpenPrice();
         double currentSL  = OrderStopLoss();
         
         // --- 買いポジションのトレーリングストップ ---
         if(OrderType() == OP_BUY)
         {
            // 現在の含み益をpipsで計算
            double profitPips = (closePrice - openPrice) / pipPoint;
            
            // トレーリング開始条件を満たしているか
            if(profitPips >= TrailingStartPips)
            {
               // 新しいストップロス価格を計算
               double newSL = closePrice - TrailingStopPips * pipPoint;
               
               // 現在のSLより高い場合のみ更新(SLを引き上げる)
               if(newSL > currentSL || currentSL == 0)
               {
                  bool result = OrderModify(OrderTicket(), openPrice, 
                                            NormalizeDouble(newSL, Digits), 
                                            OrderTakeProfit(), 0, clrGreen);
                  if(result)
                     Print("トレーリングSL更新:チケット ", OrderTicket(), 
                           " 新SL=", NormalizeDouble(newSL, Digits));
               }
            }
         }
         // --- 売りポジションのトレーリングストップ ---
         else if(OrderType() == OP_SELL)
         {
            // 現在の含み益をpipsで計算
            double profitPips = (openPrice - closePrice) / pipPoint;
            
            // トレーリング開始条件を満たしているか
            if(profitPips >= TrailingStartPips)
            {
               // 新しいストップロス価格を計算
               double newSL = closePrice + TrailingStopPips * pipPoint;
               
               // 現在のSLより低い場合のみ更新(SLを引き下げる)
               if(newSL < currentSL || currentSL == 0)
               {
                  bool result = OrderModify(OrderTicket(), openPrice, 
                                            NormalizeDouble(newSL, Digits), 
                                            OrderTakeProfit(), 0, clrGreen);
                  if(result)
                     Print("トレーリングSL更新:チケット ", OrderTicket(), 
                           " 新SL=", NormalizeDouble(newSL, Digits));
               }
            }
         }
      }
   }
}

OrderClosePriceで取得した決済価格を基準にして、「今決済したらいくらになるか」を把握しながらストップロスの位置を計算しています。買い・売りのどちらでも正しい価格が返るため、ロジックがシンプルに書けるのがメリットです。

 

例5:指定時刻に全ポジションを自動決済するEA

週末や経済指標発表前など、特定の時刻になったら保有中のポジションをすべて自動で決済する処理です。時間管理とOrderClosePriceを組み合わせた、実用的なリスク管理ロジックです。

//+------------------------------------------------------------------+
//| 自動決済時刻の設定                                                  |
//+------------------------------------------------------------------+
input int CloseHour   = 23;  // 決済する時(サーバー時間)
input int CloseMinute = 30;  // 決済する分

//+------------------------------------------------------------------+
//| OnTick関数:ティックごとに時刻を判定                                |
//+------------------------------------------------------------------+
void OnTick()
{
   // 現在のサーバー時間を取得
   int currentHour   = Hour();
   int currentMinute = Minute();
   
   // 指定時刻に達したかチェック
   if(currentHour == CloseHour && currentMinute == CloseMinute)
   {
      // 全ポジションを後ろからループして決済
      for(int i = OrdersTotal() - 1; i >= 0; i--)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
         {
            // 現在のチャートの通貨ペアのみ対象
            if(OrderSymbol() != Symbol()) continue;
            
            // マジックナンバーで自分のEAのポジションだけ決済する場合
            // if(OrderMagicNumber() != MagicNumber) continue;
            
            // OrderClosePriceで決済価格を取得
            double closePrice = OrderClosePrice();
            
            // 現在の損益情報をログに記録
            double profit = OrderProfit() + OrderSwap() + OrderCommission();
            Print("時刻決済:チケット ", OrderTicket(), 
                  " 損益=", profit, " 決済価格=", closePrice);
            
            // ポジションを決済
            bool result = OrderClose(OrderTicket(), OrderLots(), closePrice, 15, clrYellow);
            
            if(!result)
            {
               // 決済失敗時はエラーコードを記録して再試行の目安にする
               int err = GetLastError();
               Print("時刻決済失敗:チケット ", OrderTicket(), 
                     " エラーコード=", err);
            }
         }
      }
   }
}

週末持ち越しを避けたい場合は「金曜の23:30」などに設定すると便利です。マジックナンバーによるフィルタリングのコメント部分を有効にすれば、自分のEAが出したポジションだけを対象にすることもできます。

 

例6:ポジション情報をチャート上に表示するインジケーター

保有中のポジションの決済価格・含み損益をチャート上にリアルタイム表示するインジケーターです。OrderClosePriceを使って各ポジションの現在の決済価格を取得し、一覧として視覚的に確認できます。

//+------------------------------------------------------------------+
//| ポジション情報表示インジケーター                                     |
//+------------------------------------------------------------------+
#property indicator_chart_window

//+------------------------------------------------------------------+
//| 初期化処理                                                         |
//+------------------------------------------------------------------+
int OnInit()
{
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 終了処理:オブジェクトを削除                                        |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // 表示したオブジェクトをすべて削除
   ObjectsDeleteAll(0, "PosInfo_");
}

//+------------------------------------------------------------------+
//| メイン処理:ティックごとにポジション情報を更新                       |
//+------------------------------------------------------------------+
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[])
{
   // 前回の表示をクリア
   ObjectsDeleteAll(0, "PosInfo_");
   
   int displayLine = 0;  // 表示行カウンター
   
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         // 現在のチャートの通貨ペアのみ対象
         if(OrderSymbol() != Symbol()) continue;
         
         // OrderClosePriceで現在の決済価格を取得
         double closePrice = OrderClosePrice();
         double openPrice  = OrderOpenPrice();
         double profit     = OrderProfit() + OrderSwap() + OrderCommission();
         
         // ポジション種別の文字列を作成
         string typeStr = (OrderType() == OP_BUY) ? "BUY" : "SELL";
         
         // 含み損益のpipsを計算
         double pipPoint = Point * 10;
         double pips = 0;
         if(OrderType() == OP_BUY)
            pips = (closePrice - openPrice) / pipPoint;
         else
            pips = (openPrice - closePrice) / pipPoint;
         
         // 表示する文字列を組み立て
         string info = StringConcatenate(
            "#", OrderTicket(), " ", typeStr, 
            " | Lots:", DoubleToStr(OrderLots(), 2),
            " | Open:", DoubleToStr(openPrice, Digits),
            " | Close:", DoubleToStr(closePrice, Digits),
            " | ", DoubleToStr(pips, 1), "pips",
            " | ", DoubleToStr(profit, 0), "円");
         
         // オブジェクト名を作成
         string objName = "PosInfo_" + IntegerToString(displayLine);
         
         // チャート左上にテキストラベルとして表示
         ObjectCreate(0, objName, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, objName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
         ObjectSetInteger(0, objName, OBJPROP_XDISTANCE, 10);
         ObjectSetInteger(0, objName, OBJPROP_YDISTANCE, 20 + displayLine * 20);
         ObjectSetString(0, objName, OBJPROP_TEXT, info);
         ObjectSetInteger(0, objName, OBJPROP_FONTSIZE, 10);
         
         // 損益に応じて文字色を変更(プラスなら青、マイナスなら赤)
         color textColor = (profit >= 0) ? clrDodgerBlue : clrRed;
         ObjectSetInteger(0, objName, OBJPROP_COLOR, textColor);
         
         displayLine++;
      }
   }
   
   return(rates_total);
}

OrderClosePriceで取得した決済価格をそのままチャート上に表示しているので、「今決済したらいくらで約定するか」をリアルタイムで確認できます。損益がプラスなら青、マイナスなら赤で表示されるため、視覚的にもわかりやすいインジケーターです。

 

まとめ

OrderClosePrice関数は、選択したポジションの決済価格を返す関数です。買いポジションの場合は売値(Bid)、売りポジションの場合は買値(Ask)が自動的に返されるため、スプレッドを意識せずに正しい決済価格を取得できます。

主にOrderClose関数と組み合わせてポジションの決済処理に使いますが、含み損益の計算やトレーリングストップの判定など、幅広い場面で活用できる便利な関数です。