---
title: "Trade Statistics"
description: "The TradeBuilder tracks your trades and calculates some statistics. You can adjust how it defines a trade and how it matches offsetting order fills."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/trade-statistics
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/trade-statistics.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/22%20Trading%20and%20Orders/12%20Trade%20Statistics
modified: 2026-10-29
index: https://www.quantconnect.com/llms.txt
---

# Trade Statistics

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Trading and Orders > Trade Statistics

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

The `TradeBuilder` tracks the trades of your algorithm and calculates some statistics. Some of these statistics are a function of the [risk free interest rate](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/risk-free-interest-rate/key-concepts.md) and the [number of trading days per year](https://www.quantconnect.com/docs/v2/writing-algorithms/initialization.md#10-Set-Algorithm-Settings). You can adjust how the `TradeBuilder` defines a trade and how it matches offsetting order fills.

## Set Trade Builder

To set the `TradeBuilder`, in the `initialize` method, call the `set_trade_builder` method.

```python
self.set_trade_builder(TradeBuilder(grouping_method, matching_method))
```

The following table describes the arguments the `TradeBuilder` constructor accepts:

| Argument | Data Type | Description | Default Value |
| --- | --- | --- | --- |
| `grouping_method` | `FillGroupingMethod` | The method used to group order fills into trades |  |
| `matching_method` | `FillMatchingMethod` | The method used to match offsetting order fills |  |

The `FillGroupingMethod` enumeration has the following members:

*Members of `QuantConnect.Statistics.FillGroupingMethod` (JSON): https://www.quantconnect.com/services/inspector?type=T:QuantConnect.Statistics.FillGroupingMethod&language=python*

The `FillMatchingMethod` enumeration has the following members:

*Members of `QuantConnect.Statistics.FillMatchingMethod` (JSON): https://www.quantconnect.com/services/inspector?type=T:QuantConnect.Statistics.FillMatchingMethod&language=python*

## Default Behavior

The default `TradeBuilder` uses `FillGroupingMethod.FILL_TO_FILL` and `FillMatchingMethod.FIFO`.

## Check Open Positions

To check if you have a position open for a security as defined by the `FillGroupingMethod`, call the `has_open_position` method.

```python
# Check if the trade builder has recorded any active trades (unclosed positions)
# for a security.
has_open_position = self.trade_builder.has_open_position(self._symbol)
```

## Get Closed Trades

To get your closed trades, use the `closed_trades` property.

```python
trades = self.trade_builder.closed_trades
```

This property returns a list of `Trade` objects, which have the following attributes:

*Members of `QuantConnect.Statistics.Trade` (JSON): https://www.quantconnect.com/services/inspector?type=T:QuantConnect.Statistics.Trade&language=python*

## Examples

The following examples demonstrate some common practices for making use of trade statistics.

### Example 1: Kelly Criterion Sizing Using Previous Trades

The following algorithm uses the previous trades to update the win probability and expected return of each trade of the EMA cross strategy of SPY, by the concept of Bayes Theorem. The updated figures are used for position sizing through Kelly Criterion.

```python
class TradeStatisticsAlgorithm(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 9, 12)
        self.set_end_date(2024, 10, 1)
        self.set_cash(1000000)

        # Request SPY data to trade.
        self.spy = self.add_equity("SPY").symbol
        # Create an EMA indicator to generate trade signals.
        self._ema = self.ema(self.spy, 20, Resolution.DAILY)
        # Warm-up indicator for immediate readiness.
        self.warm_up_indicator(self.spy, self._ema, Resolution.DAILY)

        # Set up a trade builder to track the trade statistics; we are interested in open-to-close round trade.
        self.set_trade_builder(TradeBuilder(FillGroupingMethod.FLAT_TO_FLAT, FillMatchingMethod.FIFO))

    def on_data(self, slice: Slice) -> None:
        bar = slice.bars.get(self.spy)
        if not bar:
            return
        # Trend-following strategy using price and EMA.
        # If the price is above EMA, SPY is in an uptrend, and we buy it.
        sign = 0
        if bar.close > self._ema.current.value and not self.portfolio[self.spy].is_long:
            sign = 1
        elif bar.close < self._ema.current.value and not self.portfolio[self.spy].is_short:
            sign = -1
        else:
            return

        size = 1
        trades = self.trade_builder.closed_trades

        if len(trades) > 4:
            # Use the trade builder to obtain the win rate and % return of the last five trades to calculate position size.
            last_five_trades = sorted(trades, key=lambda x: x.exit_time)[-5:]
            prob_win = len([x for x in last_five_trades if x.is_win]) / 5
            win_size = np.mean([x.profit_loss / x.entry_price for x in last_five_trades])
            # Use the Kelly Criterion to calculate the order size.
            size = max(0, prob_win - (1 - prob_win) / win_size)

        self.set_holdings(self.spy, size * sign)
```
