> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stabyl.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Trade Statistics

> Build account volume and execution P&L reports with deterministic comparison periods.

Use `GET /partner/exchange/trade-statistics` to render an account's exchange
report. The API-key owner is always the report subject; there is no `user_id`
parameter. The key must include `trades:view`.

```bash theme={null}
curl "https://api-staging.stabyl.com/v1/partner/exchange/trade-statistics?interval=7d&pair_id=USD%2FNGN" \
  -H "X-Api-Key: $STABYL_API_KEY"
```

## Parameters

| Parameter  | Required | Supported values                                           | Meaning                                                                                   |
| ---------- | -------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `interval` | Yes      | `1d`, `7d`, `30d`, `180d`, `360d`                          | Fixed duration of both the current and comparison periods                                 |
| `pair_id`  | No       | A current pair returned by `GET /partner/exchange/markets` | Restricts the report to one pair; omit it for all recognized current and historical pairs |

`as_of` is the start of the current UTC hour, which is also the end of the last
completed hour. The current period is `[as_of - interval, as_of)`. The previous
period is the immediately preceding equal-duration window. Activity in the open
hour is excluded so the two periods remain comparable.

## Chart Shape

The server selects a fixed chart resolution. Clients do not choose a separate
bucket interval.

| `interval` | `bucket_interval` | Exact bucket count |
| ---------- | ----------------- | ------------------ |
| `1d`       | `1h`              | 24                 |
| `7d`       | `1d`              | 7                  |
| `30d`      | `1d`              | 30                 |
| `180d`     | `30d`             | 6                  |
| `360d`     | `30d`             | 12                 |

Buckets are anchored at `current_period.from`, ordered oldest-first, and always
present. A bucket without activity contains zero-valued strings, so the client
can render the returned array directly without inventing missing points.

## Metric Definitions

`traded_volume` is executed quote notional. A fill counts once even when the
account is both maker and taker.

`net_profit_loss` is net execution cash flow in `quote_currency`:

```text theme={null}
sell quote proceeds
- buy quote spend
- ordinary maker and taker fees
- committed credit-fee charges
+ paid maker rebates
```

It is not inventory-cost-basis realized P\&L and is not mark-to-market portfolio
P\&L. For a self-trade, volume counts once while both participant cash-flow and
fee legs apply. Executions and ordinary fees use fill time. Committed credit-fee
effects and maker rebates use their commitment time.

An unfiltered request returns one summary per quote currency. Values in unlike
currencies are never added together. Every amount is a decimal string in major
units of the summary's `quote_currency`; do not parse monetary values as binary
floating point. Fee conversions are rounded to the nearest quote minor unit per
returned bucket, and both period summaries sum buckets using that same rule.

For both summary metrics, `change_pct` is:

```text theme={null}
(current - previous) / abs(previous) * 100
```

It is `0.0` when both periods are zero and `null` when the previous value is zero
but the current value is not.

## Response Example

```json theme={null}
{
  "status": "success",
  "data": {
    "as_of": "2026-09-03T12:00:00Z",
    "interval": "7d",
    "pair_id": "USD/NGN",
    "current_period": {
      "from": "2026-08-27T12:00:00Z",
      "to": "2026-09-03T12:00:00Z"
    },
    "previous_period": {
      "from": "2026-08-20T12:00:00Z",
      "to": "2026-08-27T12:00:00Z"
    },
    "bucket_interval": "1d",
    "summaries": [
      {
        "quote_currency": "NGN",
        "traded_volume": {
          "current": "525900.00",
          "previous": "508510.64",
          "change_pct": 3.42
        },
        "net_profit_loss": {
          "current": "25900.00",
          "previous": "25043.51",
          "change_pct": 3.42
        },
        "buckets": [
          {
            "from": "2026-08-27T12:00:00Z",
            "to": "2026-08-28T12:00:00Z",
            "traded_volume": "82500.00",
            "net_profit_loss": "1250.00"
          }
        ]
      }
    ]
  }
}
```

The example shortens `buckets` for readability; a real `7d` response always has
seven points.

## Freshness and Errors

Reporting data refreshes shortly after each hour closes. A newly completed hour can
appear after a short delay, and successful responses can be cached for up to 15
seconds. Use the returned `as_of`, `current_period`, and `previous_period` as the
authoritative boundaries instead of deriving them from response receipt time.

| Status | Meaning                                                       |
| ------ | ------------------------------------------------------------- |
| `400`  | Unsupported interval or pair                                  |
| `401`  | Missing or invalid API key                                    |
| `403`  | The key does not include `trades:view`                        |
| `503`  | Reporting data is temporarily unavailable; retry with backoff |
