MT5 Pythonでトレード履歴分析する方法|損益・勝率を可視化

目次

この記事の結論

MT5 Pythonでトレード履歴分析を行う目的は、売買結果を感覚ではなくデータで確認することです。
MetaTrader 5の履歴から約定データを取得し、損益、勝率、損益比、ドローダウン、時間帯別の傾向を整理すると、EAや裁量ロジックの弱点を見つけやすくなります。
Pythonでは、履歴取得、データ整形、集計、可視化を分けて実装すると、分析結果を再利用しやすくなります。
ただし、バックテストや履歴分析の結果は将来の利益を保証しません。実運用では、スプレッド、約定差、ブローカー仕様、口座タイプの違いを考慮する必要があります。

1. MT5 Pythonでトレード履歴分析が必要な理由

【結論】
MT5 Pythonでトレード履歴分析が必要な理由は、EAや売買ロジックの成績を数値で分解できるためです。
単純な総損益だけでは、どの条件で損益が偏ったのかを判断できません。

トレード履歴分析では、口座履歴に残る約定データを取得し、取引ごとの損益、銘柄、時間、ポジション識別子、手数料、スワップなどを確認します。
MT5の画面上でも履歴は確認できますが、Pythonで分析すると、条件別の集計や複数期間の比較を自動化しやすくなります。

【定義】
トレード履歴分析とは、過去の約定データを集計し、売買ロジックの収益性、リスク、偏り、再現性を確認する作業です。

1.1 総損益だけでは不十分な理由

総損益がプラスでも、少数の大きな利益だけに依存している場合があります。
総損益がマイナスでも、特定の時間帯、銘柄、相場状態だけが成績を悪化させている場合があります。

分析では、最低でも次の項目を分けて確認します。

  • 総損益
  • 勝率
  • 平均利益
  • 平均損失
  • 損益比
  • 最大ドローダウン
  • 取引回数
  • 連敗数
  • 銘柄別成績
  • 時間帯別成績

1.2 EA改善に接続しやすい分析単位

EA改善に使いやすい分析単位は、取引結果をロジックの構成要素に戻せる単位です。
たとえば、エントリー条件、決済条件、時間帯、ボラティリティ、スプレッド、銘柄を分けて集計すると、修正すべき箇所を判断しやすくなります。

MT5 Python trade history analysis process showing history_deals_get data retrieval, DataFrame aggregation, profit factor calculation, drawdown measurement, and EA performance reporting

2. MT5 Pythonによる履歴分析の基本構造

【結論】
MT5 Pythonの履歴分析は、接続、履歴取得、データ整形、集計、評価、出力の順で分けると安定します。
この構造にすると、履歴取得の問題と分析ロジックの問題を切り分けやすくなります。

基本的な処理の流れは次のとおりです。

MT5への接続
↓
分析期間の指定
↓
約定履歴の取得
↓
DataFrameへの変換
↓
損益・勝率・ドローダウンの集計
↓
銘柄別・時間帯別の分析
↓
CSVや表への出力

2.1 履歴分析で扱う主なデータ

履歴分析では、注文そのものよりも、実際に成立した約定データを中心に扱います。
注文はリクエスト、約定は取引成立の結果です。分析対象を混同すると、勝率や損益の計算がずれる場合があります。

主に確認する項目は次のとおりです。

項目意味分析での使いどころ
ticket約定の識別番号個別取引の追跡
order注文番号注文と約定の関係確認
position_idポジション識別子エントリーと決済の対応付け
symbol銘柄銘柄別成績の集計
time約定時刻時間帯別分析
type売買や入出金などの種別取引データの抽出
volumeロットリスク量の確認
price約定価格約定条件の確認
profit損益成績集計
commission手数料実質損益の確認
swapスワップ保有コストの確認

2.2 netting口座とhedging口座の違い

MT5では、netting口座とhedging口座でポジション管理の考え方が異なります。
netting口座では同一銘柄のポジションが集約されやすく、hedging口座では同一銘柄で複数ポジションを持てます。

履歴分析では、口座タイプによりエントリーと決済の対応付けが変わる場合があります。
単純に「1つの買いに対して1つの売りが決済」と決めつけると、分割決済や増し玉を正しく扱えないことがあります。

3. 基本構造と必要な準備

【結論】
PythonでMT5履歴を分析するには、MT5端末、Python実行環境、MetaTrader5パッケージ、データ集計用ライブラリを準備します。
分析コードは、取得処理と集計処理を分けると保守しやすくなります。

Python側では、MT5端末に接続して履歴を取得します。
端末側でログインしている口座、取引サーバー、口座種別、履歴期間により取得できる内容が変わる場合があります。

3.1 準備するもの

必要なものは次のとおりです。

  • MetaTrader 5端末
  • Python実行環境
  • MetaTrader5パッケージ
  • pandas
  • 分析対象のMT5口座
  • 分析期間

3.2 分析ファイルの役割分担

履歴分析を続ける場合は、1つのファイルにすべてを書くより、役割を分ける方が再利用しやすくなります。

connection.py      MT5接続と終了処理
history_loader.py  約定履歴の取得
metrics.py         損益指標の計算
report.py          表やCSVへの出力
main.py            実行入口

小規模な検証では1ファイルでも問題ありません。
ただし、EAごとの比較、期間別分析、複数銘柄分析を行う場合は、役割分担を早めに作る方が変更に強くなります。

4. 主要モジュールの役割

【結論】
MT5 Pythonの履歴分析では、接続、取得、整形、指標計算、検証出力を独立した処理として扱います。
役割を分けることで、取得失敗、データ不足、集計ミスを見つけやすくなります。

EA設計と同じように、分析処理も状態と役割を分けることが重要です。
取引実行を行わない分析コードでも、データの取得範囲や取引種別を誤ると、結果が大きく変わります。

4.1 接続モジュール

接続モジュールは、MT5端末との初期化と終了を担当します。
接続失敗時は、分析処理を続けずに停止します。

4.2 履歴取得モジュール

履歴取得モジュールは、指定期間の約定データを取得します。
分析対象が注文履歴なのか約定履歴なのかを明確にします。

4.3 指標計算モジュール

指標計算モジュールは、損益、勝率、損益比、最大ドローダウンなどを計算します。
手数料とスワップを含めるかどうかも、あらかじめ決める必要があります。

4.4 レポート出力モジュール

レポート出力モジュールは、集計結果をCSVや表に整理します。
後から比較できるように、分析期間、口座タイプ、銘柄、時間足、EA名などの条件も一緒に残すと扱いやすくなります。

5. 実装パターン

【結論】
MT5 Pythonの履歴分析は、最初は約定履歴の取得と基本指標の集計から始めるのが現実的です。
その後、銘柄別、時間帯別、ポジション単位の分析へ広げると、原因を段階的に深掘りできます。

実装パターンは、分析目的によって変わります。
単発の確認ならシンプルな集計で十分ですが、EA改善に使う場合は、同じ指標を繰り返し計算できる形にする必要があります。

5.1 パターン別の考え方

方法メリットデメリット向いている場面
約定ごとの単純集計実装しやすい分割決済や増し玉の分析が粗くなる初期確認
銘柄別集計弱い銘柄を見つけやすい取引回数が少ないと判断しにくい複数銘柄EA
時間帯別集計約定環境の偏りを見やすいサーバー時刻と現地時刻の扱いが必要時間フィルター検証
ポジション単位集計取引のまとまりを評価しやすいnetting口座とhedging口座で処理が変わるEA改善
条件タグ別集計ロジック別の成績を分けやすいEA側でコメントや識別子設計が必要複数シグナルEA

5.2 条件タグを残す設計

EA側で注文コメントやマジックナンバーを設計しておくと、Python分析でロジック別の集計がしやすくなります。
たとえば、トレンドフォロー、押し目買い、ブレイクアウトなどのシグナルを識別できるようにしておくと、後から弱い条件を分けて確認できます。

6. サンプルコード

【結論】
PythonでMT5の履歴を分析する基本は、MT5端末に接続し、指定期間の約定履歴を取得し、DataFrameで集計する流れです。
取得件数がゼロの場合や接続に失敗した場合は、分析結果を出さずに原因を確認します。

次のコードは、検証用の最小構成です。
実運用判断ではなく、履歴データを集計するためのサンプルです。

from datetime import datetime, timedelta

import MetaTrader5 as mt5
import pandas as pd


def initialize_mt5() -> bool:
    if not mt5.initialize():
        print("MT5 initialization failed:", mt5.last_error())
        return False
    return True


def shutdown_mt5() -> None:
    mt5.shutdown()


def load_deals(days: int = 90) -> pd.DataFrame:
    date_to = datetime.now()
    date_from = date_to - timedelta(days=days)

    deals = mt5.history_deals_get(date_from, date_to)
    if deals is None:
        raise RuntimeError(f"Failed to get deal history: {mt5.last_error()}")

    if len(deals) == 0:
        return pd.DataFrame()

    first_deal = next(iter(deals))
    df = pd.DataFrame(list(deals), columns=first_deal._asdict().keys())
    df["time"] = pd.to_datetime(df["time"], unit="s")
    return df


def filter_trade_deals(df: pd.DataFrame) -> pd.DataFrame:
    if df.empty:
        return df

    # profit列が存在する約定を分析対象にする
    trade_df = df.copy()
    trade_df["net_profit"] = (
        trade_df["profit"].fillna(0)
        + trade_df["commission"].fillna(0)
        + trade_df["swap"].fillna(0)
    )
    return trade_df


def calculate_metrics(df: pd.DataFrame) -> dict:
    if df.empty:
        return {
            "trades": 0,
            "total_profit": 0.0,
            "win_rate": 0.0,
            "average_win": 0.0,
            "average_loss": 0.0,
            "profit_factor": 0.0,
            "max_drawdown": 0.0,
        }

    profits = df["net_profit"]
    wins = profits[profits > 0]
    losses = profits[profits < 0]

    equity_curve = profits.cumsum()
    running_max = equity_curve.cummax()
    drawdown = equity_curve - running_max

    gross_profit = wins.sum()
    gross_loss = abs(losses.sum())

    return {
        "trades": int(len(df)),
        "total_profit": float(profits.sum()),
        "win_rate": float(len(wins) / len(df)) if len(df) > 0 else 0.0,
        "average_win": float(wins.mean()) if len(wins) > 0 else 0.0,
        "average_loss": float(losses.mean()) if len(losses) > 0 else 0.0,
        "profit_factor": float(gross_profit / gross_loss) if gross_loss > 0 else 0.0,
        "max_drawdown": float(drawdown.min()) if len(drawdown) > 0 else 0.0,
    }


def summarize_by_symbol(df: pd.DataFrame) -> pd.DataFrame:
    if df.empty or "symbol" not in df.columns:
        return pd.DataFrame()

    return (
        df.groupby("symbol")
        .agg(
            trades=("net_profit", "count"),
            total_profit=("net_profit", "sum"),
            average_profit=("net_profit", "mean"),
        )
        .sort_values("total_profit", ascending=False)
    )


def main() -> None:
    if not initialize_mt5():
        return

    try:
        raw_deals = load_deals(days=90)
        trade_deals = filter_trade_deals(raw_deals)
        metrics = calculate_metrics(trade_deals)
        symbol_summary = summarize_by_symbol(trade_deals)

        print("Overall metrics")
        for key, value in metrics.items():
            print(f"{key}: {value}")

        print("\nSymbol summary")
        print(symbol_summary)

    finally:
        shutdown_mt5()


if __name__ == "__main__":
    main()

6.1 コードの確認ポイント

このコードでは、MT5接続に失敗した場合は履歴取得を実行しません。
履歴が取得できない場合は、空の結果と取得失敗を分けて扱います。

実際の分析では、入出金、残高調整、手数料だけの行などを除外する条件が必要になる場合があります。
ブローカーや口座履歴の内容により、扱うべき行は変わります。

6.2 実運用前に追加したい処理

実運用に近い分析では、次の処理を追加します。

  • マジックナンバー別の集計
  • 注文コメント別の集計
  • 時間帯別の集計
  • ポジション単位の損益集計
  • 入出金データの除外
  • スプレッド拡大時間帯の確認
  • CSV保存
  • 分析条件のログ保存

7. 設計パターン比較

【結論】
MT5 Pythonの履歴分析では、分析粒度が細かいほど原因を特定しやすくなります。
一方で、粒度を細かくしすぎると取引回数が不足し、統計的に判断しにくくなります。

分析設計では、最初から複雑な分類を増やすより、総合成績、銘柄別、時間帯別、ロジック別の順に広げる方が扱いやすくなります。

方法メリットデメリット向いている場面実装難易度
総合成績分析全体像をすぐ確認できる原因特定が難しい初回分析低い
銘柄別分析得意銘柄と苦手銘柄を分けやすい取引回数に偏りが出やすい複数銘柄EA低い
時間帯別分析約定環境や流動性の影響を見やすい時刻変換の扱いが必要時間フィルター検証中程度
ポジション単位分析取引のまとまりを評価できる口座タイプ差の処理が必要分割決済の分析高い
ロジック別分析シグナルの弱点を分けやすいEA側の識別子設計が必要複数戦略EA中程度

7.1 初心者が最初に使いやすい分析

初心者が最初に行うなら、総合成績、銘柄別、時間帯別の3つが扱いやすいです。
この3つで大きな偏りが見えた後に、ポジション単位やロジック別の分析へ進むと、実装負担を抑えやすくなります。

7.2 過剰分析を避ける考え方

取引回数が少ない条件で細かく分類すると、偶然の勝ち負けをロジックの優劣と誤解する場合があります。
分析粒度を上げるほど、十分な取引回数と期間の確認が必要です。

8. バックテストで確認すべき項目

【結論】
バックテストでは、総損益だけでなく、最大ドローダウン、取引回数、連敗数、期間依存性、パラメータ依存性を確認します。
バックテスト結果は、実運用の約定条件を完全には再現しません。

バックテスト履歴をPythonで分析すると、MT5のレポートだけでは見えにくい偏りを確認しやすくなります。
特に、特定の期間だけ成績が良いロジックや、スプレッド条件に弱いロジックは注意が必要です。

8.1 必ず見る指標

バックテストでは次の項目を確認します。

  • 総損益
  • 最大ドローダウン
  • 勝率
  • 損益比
  • 取引回数
  • 連敗数
  • スプレッド条件
  • 期間依存性
  • パラメータ依存性

8.2 パラメータ依存性の見方

特定のパラメータだけが極端に良い場合、過剰最適化の可能性があります。
近い値でも成績が大きく崩れる場合は、実運用で再現性が低くなりやすいです。

バックテスト分析では、最良値だけを見るのではなく、周辺パラメータの安定性を確認します。
安定性が低いロジックは、スプレッドや約定差の影響で結果が変わりやすくなります。

9. フォワードテストで確認すべき項目

【結論】
フォワードテストでは、バックテストと実際の約定環境の差を確認します。
スプレッド拡大、約定遅延、ブローカー差、VPS環境の安定性は、履歴分析で必ず確認すべき項目です。

フォワードテストの履歴分析では、過去データに合わせたロジックが、未知の相場でも同じように機能するかを確認します。
バックテストで良い成績でも、フォワードで取引頻度やドローダウンが大きく変わる場合があります。

9.1 フォワードで見る指標

フォワードテストでは次の項目を確認します。

  • 約定差
  • スプレッド拡大時の挙動
  • 取引頻度
  • ドローダウン
  • バックテストとの乖離
  • ブローカー差
  • VPS環境での安定性

9.2 バックテストとの乖離を判断する

フォワードテストで重要なのは、損益だけではありません。
取引回数、平均損益、連敗数、最大ドローダウンがバックテストと大きく違う場合、ロジックの前提が崩れている可能性があります。

ただし、短期間のフォワードテストだけで断定することも危険です。
相場環境が偏る期間では、一時的に良い結果や悪い結果が出ることがあります。

10. 実運用での注意点

【結論】
MT5 Pythonの履歴分析は、実運用リスクを減らすための確認作業であり、利益を保証するものではありません。
実運用では、スプレッド、スリッページ、約定方式、証拠金、レバレッジ、ブローカー仕様を考慮する必要があります。

履歴分析で良い結果が出ても、実運用では条件が変わります。
デモ口座とリアル口座で約定条件が異なる場合もあります。

10.1 スプレッドと約定差

短期売買EAでは、スプレッド拡大や約定遅延が成績に大きく影響します。
履歴分析では、損益が小さい取引が多いほど、取引コストに弱い可能性を確認します。

10.2 ロットとレバレッジ

同じロジックでも、ロットが大きいほど損益変動とドローダウンは大きくなります。
レバレッジが高いほど、証拠金維持率の低下や強制決済のリスクも高まりやすくなります。

ロット計算を分析する場合は、最小ロット、最大ロット、ロットステップ、証拠金、ティックバリュー、ティックサイズを確認します。
銘柄仕様により、同じロットでも損益の動きは異なります。

10.3 注文前チェックとの接続

履歴分析で問題が見えた場合、EA側では注文前チェックも見直します。
MQL5のEAでは、注文前に取引許可、スプレッド、ロット制限、証拠金、ストップレベル、フリーズレベル、既存ポジションを確認する設計が必要です。

注文処理を行うEAでは、MqlTradeRequestMqlTradeResultMqlTradeCheckResult を分けて扱い、OrderSend の前に OrderCheck で注文条件を確認する構造が実用的です。

11. よくある設計ミス

【結論】
MT5 Pythonの履歴分析で多い失敗は、取引データの種類、手数料、スワップ、口座タイプ、期間条件を正しく扱わないことです。
分析前提がずれると、改善すべきロジックを誤って判断する可能性があります。

履歴分析では、コードが動くだけでは十分ではありません。
分析対象としているデータが、目的に合っているかを確認する必要があります。

11.1 入出金を損益に含めてしまう

入出金や残高調整を取引損益に含めると、EA成績が実態と異なる値になります。
履歴データを扱うときは、売買による損益と資金移動を分けます。

11.2 手数料とスワップを無視する

profit だけを集計すると、実質損益とずれる場合があります。
手数料やスワップが発生する銘柄では、profitcommissionswap を合わせた値を確認します。

11.3 取引回数が少ない条件で判断する

取引回数が少ない条件では、偶然の利益や損失の影響が大きくなります。
条件別分析では、集計結果と取引回数を必ずセットで確認します。

11.4 時刻の扱いを間違える

MT5の履歴時刻は、端末やサーバー時刻の扱いを意識する必要があります。
時間帯別分析では、どの時刻基準で集計しているかを明確にします。

12. まとめ

【結論】
MT5 Pythonでトレード履歴分析を行うと、EAや売買ロジックの成績を分解して確認できます。
分析は、履歴取得、データ整形、指標計算、条件別集計、検証結果の保存に分けると実務で使いやすくなります。

トレード履歴分析では、総損益だけでなく、勝率、損益比、最大ドローダウン、連敗数、銘柄別成績、時間帯別成績を確認します。
EA改善に使う場合は、マジックナンバーや注文コメントを設計し、ロジック別に分析できる状態を作ることが重要です。

バックテストとフォワードテストの結果は一致しない場合があります。
実運用では、スプレッド、約定差、ブローカー仕様、口座タイプ、レバレッジ、ドローダウン許容度を考慮し、十分な検証を行う必要があります。

FAQ

MT5 Pythonでトレード履歴分析をする目的は何ですか?

MT5 Pythonでトレード履歴分析をする目的は、EAや売買ロジックの成績を数値で分解することです。総損益だけでなく、勝率、損益比、ドローダウン、銘柄別成績、時間帯別成績を確認できます。

Pythonでは注文履歴と約定履歴のどちらを分析すべきですか?

損益分析では、実際に成立した約定履歴を中心に扱うのが基本です。注文履歴はリクエストの確認に使いやすく、約定履歴は成績集計に使いやすいデータです。

profitだけを集計しても問題ありませんか?

profit だけでは実質損益とずれる場合があります。手数料やスワップがある場合は、profitcommissionswap を合わせて確認します。

銘柄別分析はどのような場面で役立ちますか?

銘柄別分析は、EAが得意な銘柄と苦手な銘柄を分けて確認する場面で役立ちます。ただし、取引回数が少ない銘柄では判断が不安定になりやすいです。

バックテスト履歴を分析するときの注意点は何ですか?

バックテスト履歴では、総損益、最大ドローダウン、取引回数、連敗数、パラメータ依存性を確認します。バックテスト結果は将来の利益を保証しないため、フォワードテストも必要です。

フォワードテスト履歴では何を確認すべきですか?

フォワードテスト履歴では、約定差、スプレッド拡大時の挙動、取引頻度、ドローダウン、バックテストとの乖離を確認します。ブローカー差やVPS環境の安定性も成績に影響する場合があります。

MT5 Python分析でよくある失敗は何ですか?

よくある失敗は、入出金を取引損益に含めること、手数料やスワップを無視すること、取引回数が少ない条件で断定することです。分析前提を固定してから集計する必要があります。

履歴分析だけでEAを実運用できますか?

履歴分析だけでEAの実運用を判断するのは不十分です。実運用前には、フォワードテスト、スプレッド条件、約定差、ロット制限、ドローダウン許容度を確認する必要があります。