Account PnL
Returns the user's daily and cumulative profit-and-loss statistics within a date range. Used by the account dashboard's Daily and Cumulative PnL card and overview metrics.
GET /account/pnl
Authorization: Bearer <token>
Query Parameters
| Name | Type | Required | Description |
|---|---|---|---|
symbol | string | No | Filter to a single market (e.g. BTC-USDT). When omitted, all markets are aggregated. |
start_date | string | No | Inclusive lower bound, YYYY-MM-DD (UTC). |
end_date | string | No | Inclusive upper bound, YYYY-MM-DD (UTC). |
days | int64 | No | Look-back window in days, used whenever start_date and end_date are not both provided. Supplying only one of the two dates causes it to be ignored and the days fallback to apply. Default 30. |
Resolution order:
- If both
start_dateandend_dateare set, that explicit range is used. - Otherwise (including when only one of the two is set — the lone date is ignored), the server uses
[today − days, today]in UTC. Today is alwaysUtc::now().date_naive().
Response
{
"daily": [
{
"date": "2026-05-10",
"realized_pnl": "125.30",
"volume": "10000.00",
"trade_count": 12,
"fees": "5.00"
}
],
"cumulative": {
"total_realized_pnl": "320.50",
"total_unrealized_pnl": "-12.40",
"total_pnl": "308.10",
"total_volume": "85000.00",
"total_trades": 87,
"total_fees": "42.50",
"win_rate": "62.50",
"avg_profit_per_trade": "3.68"
},
"symbol": null
}
When the window contains a day with no activity, the day still appears in daily with all numeric fields equal to 0 and trade_count equal to 0. The series is contiguous from start_date to end_date in UTC.
When the user has no trades in the window at all, daily is a contiguous series of zero rows and cumulative is all zeros.
Response Fields
Top level
| Field | Type | Description |
|---|---|---|
daily | DailyPnl[] | One row per UTC day, contiguous between start_date and end_date. |
cumulative | CumulativePnl | Aggregate stats over the same window. |
symbol | string | null | Echo of the symbol query parameter. |
DailyPnl
| Field | Type | Description |
|---|---|---|
date | string | UTC date in YYYY-MM-DD. |
realized_pnl | Decimal | Sum of realized_pnl_events.realized_pnl for the day (USDT). |
volume | Decimal | Notional traded that day, computed as SUM(price × amount) over trades where the user is maker or taker (USD). |
trade_count | int64 | Number of trades rows where the user is maker or taker. |
fees | Decimal | The user's portion of fees on trades (maker fee if user is maker, taker fee otherwise), summed for the day (USDT). |
CumulativePnl
All fields cover the same window [start_date, end_date] (inclusive, UTC).
| Field | Type | Description |
|---|---|---|
total_realized_pnl | Decimal | Sum of realized_pnl_events.realized_pnl over the window. |
total_unrealized_pnl | Decimal | Floating PnL of all currently open positions, computed at request time using the latest mark price for each symbol. Independent of the date window. |
total_pnl | Decimal | total_realized_pnl + total_unrealized_pnl. |
total_volume | Decimal | SUM(price × amount) over trades in the window. |
total_trades | int64 | Count of trades rows in the window where the user is maker or taker. |
total_fees | Decimal | Sum of the user's portion of fees on trades in the window. |
win_rate | Decimal | count(realized_pnl_events with realized_pnl > 0) / count(realized_pnl_events) × 100 over the window. Returned as a percentage (e.g. 62.50 means 62.5%). 0 when there are no closes in the window. |
avg_profit_per_trade | Decimal | total_realized_pnl / total_trades. 0 when total_trades is 0. |
Errors
| HTTP | code | When |
|---|---|---|
| 400 | INVALID_START_DATE | start_date is not parseable as YYYY-MM-DD. |
| 400 | INVALID_END_DATE | end_date is not parseable as YYYY-MM-DD. |
| 500 | DAILY_TRADE_STATS_FAILED | DB error aggregating daily trade rows. |
| 500 | DAILY_PNL_FETCH_FAILED | DB error aggregating daily realized PnL. |
| 500 | STATS_FETCH_FAILED | DB error computing cumulative trade stats. |
| 500 | WIN_RATE_FETCH_FAILED | DB error computing win rate. |
Error body:
{ "error": "...", "code": "..." }
Notes
- All money is reported as a decimal string. Callers should parse with arbitrary-precision arithmetic, not float.
- Day boundaries are UTC. There is no
tzparameter; callers that need a local-time view should aggregatedailyrows on the client. total_unrealized_pnldoes not depend onstart_date/end_date— it always reflects the user's currently open positions and the latest mark prices.