# Full account report

> Everything about one account in a single call — identity, curve, statement, indicators, every deal and the evaluation terms it is judged against.

Source: https://www.propexecutor.com/docs/account-report
Whole reference in one file: https://www.propexecutor.com/doc.md

Everything the platform knows about one trading account, in a single response: who it is, what it is worth, its month-by-month statement, its risk and streak indicators, its long/short split, its results per instrument and per weekday, **every deal it has ever made**, and the evaluation terms it is being judged against.

`GET /v1/accounts/{account}/report` · **Available** · scope `accounts:read`

<!-- curl -->
```bash
curl "https://api.propexecutor.com/v1/accounts/10000042/report" \
  -H "Authorization: Bearer $PFX_KEY"
```

> **Which one should you call?**
> This endpoint and [analytics](https://www.propexecutor.com/docs/analytics) answer the same question in two different shapes. Call **report** when you are rendering a whole account page and want one request with nothing to stitch together — it includes the deal list and the rule terms, which analytics leaves to separate calls.
> 
> Call **analytics** when you are driving charts and polling: it is the lighter of the two, it carries extra series (money and deal counts split into winners and losers) and it never reads the full ledger row by row. One thing to watch if you call both: its weekday chart is Sunday-first, while this endpoint’s `profitDaily` is Monday-first. Each matches the contract its own clients bind to.

## This is the slow one

The report reads the account’s entire trade ledger, aggregates all of it, and fetches the equity curve — deliberately, because a partial report is not a report. A profit factor computed over one page of trades is not a profit factor.

So: call it on page load, not on a timer, and not on every price tick. There is no pagination anywhere in the response. What bounds it instead is `tradeHistory.deals`, which is capped at **5,000** entries — `totalDeals` is always the true count, so you can tell when you are seeing a truncated list, and every aggregate in the object is still computed over the whole ledger rather than the capped slice.

## Range

| Field | Type | Description |
| --- | --- | --- |
| `from` | timestamp | Start of the charted window, RFC 3339. Defaults to **the account’s creation** — this object is the account’s history, and a report that silently covered yesterday would look like an account that had barely traded. Note this differs from [analytics](https://www.propexecutor.com/docs/analytics), which defaults to the last 24 hours. Clamped forward to the account’s creation. |
| `to` | timestamp | End of the charted window. Defaults to now, and is clamped to now. |

The range affects `balance.chart`, `growth.chart` and the three `longShort` series only. Every total, indicator, table and deal covers the account’s whole life, so nothing on your statement changes because somebody looked at a different chart range.

## Units, before anything else

The same measurement appears in two units in two places. This is the contract’s shape, not an accident, and it is the one thing worth reading before you bind a field to a label:

| Measurement | As a fraction | As a percentage | In currency |
| --- | --- | --- | --- |
| Growth on the starting balance | `growth.growth`, `summary.gain`, `evaluation.metrics.profit_percent` | — | `balance.table.total` |
| Drawdown from the all-time peak | `growth.drawdown` | `summaryIndicators.drawdown` | — |
| Share of closed trades that won | — | `tradeHistory.summary.winRate` | — |
| The rule limits | `evaluation.rulesApplied.*` | — | — |

> **summary.gain is a fraction, not money**
> `summary.gain` is growth on the starting balance as a **fraction** (`-0.0546` means down 5.46%) — the same number as `growth.growth` and `evaluation.metrics.profit_percent`. The money form is `balance.table.total`, which equals `tradeHistory.summary.totalProfit` and `profitTotal.profit + profitTotal.loss`.
> 
> `summary.activity` is a fraction too: the share of the account’s life that has had trading on it, capped at `1`. The deal count is `tradeHistory.totalDeals`.

## Response

<!-- 200 OK (abridged) -->
```json
{
  "account": 10000042,
  "name": "$1K One Step",
  "broker": "Northwind Funding",
  "currency": "USD",

  "balance": {
    "balance": 945.19,
    "equity": 945.19,
    "period": 3600,
    "chart": [
      { "x": 1771415040, "y": [1000, 1000] },
      { "x": 1788795349, "y": [945.19, 945.19] }
    ],
    "table": {
      "years": [{ "year": 2026, "months": { "1": 15.8, "2": -8.74 }, "yearly": 7.06 }],
      "total": 7.06
    }
  },

  "_id": "9f1c…",
  "type": "demo",
  "digits": 2,
  "credentialKey": "1K_ONE_STEP",
  "status": "ACTIVE",
  "isBreached": false,
  "breachReasons": [],
  "statusChangedAt": null,
  "updatedAt": "2026-09-29T08:41:02Z",
  "__v": 1,

  "summary": {
    "gain": -0.054576,
    "activity": 0.36,
    "deposit": [1000, 1],
    "withdrawal": [0, 0],
    "dividend": 0, "correction": 0, "credit": 0
  },

  "summaryIndicators": {
    "sharp_ratio": -0.8,
    "profit_factor": 0.72,
    "recovery_factor": -0.5,
    "drawdown": 9.36,
    "deposit_load": 0.0797,
    "trades_per_week": 3.2,
    "hold_time": 7047
  },

  "risksIndicators": {
    "profit": [21.94, -12.36],
    "max_consecutive_trades": [2, 16],
    "max_consecutive_profit": [37.61, -74.44]
  },

  "growth": {
    "growth": -0.054576,
    "drawdown": 0.093599,
    "period": 3600,
    "chart": [
      [{ "x": 1771415040, "y": [0.01] }],
      [{ "x": 1771415040, "y": [0.002] }]
    ],
    "table": { "years": [], "total": -0.054576 }
  },

  "drawdown": {
    "drawdown": 0.093599, "deposit_load": 0.0797, "period": 3600,
    "chart": [[…fraction], […currency], [0…], [0…]]
  },
  "dividend": { "dividend": 0, "correction": 0, "credit": 0, "period": 3600, "chart": [], "table": {} },

  "profitMoney": { "period": 3600, "profit": [], "loss": [], "table": {} },
  "profitDeals": { "period": 3600, "profit": [], "loss": [], "table": {} },
  "profitType": {
    "robot":   { "x": 0, "y": [0, 0] },
    "manual":  { "x": 0, "y": [50, -104.56] },
    "signals": { "x": 0, "y": [0, 0] }
  },

  "longShortDaily": { "chart": [{ "x": 0, "y": [13, 8] }] },

  "risksMfeMaeMoney":   { "max_avg_profit": 0, "max_avg_mfe": 0, "min_avg_loss": 0, "min_avg_mae": 0, "period": 3600, "chart": [[]] },
  "risksMfeMaePercent": { "max_avg_profit_ratio": 0, "max_avg_mfe_ratio": 0, "min_avg_loss_ratio": 0, "min_avg_mae_ratio": 0, "period": 3600, "chart": [[]] },

  "symbolIndicators": {
    "profit_factor": [["US500", 1.51]], "netto_profit": [["US500", 10.16]], "fees": [["US500", 0]]
  },
  "symbolTypes":  { "type": [["Index", 89], ["Currency", 4]] },
  "symbolsTotal": { "total": [["US500", 10.16, 9]] },
  "tradeTypeTotal": { "robots": 0, "manual": 93, "signals": 0 },

  "longShort": {
    "period": 3600,
    "long":  [{ "x": 1771113600, "y": [2] }],
    "short": [{ "x": 1771113600, "y": [1] }],
    "all":   [{ "x": 1771113600, "y": [3] }]
  },

  "longShortTotal": { "long": 63, "short": 30 },

  "longShortIndicators": {
    "netto_pl":               [-25.15, -29.41],
    "average_pl":             [-0.399206, -0.980333],
    "average_pl_percent":     [-0.000399, -0.00098],
    "commissions":            [0, 0],
    "average_profit":         [2.32127, 2.529333],
    "average_profit_percent": [0.002321, 0.002529],
    "trades":                 [63, 30],
    "win_trades":             [14, 12]
  },

  "profitDaily": {
    "chart": [
      { "x": 0, "y": [38.06, -92.02] },
      { "x": 1, "y": [16.94, -61.25] },
      { "x": 2, "y": [61.21, -10.84] },
      { "x": 3, "y": [51.9, -49.63] },
      { "x": 4, "y": [54.01, -62.94] },
      { "x": 5, "y": [0, 0] },
      { "x": 6, "y": [0, 0] }
    ]
  },

  "symbolDeals": {
    "period": 604800,
    "chart": [
      ["US30",  [{ "x": 1771113600, "y": [2] }, { "x": 1771718400, "y": [7] }]],
      ["US500", [{ "x": 1771113600, "y": [3] }, { "x": 1771718400, "y": [0] }]]
    ]
  },

  "symbolMoney": {
    "period": 604800,
    "chart": [
      ["US30",  [{ "x": 1771113600, "y": [11.52] }, { "x": 1771718400, "y": [6.92] }]],
      ["US500", [{ "x": 1771113600, "y": [14.7] }, { "x": 1771718400, "y": [18.98] }]]
    ]
  },

  "tradeHistory": {
    "fromDate": "2026-02-18T11:45:20Z",
    "toDate": "2026-09-29T08:41:02Z",
    "fetchedAt": "2026-09-29T08:41:02Z",
    "dayOffsetHours": 0,
    "totalDeals": 93,
    "deals": [{
      "ticket": 1000123, "order": 1000123, "position_id": 1000123,
      "time": 1771113600, "time_msc": 1771113600000, "time_iso": "2026-02-15T00:00:00Z",
      "type": 0, "type_name": "BUY",
      "entry": 1, "entry_name": "OUT",
      "magic": 0, "reason": 0,
      "volume": 0.16, "price": 52049,
      "commission": 0, "swap": 0, "fee": 0,
      "profit": -10.5, "net_profit": -10.5,
      "is_closing": true, "symbol": "US30",
      "comment": "", "external_id": ""
    }],
    "trades": [{
      "positionId": 1000123, "symbol": "US30", "side": "BUY", "volume": 0.16,
      "openTime": 1771113600, "openTimeIso": "2026-02-15T00:00:00Z", "openPrice": 52049,
      "closeTime": 1771117200, "closeTimeIso": "2026-02-15T01:00:00Z", "closePrice": 51983,
      "durationSeconds": 3600,
      "profit": -10.5, "commission": 0, "swap": 0, "fee": 0, "netProfit": -10.5,
      "entries": [{
        "time": 1771113600, "timeIso": "2026-02-15T00:00:00Z",
        "type_name": "BUY", "entry": 0, "entry_name": "IN",
        "price": 52049, "volume": 0.16, "cumulativeVolume": 0.16
      }],
      "entryCount": 1, "firstLegVolume": 0.16, "maxLegVolume": 0.16,
      "volumeMultiple": 1, "isAveraging": false, "isMartingale": false
    }],
    "dailyNet": {
      "2026-02-15": { "netProfit": -10.5, "grossProfit": -10.5, "closedDeals": 1 }
    },
    "summary": {
      "totalProfit": -54.56,
      "netProfit": -54.56,
      "totalCommission": 0, "totalSwap": 0, "totalFee": 0,
      "winningTrades": 26,
      "losingTrades": 67,
      "totalClosedTrades": 93,
      "winRate": 27.96,
      "symbolsTraded": ["US30", "US500"],
      "tradingDays": 31,
      "averagingPositions": 0, "martingalePositions": 0,
      "averagingDetected": false, "martingaleDetected": false
    }
  },

  "evaluation": {
    "program": "1_STEP",
    "evaluatedAt": "2026-09-29T08:41:02Z",
    "credentialKey": "1K_ONE_STEP",
    "rulesApplied": {
      "profit_target": 0.1,
      "max_loss_limit": 0.06,
      "daily_loss_limit": 0.03,
      "leverage": "1:50",
      "min_trading_days": 3,
      "min_profitable_days": null,
      "max_inactivity_days": 14
    },
    "status": "ACTIVE",
    "isBreached": false,
    "breaches": [],
    "breachReasons": [],
    "metrics": {
      "initial_balance": 1000,
      "current_balance": 945.19,
      "current_equity": 945.19,
      "worst_balance_or_equity": 945.19,
      "profit_percent": -0.0548,
      "profit_target_hit": false,
      "profitable_days": 11,
      "consecutive_inactive_days": 4,
      "daily_dd_total_days_checked": 31,
      "daily_dd_peak_equity": 1000,
      "daily_dd_threshold": 970,
      "daily_dd_current_drawdown_pct": 0.05481,
      "daily_dd_breached": true,
      "daily_dd_breach_date": null,
      "max_open_lots_limits": {},
      "freedom_lot_peaks": {},
      "freedom_lot_would_breach": []
    }
  },

  "profitTotal": {
    "profit": 50,
    "profit_gross": 50,
    "profit_dividend": 0,
    "profit_swap": 0,
    "loss": -104.56,
    "loss_gross": -104.56,
    "loss_commission": 0
  }
}
```

## Identity

| Field | Type | Description |
| --- | --- | --- |
| `account` | integer | The 8-digit account number — the same one the trader types into the terminal. |
| `name` | string | The account type's name — the challenge this account is running. |
| `broker` | string | **Your organization’s name.** There is no broker: fills are simulated against live prices and never routed to a venue. The field keeps the contract’s name and carries the firm whose executor the account trades on. |
| `currency` | string | Always `"USD"`. Every account on the platform is denominated in USD today. |

## balance

| Field | Type | Description |
| --- | --- | --- |
| `balance` | number | Closed-trade equity: the starting balance plus every realized P&L. |
| `equity` | number | Balance plus the floating P&L of everything still open. This is the number rules are judged on. |
| `chart` | point[] | `x` a Unix second, `y` the pair `[balance, equity]` — balance first. Bucket width is chosen from the span you asked for. Empty when the equity curve is not available on your deployment; see [equity curve](https://www.propexecutor.com/docs/equity-curve). |
| `table` | object | Realized P&L by calendar month and year. Months are keyed by month number as a **string** (`"1"` … `"12"`) and a month with no trading is **absent rather than zero**, so iterate the keys you get rather than 1–12. Computed from the ledger, never from the chart. |

## summaryIndicators

| Field | Type | Description |
| --- | --- | --- |
| `sharp_ratio` | number | Annualized Sharpe ratio of daily realized returns against the starting balance, on 252 trading days. `0` when there is not enough history to measure a deviation — two days of trading has no meaningful one, and a number derived from it would be worse than none. (Spelled without the ‘e’ because the contract spells it that way.) |
| `profit_factor` | number | Gross profit over gross loss. `0` for an account with no losing trade — it has no ratio, and `Infinity` is not JSON a client can parse. |
| `recovery_factor` | number | Net profit over the worst drawdown, in currency. |
| `drawdown` | number | How far below its all-time peak equity the account is **now**, as a **percentage**. The same measurement max-loss rules are enforced against. |
| `trades_per_week` | number | The lifetime average, not a recent rate. |

## risksIndicators

The streak view, read over **closed** deals in the order they settled. Every field is a two-element `[best, worst]` pair: index `0` describes winning, index `1` losing, and the losing figures are negative.

| Field | Type | Description |
| --- | --- | --- |
| `profit` | [number, number] | The largest single winning deal, and the largest single losing deal. |
| `max_consecutive_trades` | [integer, integer] | The length of the longest unbroken run of winners, and of losers. |
| `max_consecutive_profit` | [number, number] | What those two runs made and lost. The money always belongs to a run of the length above — where two runs tie on length, the more extreme one is reported. |

## profitDaily

Realized P&L by **day of week**: seven points, `x` = `0` for **Monday** through `6` for Sunday, `y` = `[profit, loss]` for that weekday across the whole ledger. Loss is negative, both are `0` for a day never traded, and every day is present so you can index the array directly. A deal counts on the day it **settled**, not the day it opened.

## longShort

Three parallel series counting positions **opened** per bucket — the question a long/short chart answers is when exposure was taken on, not when it was closed. Every bucket in the range appears in all three series at the same `x`, so you can index them against each other without aligning timestamps, and `all` is always `long + short` for its bucket. `longShortDaily` is the same split by weekday, Monday first, as `[long, short]`.

## longShortTotal and longShortIndicators

The same split as scalars. `longShortTotal` is the deal count per direction — the totals of the series above, carried so you do not have to sum a chart to label a donut. `longShortIndicators` is how each direction performed, and **every field in it is a two-element array indexed `[long, short]`**.

Counts include open positions, money does not: exposure was taken long the moment the position opened, but it has realized nothing until it closes. That is the same split `tradeHistory.summary` makes between `totalDeals` and `totalClosedTrades`.

| Field | Type | Description |
| --- | --- | --- |
| `netto_pl` | [number, number] | Net realized P&L per direction. The two sum to summary.gain. |
| `average_pl` | [number, number] | `netto_pl` over the direction’s **total** deal count, open positions included — not over its closed count. The contract’s own definition, and the reason it is not `netto_pl / win_trades`. |
| `average_pl_percent` | [number, number] | average_pl as a FRACTION of the starting balance. |
| `commissions` | [number, number] | Always `[0, 0]` — no commission is modelled, for the same reason `profitTotal`’s gross and net pairs are equal. An explicit zero, not an omission. |
| `average_profit` | [number, number] | The average WINNING deal per direction — gross profit over win_trades, so losers do not drag it down. 0 for a direction that has never won. |
| `average_profit_percent` | [number, number] | average_profit as a FRACTION of the starting balance. |
| `trades` | [integer, integer] | Every deal per direction, open ones included. The same two numbers as longShortTotal. |
| `win_trades` | [integer, integer] | Closed deals that settled at or above zero, per direction. Note that `trades` counts open positions too, so it is **not** the denominator for a per-side win rate. |

## symbolDeals and symbolMoney

One series per instrument over the same buckets as `balance.chart`. Both objects carry `period` (the bucket width in seconds) and `chart`, a list of **positional** `[symbol, points]` pairs — a two-element array, not an object — sorted alphabetically by instrument. Every symbol gets every bucket in the range, leading zeros included, so the series are index-aligned with each other and with `longShort`.

| Field | Type | Description |
| --- | --- | --- |
| `symbolDeals` | series | Positions **opened** per bucket, so a symbol’s series **sums** to its deal count. |
| `symbolMoney` | series | **Running** realized P&L per bucket, banked when each position closed — so a symbol’s **last point** is its contribution to `summary.gain`, and the last points of every symbol add up to it. |

## tradeHistory

| Field | Type | Description |
| --- | --- | --- |
| `totalDeals` | integer | Every trade on the account, open and closed. Always the true count, even when the list below is capped. |
| `deals` | deal[] | Newest first, capped at 5,000. Truncation drops the oldest. |
| `deals[].ticket` | integer | The deal's display identifier, unique across the platform. |
| `deals[].time` | integer | When the position was OPENED, as a Unix second. |
| `deals[].type_name` | string | `"BUY"` or `"SELL"`. |
| `deals[].volume` | number | Position size in lots. |
| `deals[].price` | number | The entry price. A closed deal's exit price is not in this shape — read it from the trades endpoint if you need it. |
| `deals[].profit` | number | Realized P&L, and `0` while the position is still open. An open position’s floating P&L is a price-dependent number that would make two calls a second apart disagree; `totalClosedTrades` tells you how many of the deals are settled. |
| `deals[].symbol` | string | The instrument, in the platform's canonical naming. |
| `summary.winRate` | number | Percentage of CLOSED trades that won. Open positions do not dilute it. |
| `summary.netProfit` | number | Identical to `totalProfit`: the simulator charges no commission and no swap, so there is nothing to subtract. Both are reported so a client reading either gets a correct number. |
| `summary.symbolsTraded` | string[] | Every instrument the account has ever traded, sorted. |

## evaluation

The terms this account is judged against — read from the rule set version that was **frozen onto it at creation**, never from its rule set’s current version. Editing a rule set never changes the terms of accounts already running under it, and this object reflects that.

| Field | Type | Description |
| --- | --- | --- |
| `program` | string | Always `"1_STEP"`. An account points at exactly one rule set version for its whole life — there is no phase 1 → phase 2 progression and no funded stage on this platform, so every account genuinely is a single step. Reported as a constant so you can switch on it. |
| `rulesApplied.profit_target` | number \| null | Target as a **fraction** of the starting balance (`0.1` = +10%). `null` when the rule set has no profit target, which means the account can never pass — **not** `0`, which would say it already has. |
| `rulesApplied.max_loss_limit` | number \| null | Maximum drawdown as a fraction. null when the rule set does not include one. |
| `rulesApplied.daily_loss_limit` | number \| null | Daily drawdown as a fraction. null when the rule set does not include one. |
| `rulesApplied.leverage` | string | The FX ratio, as `"1:50"`. Leverage is set **per asset class** on this platform, and FX is reported as the single representative value an account-level field can carry. See [rule sets](https://www.propexecutor.com/docs/rule-sets) for the per-class map. |
| `status` | string | `ACTIVE`, `BREACHED`, `PASSED` or `CLOSED`, uppercased. |
| `isBreached` | boolean | True exactly when status is BREACHED. |
| `breaches` | object[] | One entry per breached rule: `{ rule, severity, observed, threshold, message }`, plus `peak_equity` and `breach_date` on a drawdown breach. `observed` and `threshold` are null for a rule with no number to report. The rule that ended the account comes first; any other limit the account is also past follows it. Empty for a breach an administrator recorded by hand. See the note below. |
| `breachReasons` | string[] | The rule codes that ended the account — `DAILY_DRAWDOWN`, `MAX_LOSS_LIMIT`, `INACTIVITY`, or a typed rule's key uppercased (e.g. `MAX_LOT_PER_ORDER`). A breach an administrator recorded by hand carries its own text instead. |
| `metrics.profitable_days` | integer | Distinct UTC days whose realized P&L summed positive. Not the same as a rule set’s `min_trading_days`, which counts days traded at all. |
| `metrics.profit_percent` | number | Growth as a fraction, measured on EQUITY so an open position counts toward it. |

> **breaches is not a history**
> The first entry is the rule that **ended** the account, recorded in the same transaction as the status change. Any further entries are other breach rules of the account's frozen rule set that its equity is also past right now. It is not a log you can page through, and a second breach cannot happen to an account that is already breached.
> 
> Rules that **flag** rather than breach are a different thing entirely: they accumulate, trading continues, and they are not in this array. They are reported separately — see [rule sets](https://www.propexecutor.com/docs/rule-sets).

## profitTotal

Gross profit and gross loss over closed trades. `loss` and `loss_gross` are **negative**. The net and gross pairs are identical because no trading costs are modelled — adding commission or swap would change the simulator’s P&L and every drawdown that follows from it, so it is a product decision rather than a field we can fill in quietly.

## Blocks that are structurally zero

The report serves the whole of its contract, including the parts a broker-backed account would fill and a simulator cannot. Those are **explicit zeros and empty collections, never missing keys**, so a client binding to them renders an empty panel instead of `undefined`:

- `dividend`, `summary.withdrawal`, `summary.dividend/correction/credit` — a challenge account is funded once and never paid into or out of again.
- `profitTotal.profit_swap`, `profitTotal.loss_commission`, `longShortIndicators.commissions`, `symbolIndicators.fees` and the cost totals in `tradeHistory.summary` — no commission or swap is modelled.
- `profitType.robot` / `signals` and `tradeTypeTotal` — every fill comes through one order path, so everything is manual.
- `risksMfeMaeMoney` and `risksMfeMaePercent` — measuring how far a position ran in favour or against needs every tick it lived through recorded against it, and only the open and close prices are stored. Reporting anything else would be a guess dressed as a measurement.
- `evaluation.metrics.freedom_lot_peaks` and `freedom_lot_would_breach` — peak *concurrent* lots per asset class needs an exposure history nothing records. `max_open_lots_limits` carries at most the key `ALL`, because the lot ceiling here is account-wide rather than per class.
- `tradeHistory.summary.averagingDetected` / `martingaleDetected` and their counts — a position cannot be added to on this platform, so there is no scaling-in pattern to find.

## What this object does not carry

- **A deposit history.** A challenge account’s only deposit is the starting balance it was provisioned with, so `summary.deposit` is the contract’s `[amount, count]` pair with a count of `1` for the account’s whole life — the same number as `metrics.initial_balance`.
- **Commission, swap, dividends and corrections.** Not modelled — see `profitTotal` above.
- **An order source.** There is no robot / signal / manual distinction; every fill comes through the same path.
- **The trader’s identity.** A report is about an account. The trader record holding it is on [traders](https://www.propexecutor.com/docs/traders), and an API key never reaches a trader login.

### One thing to know about history

The **balance** line in `balance.chart` is exact for the account’s whole life — it is reconstructed from the ledger. The **equity** line needs the floating value of open positions at each moment, which is only recorded from the day the equity curve shipped on your deployment. For any earlier period the two lines are equal and intraday dips from open losing positions are not visible.
