【MQL4】注文情報を取得する関数を徹底解説!OrderOpenPrice・OrderStopLoss・OrderTakeProfit・OrderCloseTime・OrderProfit の使い方

関数

EA(自動売買)を開発していると、「今持っているポジションのエントリー価格はいくらだろう?」「ストップロスはちゃんと設定されているかな?」といった場面に必ず出くわします。MQL4には、選択中の注文からさまざまな情報を取り出すための専用関数が用意されています。

この記事では、EA開発で頻繁に使う5つの注文情報取得関数――OrderOpenPrice()OrderStopLoss()OrderTakeProfit()OrderCloseTime()OrderProfit()を、サンプルコード付きで徹底解説します。

前提知識:OrderSelect() で注文を選択してから使う

MQL4の注文情報取得関数には、共通のルールがあります。それは「必ず事前に OrderSelect() で注文を選択しておくこと」です。

OrderSelect() を呼ばずにこれらの関数を使うと、意図しない値が返ってきたり、前回選択した注文の情報が返ってしまったりします。これはMQL4初心者が最もハマりやすいポイントの一つです。

// 基本パターン:注文を選択してから情報を取得する
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
    double openPrice = OrderOpenPrice();   // エントリー価格
    double sl        = OrderStopLoss();    // 損切り価格
    double tp        = OrderTakeProfit();  // 利確価格
    double profit    = OrderProfit();      // 損益額
}

この前提を押さえた上で、各関数を詳しく見ていきましょう。

OrderOpenPrice() — エントリー価格を取得する

基本仕様

OrderOpenPrice() は、選択中の注文の約定価格(エントリー価格)double 型で返します。

double OrderOpenPrice();

成行注文の場合は実際に約定した価格、指値・逆指値注文(未約定の待機注文)の場合は設定した注文価格が返ります。

使用例

if(OrderSelect(0, SELECT_BY_POS, MODE_TRADES))
{
    double entryPrice = OrderOpenPrice();
    Print("エントリー価格: ", entryPrice);
}

エントリー価格は、損益の計算やトレーリングストップのロジックなど、あらゆる場面で使う最も基本的な注文情報です。

OrderStopLoss() — 損切り価格を取得する

基本仕様

OrderStopLoss() は、選択中の注文に設定されているストップロス(損切り)価格double 型で返します。

double OrderStopLoss();

ストップロスが設定されていない場合は 0 が返ります。この性質を利用して、「SLが未設定のポジションを検出する」といった処理が可能です(応用例で後述します)。

OrderTakeProfit() — 利確価格を取得する

基本仕様

OrderTakeProfit() は、選択中の注文に設定されているテイクプロフィット(利益確定)価格double 型で返します。

double OrderTakeProfit();

OrderStopLoss() と同様に、テイクプロフィットが未設定の場合は 0 が返ります。

OrderCloseTime() — 決済時刻を取得する

基本仕様

OrderCloseTime() は、選択中の注文の決済時刻datetime 型で返します。

datetime OrderCloseTime();

ここで重要なのが、まだ決済されていないポジション(保有中のポジション)の場合は 0 が返るという点です。この性質を使えば、「この注文はまだ保有中か、それとも決済済みか」を判定できます。

使用例

if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
    datetime closeTime = OrderCloseTime();
    if(closeTime > 0)
    {
        Print("決済時刻: ", TimeToString(closeTime, TIME_DATE | TIME_MINUTES));
    }
    else
    {
        Print("この注文はまだ未決済です");
    }
}

履歴からトレード結果を分析するEAや、日報を自動生成するスクリプトを作る際に活躍します。

OrderProfit() — 損益額を取得する

基本仕様

OrderProfit() は、選択中の注文の損益額(口座通貨建て)double 型で返します。

double OrderProfit();

保有中のポジションなら含み損益、決済済みの注文なら確定損益が返ります。

重要な注意点:OrderProfit() が返す値にはスワップポイントと取引手数料は含まれません。スワップを含めた正確な損益を計算するには、OrderSwap()OrderCommission() を加算する必要があります。

// スワップと手数料を含めた正確な損益
double totalProfit = OrderProfit() + OrderSwap() + OrderCommission();

実践サンプル:全ポジションの注文情報を一覧表示する

ここまで学んだ5つの関数を組み合わせて、保有中の全ポジション情報をエキスパートログに出力する実践的な関数を作ってみましょう。

void ShowAllOrderInfo()
{
    int totalOrders = OrdersTotal();
    Print("===== 保有ポジション一覧(全 ", totalOrders, " 件)=====");

    for(int i = totalOrders - 1; i >= 0; i--)
    {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
            continue;

        // 自分のEAの注文だけを対象にする
        if(OrderMagicNumber() != 12345)
            continue;

        // 待機注文を除外し、成行注文(ポジション)のみ対象にする
        if(OrderType() > OP_SELL)
            continue;

        string type = (OrderType() == OP_BUY) ? "BUY" : "SELL";
        double totalPL = OrderProfit() + OrderSwap() + OrderCommission();

        Print("チケット: ", OrderTicket(),
              " | 通貨: ", OrderSymbol(),
              " | ", type,
              " | ロット: ", OrderLots(),
              " | エントリー: ", DoubleToString(OrderOpenPrice(), Digits),
              " | SL: ", DoubleToString(OrderStopLoss(), Digits),
              " | TP: ", DoubleToString(OrderTakeProfit(), Digits),
              " | 損益: ", DoubleToString(totalPL, 2));
    }

    Print("==========================================");
}

ループを totalOrders - 1 から 0 に向かって逆順で回しているのがポイントです。これについては後述の注意点で詳しく説明します。

応用例:SL未設定ポジションに自動でSLを追加する

OrderStopLoss()0 を返す(=SL未設定)ポジションを検出し、自動的にストップロスを設定する実用的なサンプルです。

void SetSLForUnprotectedPositions(int magicNumber, int slPips)
{
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
            continue;

        if(OrderMagicNumber() != magicNumber)
            continue;

        // SLが既に設定されている場合はスキップ
        if(OrderStopLoss() != 0)
            continue;

        double newSL = 0;
        double point = MarketInfo(OrderSymbol(), MODE_POINT);
        int    digits = (int)MarketInfo(OrderSymbol(), MODE_DIGITS);

        // 3桁/5桁業者対応
        if(digits == 3 || digits == 5)
            point *= 10;

        if(OrderType() == OP_BUY)
        {
            newSL = OrderOpenPrice() - slPips * point;
        }
        else if(OrderType() == OP_SELL)
        {
            newSL = OrderOpenPrice() + slPips * point;
        }
        else
        {
            continue; // 待機注文はスキップ
        }

        newSL = NormalizeDouble(newSL, digits);

        bool result = OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrYellow);

        if(result)
        {
            Print("SL設定成功 チケット:", OrderTicket(), " SL:", DoubleToString(newSL, digits));
        }
        else
        {
            Print("SL設定失敗 チケット:", OrderTicket(), " エラー:", GetLastError());
        }
    }
}

OrderStopLoss() != 0 で「SLが設定済みかどうか」を判定し、未設定のポジションにのみ OrderModify() でSLを追加しています。リスク管理を自動化する際にとても便利なパターンです。

3つの重要な注意点

1. OrderSelect() の呼び忘れに注意

繰り返しになりますが、すべての注文情報取得関数は OrderSelect() で注文を選択した後に呼ぶ必要があります。選択せずに使うと、前回選択した注文の情報が返ったり、不正な値が返ったりして、バグの原因になります。

2. ループは逆順(降順)で回す

注文一覧をループする際は、for(int i = OrdersTotal() - 1; i >= 0; i--) のように逆順で回すのがMQL4の定石です。

なぜなら、ループ中に注文が決済されるとインデックスがズレてしまうからです。昇順(0から)でループすると、途中の注文が消えた際にインデックスが詰まり、一部の注文がスキップされてしまいます。逆順で回せばこの問題を回避できます。

3. OrderProfit() にはスワップ・手数料が含まれない

OrderProfit() は純粋な為替差益のみを返します。スワップポイントや取引手数料は含まれません。正確なトータル損益を出すには、必ず以下のように計算してください。

double totalPL = OrderProfit() + OrderSwap() + OrderCommission();

特にスワップが大きい通貨ペアや、ECN口座のように手数料が発生する環境では、この差が無視できない金額になることがあります。

まとめ

今回解説した5つの関数を一覧表で整理します。

関数名 戻り値の型 取得できる情報 備考
OrderOpenPrice() double エントリー価格(約定価格) 待機注文の場合は設定した注文価格
OrderStopLoss() double ストップロス価格 未設定なら0が返る
OrderTakeProfit() double テイクプロフィット価格 未設定なら0が返る
OrderCloseTime() datetime 決済時刻 未決済なら0が返る
OrderProfit() double 損益額(口座通貨建て) スワップ・手数料は含まない

いずれの関数も、事前に OrderSelect() で注文を選択することが必須です。また、ループは逆順で回す、OrderProfit() にはスワップが含まれない、といったポイントを押さえておけば、安全で正確なEAを開発できます。

これらの関数をマスターすれば、ポジション管理・リスク管理・トレード分析など、EA開発の幅が大きく広がります。ぜひ実際のコードに組み込んで試してみてください!