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

# Account analytics and stage eligibility

> Read firm-issued account performance and safely check whether a challenge can advance.

**Sandbox rollout:** use `https://sandbox.trdrs.co` for this workflow. Production availability
depends on the production engine release.

Use your **server-side partner key**. These endpoints reach only paper accounts your firm issued
through the account-creation API. A trader session, tenant key, or another firm's key cannot read
those accounts. A missing account and an account owned by another firm both return `404`.
Read access does not require a payment in sandbox. No payment processing belongs in this workflow.

## Read performance

```bash theme={null}
export TRDRS_API_BASE_URL="https://sandbox.trdrs.co"

curl --get "$TRDRS_API_BASE_URL/api/partner/accounts/analytics" \
  -H "Authorization: Bearer $TRDRS_PARTNER_KEY" \
  --data-urlencode "account=EVAL-7C21A9" \
  --data-urlencode "timeZone=America/Chicago" \
  --data-urlencode "rolloverHour=17"
```

The response is one consistent database snapshot, identified by `asOf`, `snapshotId` and
`cycle.id`. Reads do not create orders, move balances, reset accounts or advance stages.
Amounts use the account's currency, quantities may be fractional, and timestamps are UTC ISO 8601.

| Field                          | Meaning                                                                                                                                                                                                                                                |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `pnl.grossRealized`            | Realized profit from the current cycle's fills using the paper venue's average-cost accounting.                                                                                                                                                        |
| `pnl.fees`                     | All recorded fill fees, including fees paid to open positions that remain open.                                                                                                                                                                        |
| `pnl.netTrading`               | Gross realized profit minus all fill fees. This is the stage target's basis.                                                                                                                                                                           |
| `pnl.balanceAdjustments`       | Signed non-trading credits, debits, adjustments, top-ups and payouts since the current cycle began. Provision/reset amounts are excluded.                                                                                                              |
| `pnl.balance`                  | Actual account cash balance, including those adjustments.                                                                                                                                                                                              |
| `pnl.unrealized`, `pnl.equity` | Current valuation, or `null` when an open position lacks a recent mark. Flat-account equity equals balance.                                                                                                                                            |
| `closedTrades`                 | Each fill's closing portion, with stable fill ID, average entry, exit, quantity, direction, opening/closing time, gross profit and allocated fees. Partial closes are separate rows; a reversing fill closes the old position and opens its remainder. |
| `openPositions`                | Signed quantities, average prices and available unrealized profit.                                                                                                                                                                                     |
| `openOrders`                   | All working orders, including protective stops and targets. An empty position list alone does not make the account safe to advance.                                                                                                                    |
| `risk.breaches`                | Recorded loss/evaluation breaches in the current cycle, plus a current disqualifying lock or failed enrollment. Timed unlocks do not erase recorded breaches.                                                                                          |

**Example:** $3,010 of realized profit, $10 of fees and a $500 promotional credit produce `netTrading: 3000` and `balanceAdjustments: 500`. The credit cannot satisfy a $3,500 trading target.
Closed-trade net profit may differ from account net trading profit while positions are open because
entry fees on those open positions have already been charged to the account.

## Trading days and session rules

A qualifying day is a distinct session containing **at least one executed fill**. Opening fills,
closing fills, and losing trades count. Placing or cancelling an unfilled order, signing in,
receiving a credit, or merely holding overnight does not count. Weekends are not excluded: a
crypto fill on Saturday counts if it belongs to a distinct session.

Defaults are `timeZone=America/Chicago` and `rolloverHour=17`. At 17:00 local time the next
session starts; its label is the next calendar date. The timezone observes daylight-saving changes.
For UTC calendar days, explicitly send `timeZone=UTC&rolloverHour=0`.

Save these rules with your challenge stage and send the same rules on every check. They control
analytics grouping; they **do not change** the engine's existing risk-monitor session boundaries.
Minimum profitable days, minimum volume per day and exchange-holiday exclusions are not evaluated.
If your challenge requires them, your backend must also check those rules before advancing.

## Equity history and completeness

`equityHistory.points` contains the latest **up to 1,000 forward samples**, newest first, with at
most one sample per minute. The existing P\&L worker samples registered paper accounts that have
traded, including after a restart. This is a sampled curve, **not tick-by-tick history** or proof
of the exact intraday high/low. It starts after this feature is deployed; earlier equity is not
reconstructed. Gaps can occur while the worker is offline. `continuous` is always `false`;
`mayHaveOlderSamples` indicates that another page is available. Request the same analytics URL
with `equityBefore` set to `equityHistory.nextBefore` to retrieve the next older page. Continue
until `nextBefore` is null; verify `cycle.id` has not changed on each page and restart if it has.
Other analytics fields describe the latest snapshot, not the historical page time. Missing or stale marks produce a null equity point, never an invented zero.
Current marks must be no more than 10 seconds old and available on the serving machine.

Inspect `completeness` before using any derived totals:

* `trading` is false if fills/positions/balance do not reconcile, fill ordering is ambiguous,
  values are invalid, or a source exceeds the 50,000-row walk limit. `reasons` identifies why.
  A capped response contains partial source data; do not use its totals as final performance.
* `risk` describes whether durable risk-event recording covers the whole current cycle. Accounts
  whose cycle predates deployment return false, even if no surviving breach can be found.
* `currentEquity` is false when an open position cannot be valued. Historical samples are
  independently labelled `sampled_not_continuous`.
* `unresolvedCommands` counts accepted, dispatching, uncertain or unrecognized command states. Any such command blocks
  advancement even when the visible account currently looks flat.

These reads report the engine's recorded risk evidence. They do not retrospectively test private
firm rules or reconstruct an unrecorded intraday drawdown. Configure your risk controls before
trading; evaluate additional business rules in your own backend. An incomplete answer or HTTP error
must never be interpreted as permission to advance.

## Reset boundaries

`cycle.startedAt` is account creation or its latest reset. A reset starts a new `cycle.id`, resets
trading-day and fill-derived profit calculations, and changes the transition reference.
`cycle.resetBoundaries` records observed reset boundaries from deployment onward. Resets before
this feature may not appear in that list; `cycle.resetAt` still exposes the most recent reset.
The paper venue deletes prior-cycle fills when reset, so `priorTradingHistoryAvailable` is false.
Export analytics before an intentional reset if you need that history. Resetting does not clear
an active risk lock or an enrollment failure through this API.

For a legacy account with `incomplete_risk_history`, do not automatically reset it to make it pass.
Review its history separately. A genuinely new account or an intentionally authorized new reset
cycle has forward coverage; old unknown evidence is never silently declared complete.

## Check a stage

```bash theme={null}
curl --get "$TRDRS_API_BASE_URL/api/partner/accounts/eligibility" \
  -H "Authorization: Bearer $TRDRS_PARTNER_KEY" \
  --data-urlencode "account=EVAL-7C21A9" \
  --data-urlencode "stageId=evaluation-1" \
  --data-urlencode "profitTarget=3000" \
  --data-urlencode "minimumTradingDays=2" \
  --data-urlencode "timeZone=America/Chicago" \
  --data-urlencode "rolloverHour=17"
```

The firm supplies its saved stage policy. `profitTarget` is a positive amount in account currency
with at most two decimal places, not a percentage. `minimumTradingDays` is an integer from 0 to
3,650. `stageId` is 1–80 letters, digits, underscores or hyphens and must remain stable across retries.
`policyId` fingerprints those rules and the session definition. Persist it with your decision;
do not lower thresholds or change session rules during a retry.

`eligible: true` requires **all** of the following at the snapshot:

1. Complete current-cycle trading data and risk-event coverage, and an active issued account.
2. Net trading profit at or above the target, and at least the minimum qualifying session days.
3. No open positions, no working orders and no unresolved commands.
4. No recorded daily-loss, weekly-loss or evaluation breach. Unknown risk reasons also block.
   Daily/weekly profit locks and end-of-day closes are not treated as disqualifying losses.
5. An active **firm halt**, so trading cannot restart while your backend creates the next stage.

A successful check with unmet conditions returns `200`, `eligible: false`, and `reasons` such as
`profit_target_not_met`, `minimum_trading_days_not_met`, `open_positions`, `open_orders`,
`unresolved_commands`, `disqualifying_breach`, `incomplete_trading_data`, `incomplete_risk_history`,
`account_not_active` or `firm_halt_required`.

## Advance safely and retry

The read does **not** advance, close, reset or reserve an account. Meridian owns the challenge's
stage sequence and its customer communications. Use this sequence in your backend:

1. Use analytics to detect a candidate that has reached its goals. Check your additional firm rules.
2. Serialize progression for that challenge in your own database. Halt the old account using the
   existing partner halt endpoint. Halt prevents new trading; it does not close positions or cancel
   orders. Resolve remaining activity through your normal authorized workflow, then recheck.
3. Read eligibility with the saved stage policy. Advance only on a fresh `eligible: true` result.
   Keep the old account halted; do not concurrently resume, reset, change risk rules or adjust it.
4. Persist the decision's `cycleId`, `stageId`, `policyId`, `snapshotId`, and `transitionReference`
   under a unique constraint on your challenge + cycle + stage. Queue the next-account creation
   durably in the same transaction, so a backend restart cannot lose it.
5. Create the next stage account through the existing account API, using **the exact
   `transitionReference` as its `referenceId`**. If the request times out, retry the same payload and
   reference. The account API returns the already-created account instead of creating a second one.
6. Save the returned account number and configure its next-stage risk controls before allowing trading.

The transition reference is stable for the issuing firm, account cycle and stage. A repeated check
may return a different eligibility verdict as facts change; it is not a permanent pass certificate.
A changed target produces a different `policyId` but does not create a new transition reference.
Retries cannot become an excuse to create another next-stage account under the same stage identity.
Use separate stage IDs and preserve the previous account when advancing multiple-stage challenges.

On `429`, network failures or `5xx`, retry with backoff. On `400`, correct the parameters. On `401`,
fix authorization. On `404`, check ownership and whether this deployment runs firm-issued accounts.
Do not translate any error into a pass. No new eligibility webhook is required: the read is the
source for this workflow, and existing fill/risk notifications can prompt your backend to recheck.
