How to Analyze Trade History with MT5 Python: Visualize Profit, Loss, and Win Rate

目次

Key Takeaways

The purpose of MT5 Python trade history analysis is to review trading results with data instead of relying on impressions.
By retrieving deal data from MetaTrader 5 history and organizing profit and loss, win rate, risk-reward ratio, drawdown, and time-based tendencies, you can identify weak points in an EA or discretionary trading logic more easily.
In Python, it is easier to reuse analysis results when history retrieval, data preparation, aggregation, and visualization are implemented as separate steps.
However, backtest and history analysis results do not guarantee future profit. In live trading, you must consider spreads, slippage, broker rules, and differences between account types.

1. Why MT5 Python Trade History Analysis Is Necessary

Conclusion:
MT5 Python trade history analysis is necessary because it lets you break down the performance of an EA or trading logic into measurable data.
Total profit alone does not show which conditions caused gains or losses to become concentrated.

Trade history analysis retrieves deal data stored in the account history and checks profit and loss, symbols, times, position identifiers, commissions, swaps, and other fields for each trade.
You can review history in the MT5 screen, but Python makes it much easier to automate aggregation by condition and compare multiple periods.

Definition:
Trade history analysis is the process of aggregating past deal data to check the profitability, risk, bias, and repeatability of a trading logic.

1.1 Why Total Profit Alone Is Not Enough

Even when total profit is positive, the result may depend on only a small number of large winning trades.
Even when total profit is negative, only a specific time period, symbol, or market condition may be hurting performance.

At a minimum, separate and check the following items in your analysis.

  • Total profit
  • Win rate
  • Average win
  • Average loss
  • Risk-reward ratio
  • Maximum drawdown
  • Number of trades
  • Consecutive losses
  • Performance by symbol
  • Performance by time period

1.2 Analysis Units That Connect Easily to EA Improvement

The most useful analysis units for improving an EA are units that can be traced back to the components of the trading logic.
For example, if you aggregate entry conditions, exit conditions, time periods, volatility, spreads, and symbols separately, it becomes easier to decide which part should be changed.

MT5 Python trade history analysis workflow showing deal history retrieval, DataFrame preparation, performance metrics, aggregation, visualization, and risk notes

2. Basic Structure of MT5 Python History Analysis

Conclusion:
MT5 Python history analysis is more stable when you separate it into connection, history retrieval, data preparation, aggregation, evaluation, and output.
This structure makes it easier to distinguish history retrieval problems from analysis logic problems.

The basic processing flow is as follows.

Connect to MT5
↓
Specify the analysis period
↓
Retrieve deal history
↓
Convert to a DataFrame
↓
Aggregate profit, win rate, and drawdown
↓
Analyze by symbol and time period
↓
Output to CSV or tables

2.1 Main Data Used in History Analysis

In history analysis, you mainly use actual executed deal data rather than the orders themselves.
An order is a request, while a deal is the result of an executed transaction. If you mix these up, win rate and profit calculations may become inaccurate.

The main fields to check are as follows.

FieldMeaningHow It Is Used in Analysis
ticketDeal identifierTracking each trade
orderOrder numberChecking the relationship between orders and deals
position_idPosition identifierMatching entries and exits
symbolTrading symbolAggregating performance by symbol
timeDeal timeTime-period analysis
typeType such as buy, sell, deposit, or withdrawalExtracting trading data
volumeLot sizeChecking risk amount
priceExecution priceChecking execution conditions
profitProfit or lossPerformance aggregation
commissionCommissionChecking net performance
swapSwapChecking holding costs

2.2 Differences Between Netting and Hedging Accounts

In MT5, position management differs between netting accounts and hedging accounts.
In a netting account, positions for the same symbol are usually consolidated. In a hedging account, you can hold multiple positions on the same symbol.

In history analysis, the method for matching entries and exits may change depending on the account type.
If you simply assume that one buy trade is closed by one sell trade, you may fail to handle partial closes or position additions correctly.

3. Basic Structure and Required Preparation

Conclusion:
To analyze MT5 history with Python, prepare the MT5 terminal, a Python runtime, the MetaTrader5 package, and libraries for data aggregation.
The analysis code is easier to maintain when the retrieval process and the aggregation process are separated.

On the Python side, you connect to the MT5 terminal and retrieve history data.
The account logged in on the terminal, trading server, account type, and history period may affect the data that can be retrieved.

3.1 What You Need

You need the following items.

  • MetaTrader 5 terminal
  • Python runtime
  • MetaTrader5 package
  • pandas
  • MT5 account to analyze
  • Analysis period

3.2 Separating the Roles of Analysis Files

If you plan to continue history analysis, separating roles is easier to reuse than writing everything in one file.

connection.py      MT5 connection and shutdown processing
history_loader.py  Retrieve deal history
metrics.py         Calculate performance metrics
report.py          Output tables and CSV files
main.py            Execution entry point

For small-scale validation, one file is not a problem.
However, if you compare multiple EAs, analyze separate periods, or analyze multiple symbols, creating this role separation early makes later changes easier.

4. Roles of the Main Modules

Conclusion:
In MT5 Python history analysis, connection, retrieval, preparation, metric calculation, and validation output should be treated as separate processes.
Separating roles makes it easier to find retrieval failures, insufficient data, and aggregation mistakes.

As with EA design, it is important to separate state and responsibility in analysis processing.
Even when the analysis code does not execute trades, choosing the wrong data range or trade type can greatly change the results.

4.1 Connection Module

The connection module handles initialization and shutdown for the MT5 terminal.
If the connection fails, stop the analysis instead of continuing.

4.2 History Retrieval Module

The history retrieval module retrieves deal data for the specified period.
Clearly decide whether the analysis target is order history or deal history.

4.3 Metric Calculation Module

The metric calculation module calculates profit and loss, win rate, risk-reward ratio, maximum drawdown, and similar metrics.
You also need to decide in advance whether commissions and swaps are included.

4.4 Report Output Module

The report output module organizes aggregation results into CSV files or tables.
To make later comparisons easier, store the analysis period, account type, symbol, timeframe, EA name, and other conditions together with the results.

5. Implementation Patterns

Conclusion:
For MT5 Python history analysis, it is practical to start with retrieving deal history and aggregating basic metrics.
After that, you can expand into symbol-based, time-based, and position-based analysis to investigate causes step by step.

The implementation pattern changes depending on the analysis purpose.
For a one-time check, simple aggregation is enough. If you use it for EA improvement, you need a structure that can calculate the same metrics repeatedly.

5.1 How to Think About Each Pattern

MethodAdvantagesDisadvantagesBest Use Case
Simple aggregation by dealEasy to implementAnalysis of partial closes and position additions becomes roughInitial check
Aggregation by symbolEasy to find weak symbolsHard to judge when trade count is lowMulti-symbol EAs
Aggregation by time periodEasy to see execution environment biasRequires handling server time and local timeTesting time filters
Aggregation by positionEasy to evaluate trades as groupsProcessing differs between netting and hedging accountsEA improvement
Aggregation by condition tagEasy to separate performance by logicRequires comment or identifier design on the EA sideMulti-signal EAs

5.2 Designing Condition Tags

If you design order comments or magic numbers on the EA side, Python analysis can aggregate results by logic more easily.
For example, if signals such as trend following, pullback buying, and breakout can be identified, weak conditions can be checked separately later.

6. Sample Code

Conclusion:
The basic flow for analyzing MT5 history with Python is to connect to the MT5 terminal, retrieve deal history for a specified period, and aggregate it with a DataFrame.
If the retrieved count is zero or the connection fails, check the cause instead of producing analysis results.

The following code is a minimal validation example.
It is sample code for aggregating history data, not for making a live trading decision.

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

    # Treat deals with a profit column as the analysis target.
    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 Code Review Points

In this code, history retrieval is not executed if the MT5 connection fails.
If history cannot be retrieved, the code separates an empty result from a retrieval failure.

In real analysis, you may need conditions that exclude deposits, withdrawals, balance adjustments, commission-only rows, and similar records.
The required filtering changes depending on the broker and the contents of the account history.

6.2 Processing to Add Before Practical Use

Before using the analysis for practical decisions, add the following processing.

  • Filtering by trade type
  • Filtering out deposits and withdrawals
  • Handling account type differences
  • Checking time zones
  • Saving analysis conditions
  • Outputting CSV files
  • Charting the equity curve
  • Checking the number of trades for each condition

7. Comparison of Design Patterns

Conclusion:
The best design pattern for MT5 Python history analysis depends on whether you want a quick check, EA improvement, or continuous reporting.
A simple structure is enough at first, but repeated validation is easier when retrieval, aggregation, and output are separated.

PatternEase of ImplementationDetail LevelReusabilityNotes
Single-file aggregationHighLow to mediumLowGood for first validation
Separate retrieval and aggregationMediumMediumMediumEasy to extend
Separate analysis modulesMedium to lowHighHighSuitable for repeated EA comparison
Report automationLowHighHighUseful for continuous validation

7.1 Analysis That Beginners Can Start With

For beginners, overall performance, symbol-based performance, and time-period performance are the easiest three areas to start with.
After these three reveal major bias, moving to position-based or logic-based analysis helps keep the implementation effort manageable.

7.2 How to Avoid Overanalysis

If you classify conditions too finely when the number of trades is small, you may mistake random wins or losses for the superiority of the logic.
The more detailed the analysis level becomes, the more you need to check that the number of trades and the period are sufficient.

8. Items to Check in Backtesting

Conclusion:
In backtesting, check not only total profit but also maximum drawdown, number of trades, consecutive losses, period dependency, and parameter dependency.
Backtest results do not perfectly reproduce live execution conditions.

Analyzing backtest history with Python makes it easier to find bias that is hard to see from the MT5 report alone.
Pay special attention to logic that performs well only in a specific period or is weak under spread conditions.

8.1 Metrics You Should Always Check

In backtesting, check the following items.

  • Total profit
  • Maximum drawdown
  • Win rate
  • Risk-reward ratio
  • Number of trades
  • Consecutive losses
  • Spread conditions
  • Period dependency
  • Parameter dependency

8.2 How to View Parameter Dependency

If only one specific parameter value performs extremely well, over-optimization may be involved.
If nearby values cause performance to collapse, repeatability in live trading tends to be low.

In backtest analysis, do not look only at the best value. Check the stability of surrounding parameter values as well.
Logic with low stability is more likely to change results due to spreads or slippage.

9. Items to Check in Forward Testing

Conclusion:
In forward testing, check the gap between backtesting and the actual execution environment.
Spread expansion, execution delay, broker differences, and VPS stability are items that should always be reviewed in history analysis.

Forward test history analysis checks whether logic fitted to past data can still work in an unknown market.
Even if backtest performance is good, trade frequency or drawdown may change greatly in forward testing.

9.1 Metrics to Check in Forward Testing

In forward testing, check the following items.

  • Slippage
  • Behavior when spreads widen
  • Trade frequency
  • Drawdown
  • Gap from backtesting
  • Broker differences
  • Stability in the VPS environment

9.2 Judging the Gap From Backtesting

Profit and loss are not the only important items in forward testing.
If the number of trades, average profit or loss, consecutive losses, or maximum drawdown differs greatly from the backtest, the assumptions behind the logic may no longer hold.

However, it is also risky to make a final judgment from a short forward test period only.
During periods with biased market conditions, temporary good or bad results can occur.

10. Notes for Live Trading

Conclusion:
MT5 Python history analysis is a verification process for reducing live trading risk, not a tool that guarantees profit.
In live trading, you must consider spreads, slippage, execution method, margin, leverage, and broker rules.

Even if history analysis shows good results, the conditions change in live trading.
Execution conditions may also differ between demo accounts and live accounts.

10.1 Spreads and Slippage

For short-term trading EAs, spread widening and execution delay can have a large effect on performance.
In history analysis, if many trades have small profit or loss, check whether the logic is vulnerable to trading costs.

10.2 Lot Size and Leverage

Even with the same logic, larger lot sizes increase profit fluctuation and drawdown.
The higher the leverage, the easier it is for margin level deterioration and forced liquidation risk to increase.

When analyzing lot calculation, check the minimum lot, maximum lot, lot step, margin, tick value, and tick size.
Depending on symbol specifications, profit and loss behavior differs even with the same lot size.

10.3 Connecting Analysis to Pre-Order Checks

If history analysis reveals a problem, also review pre-order checks on the EA side.
In an MQL5 EA, the design should check trade permission, spreads, lot limits, margin, stop levels, freeze levels, and existing positions before sending an order.

For EAs that execute orders, it is practical to handle MqlTradeRequest, MqlTradeResult, and MqlTradeCheckResult separately, and to check order conditions with OrderCheck before OrderSend.

11. Common Design Mistakes

Conclusion:
Common mistakes in MT5 Python history analysis include mishandling the type of trade data, commissions, swaps, account type, and period conditions.
If the analysis assumptions are wrong, you may misjudge which logic should be improved.

In history analysis, having code that runs is not enough.
You must check whether the data being analyzed matches the purpose.

11.1 Including Deposits and Withdrawals in Profit and Loss

If deposits, withdrawals, or balance adjustments are included in trading profit and loss, EA performance will not reflect reality.
When handling history data, separate trading profit and loss from fund transfers.

11.2 Ignoring Commissions and Swaps

If you aggregate only profit, the result may differ from actual net profit and loss.
For symbols where commissions or swaps occur, check the combined value of profit, commission, and swap.

11.3 Judging Conditions With Too Few Trades

When the number of trades is small, random profit or loss has a large effect.
In condition-based analysis, always check the aggregation result and the number of trades together.

11.4 Mishandling Time

For MT5 history times, you need to be aware of how terminal time and server time are handled.
In time-period analysis, clearly state which time basis is used for aggregation.

12. Summary

Conclusion:
MT5 Python trade history analysis lets you break down and review the performance of an EA or trading logic.
For practical use, separate the work into history retrieval, data preparation, metric calculation, condition-based aggregation, and saving validation results.

In trade history analysis, check not only total profit but also win rate, risk-reward ratio, maximum drawdown, consecutive losses, performance by symbol, and performance by time period.
When using analysis for EA improvement, it is important to design magic numbers and order comments so results can be analyzed by logic.

Backtest and forward test results may not match.
In live trading, consider spreads, slippage, broker rules, account type, leverage, and drawdown tolerance, and perform enough validation before making decisions.

FAQ

What is the purpose of MT5 Python trade history analysis?

The purpose of MT5 Python trade history analysis is to break down the performance of an EA or trading logic with numerical data. You can check not only total profit but also win rate, risk-reward ratio, drawdown, symbol-based performance, and time-period performance.

Should Python analyze order history or deal history?

For profit and loss analysis, the basic approach is to focus on deal history because it records executed transactions. Order history is useful for checking requests, while deal history is better for performance aggregation.

Is it enough to aggregate only profit?

Aggregating only profit may differ from actual net profit and loss. If commissions or swaps exist, check profit, commission, and swap together.

When is symbol-based analysis useful?

Symbol-based analysis is useful when you want to separate symbols where an EA performs well from symbols where it performs poorly. However, judgment can be unstable for symbols with a small number of trades.

What should I watch for when analyzing backtest history?

When analyzing backtest history, check total profit, maximum drawdown, number of trades, consecutive losses, and parameter dependency. Backtest results do not guarantee future profit, so forward testing is also required.

What should I check in forward test history?

In forward test history, check slippage, behavior when spreads widen, trade frequency, drawdown, and the gap from backtesting. Broker differences and VPS stability may also affect performance.

What are common mistakes in MT5 Python analysis?

Common mistakes include counting deposits and withdrawals as trading profit or loss, ignoring commissions and swaps, and making conclusions from conditions with too few trades. Fix the analysis assumptions before aggregation.

Can I use an EA in live trading based only on history analysis?

History analysis alone is not enough to decide live EA operation. Before live trading, check forward testing, spread conditions, slippage, lot limits, and drawdown tolerance.