【MQL5】HistorySelectByPosition関数の使い方と自動売買実装コード

1. HistorySelectByPosition関数の概要と実務での活用法

MQL5での取引履歴管理は、MQL4と比べて非常に厳格かつ多層的です。その中でも HistorySelectByPosition は、特定の「ポジションID」に関連する全ての注文(Order)と約定(Deal)を履歴データベースから抽出するための非常に強力な関数です。

実務レベルの開発において、この関数は主に「決済された直後のポジションの最終損益やスワップ、手数料を正確に算出する」ために活用されます。

なぜこの関数が必要なのか?

初心者の方が最初につまずくのは、「決済注文を出した瞬間にそのトレードの結果を取得しようとする」点です。MQL5では、ポジションが決済されると「ポジション」という概念は消滅し、複数の「約定(Deal)」として履歴に格納されます。
HistorySelectByPosition を使うことで、複雑な履歴の中から「特定のポジションIDに紐付くデータだけ」を一瞬でフィルタリングでき、ループ処理で合計損益を計算する際の実装ミスを大幅に減らすことができます。


2. 構文と戻り値

この関数は非常にシンプルですが、呼び出した後に初めて履歴データへのアクセス権が得られるという点に注目してください。

bool HistorySelectByPosition(
   long position_id    // ポジション識別子(POSITION_TICKET)
);

パラメーター

  • position_id: 追跡したいポジションのIDを指定します。これはポジションがオープンされた際に割り当てられる一意の番号です。

戻り値

  • true: 履歴の取得に成功した場合。
  • false: 失敗した場合。GetLastError() を呼び出すことで詳細なエラーコードを確認できます。

3. 具体的な使い方・実践サンプルコード

以下は、あるポジションが決済された際に、そのポジションに関連する全ての約定から「純損益(損益+スワップ+手数料)」を算出する実戦的なコード例です。

// ポジションIDを指定して、その履歴の統計を表示する関数
void PrintPositionPerformance(long position_id)
{
    // 1. 指定したポジションIDに関連する履歴をキャッシュにロードする
    if(!HistorySelectByPosition(position_id))
    {
        Print("履歴の取得に失敗しました。Position ID:", position_id);
        return;
    }

    uint deals_total = HistoryDealsTotal();
    double total_profit = 0;
    double total_commission = 0;
    double total_swap = 0;

    // 2. ロードされた履歴(約定)を一つずつ走査する
    for(uint i = 0; i < deals_total; i++)
    {
        ulong deal_ticket = HistoryDealGetTicket(i);
        if(deal_ticket > 0)
        {
            // 約定の各データを取得
            double profit     = HistoryDealGetDouble(deal_ticket, DEAL_PROFIT);
            double commission = HistoryDealGetDouble(deal_ticket, DEAL_COMMISSION);
            double swap       = HistoryDealGetDouble(deal_ticket, DEAL_SWAP);

            total_profit     += profit;
            total_commission += commission;
            total_swap       += swap;
        }
    }

    // 3. 結果の出力
    PrintFormat("--- Position ID: %d の集計結果 ---", position_id);
    PrintFormat("実現損益: %.2f", total_profit);
    PrintFormat("手数料: %.2f", total_commission);
    PrintFormat("スワップ: %.2f", total_swap);
    PrintFormat("純損益: %.2f", total_profit + total_commission + total_swap);
}

4. 使用上の注意点とよくあるエラー

① チケット番号の取り違え

MQL5には「オーダーチケット」「ディールチケット」「ポジションチケット」の3種類が存在します。HistorySelectByPosition に渡すのは、必ず POSITION_TICKET(またはポジションが新規建てされた際の DEAL_POSITION_ID)である必要があります。ここを混同すると、履歴が一件も取得できないというバグに繋がります。

② ヘッジング口座での挙動

ヘッジング口座(同一通貨ペアの複数ポジション保有が可能)の場合、ポジションを「分割決済」や「部分決済」すると、履歴には複数の決済約定が残ります。この関数を使わずに単純な履歴検索を行うと、一部の決済データを見落とすリスクがありますが、HistorySelectByPosition を使えば分割されたデータも漏れなく抽出可能です。

③ 履歴の有効期間

この関数はMetaTrader 5の「口座履歴」タブに表示されている範囲の影響を受けることがあります。通常、プログラムから呼び出す場合は全履歴が対象となりますが、極端に古いポジションIDを指定する場合、念のため HistorySelect(0, TimeCurrent()) などで全履歴をアクティブにする必要があるケースもあります。


5. 【重要】自動売買における約定スピードと環境の罠

自動売買プログラム(EA)がどれほど論理的に完璧であっても、それを実行する物理的環境が脆弱であれば、期待した収益を得ることは不可能です。特に、自宅のPCや一般的な光回線を利用したトレードには「ネットワーク遅延(レイテンシ)」という致命的な弱点があります。ミリ秒単位の遅延が発生するだけで、HistorySelectByPosition で損益を確認する前段階の「決済注文」そのものの価格が滑り(スリッページ)、バックテストの結果とはかけ離れた損失を招くことになります。

クオンツエンジニアの視点では、ブローカーのサーバーに対して物理的に近い距離にある「専用のVPS(仮想専用サーバー)」の導入は、コストではなく「必須の投資」です。ネットワーク遅延を極限まで抑えることで、注文の約定拒否やスリッページを最小限に抑え、プログラムが計算した通りの優位性を市場で発揮できるようになります。安定した24時間稼働と高速なレスポンスを確保できるプロフェッショナルなインフラ環境を整えることこそが、システムトレーダーとしての成功の第一歩です。

💡 この記事の内容を実運用で活かすには?

この記事の内容を実運用で活かすには、正しい環境が必要です。
特にVPSを使わないと、このロジックは再現できません。

コメント

タイトルとURLをコピーしました