Portfolio & Account State
Consolidated account state, withdrawable balance, fee schedule, enriched positions, and the portfolio time-series — across the SDKs and CLI.
The portfolio surface answers four questions about an account in one place: what is it worth right now, what can actually be withdrawn, what does it get charged, and how has it performed over time. It is exposed as a small set of authenticated REST endpoints plus enriched per-position risk fields, and every interface — the Rust, TypeScript and Python SDKs and the CLI — reaches the same routes on the gateway documented under APIs & Rates.
If you are building a portfolio view, read Reading these values safely before you render anything. Several fields are deliberately nullable, one sign convention is easy to invert, and there is one race condition that a naive two-call implementation will hit in production.
Getting it
npm install @nexus-xyz/exchange-ts # TypeScript
cargo add nexus-exchange # Rust
# Python is not on PyPI yet — install from source:
pip install git+https://github.com/nexus-xyz/nexus-exchange-pyThe CLI is distributed through nexus-exchange-cli releases. See the Interfaces overview for all four clients.
Authentication
Every route on this page is account-scoped and requires an HMAC API key — there is no public or unauthenticated variant. Requests carry X-API-Key, X-Timestamp and X-Signature, and the timestamp must be within 30 seconds of server time. The SDKs and CLI sign for you. The full flow, with runnable cURL, is in the Quickstart.
Keep the API secret out of source and out of shell history — it is shown once at creation and cannot be retrieved later. The examples below read it from the environment.
Choosing a network
The Exchange runs on Nexus Testnet today; mainnet will follow. Select the network by pointing the interface at the matching gateway base URL (see APIs & Rates). Credentials are scoped to the network they were created on, so a testnet key will not authenticate against mainnet.
Reference
GET
/account/state
HMAC
Portfolio summary and every open position, from one coherent read
GET
/account/summary
HMAC
Portfolio summary alone — the same object embedded in /account/state
GET
/account/fees
HMAC
Effective fee schedule for the account
GET
/account/portfolio-history?window=&limit=
HMAC
Equity, cumulative PnL and cumulative volume time-series
Per-SDK entry points:
Rust
fetch_account_state()
fetch_account_fees()
fetch_portfolio_history(window, limit)
Python
fetch_account_state()
fetch_account_fees()
fetch_portfolio_history(window, limit)
TypeScript
getAccountState()
getAccountFees()
getPortfolioHistory({ window, limit })
CLI
nexus account state
nexus account fees
nexus account portfolio-history --window --limit
Consolidated account state
GET /account/state returns the portfolio aggregates and all open positions built from one server-side read. Because both halves come from the same snapshot, summary.open_positions_count always equals the length of positions.
The summary carries collateral, total_equity, total_unrealized_pnl, total_realized_pnl_24h, total_volume_24h, open_positions_count, open_orders_count, margin_used, available_margin and withdrawable.
withdrawable is the balance that can actually leave the account: engine-authoritative free margin floored at zero, max(0, available_margin). Free margin already nets each position's initial margin and every pre-trade order reservation out of equity, so this is the amount a withdrawal can draw on — not total_equity, and not collateral. An underwater account clamps to "0" and is never reported negative. It is derived from the authoritative margin view, so when that view is unavailable the endpoint fails closed with 502 rather than returning a locally estimated number.
Fee schedule
GET /account/fees reports what the venue charges the account today — the forward-looking schedule rate, not a realized average over past fills.
maker_fee_bps
Basis points. May be negative, which means the maker is paid a rebate
taker_fee_bps
Basis points — 5 is 0.05%
tier
Currently always base; there are no per-account tiers yet
schedule
Scope of the reported rate. Currently always standard
volume_30d
Rolling 30-day traded notional, decimal string. Best-effort — see the flag below
volume_30d_estimated
true when volume_30d may undercount (the source fill buffer was at capacity)
discounts
Active discounts. Currently always empty
tier, schedule and discounts are provisional: the fee model is still being finalized, and discounts entries have no guaranteed properties yet. Treat the two _bps integers as the stable part of this response and do not branch on a discount shape that does not exist.
Portfolio time-series
GET /account/portfolio-history returns equity, cumulative trading PnL and cumulative traded notional over a window, downsampled server-side. Points are oldest first.
window
Cadence
Max points
Span
day
5 min
288
24 h
week
1 h
168
7 d
month
6 h
120
30 d
all
1 d
366
~1 y
Omitting window gives day. A value outside that set is rejected with 400 (invalid_window); if the parameter is repeated, the first value is used. limit must be between 1 and 366 — inside that range it narrows the result and is clamped to the window's capacity rather than rejected, so asking for 366 points of day returns 288 rather than an error; outside it, the request is rejected with 400.
The response echoes the window and the cadence_ms that were actually served. Read them back rather than assuming the values you sent: it is the difference between labelling an axis correctly and labelling it plausibly.
Each point carries timestamp_ms, equity, pnl and volume. pnl and volume are cumulative up to that sample, not per-interval — to chart per-interval activity, difference adjacent points yourself.
Enriched position fields
Positions returned by /account/state (and /positions) carry per-position risk detail alongside market_id, side, size, entry_price, unrealized_pnl and realized_pnl:
notional_value
abs(size) × mark price
margin_used
Initial margin held against the position, under the cross-margin model
roe
Return on initial margin: unrealized_pnl / margin_used
max_leverage
Maximum leverage the market allows, from its risk params
leverage
The account's leverage multiplier for this position
funding_paid
Cumulative funding on the position — see the sign convention below
These are computed on the low-latency read path rather than by round-tripping to the matching engine, which is what keeps the endpoint fast. The trade-off is that when one of their inputs is not available on that path, the field is null and a companion <field>_error carries a machine-readable reason instead of a fabricated number.
leverage is currently always null, with leverage_error set to margin_state_not_mirrored: deriving it needs the account's leverage setting or its allocated margin, and neither is available on the read path. Do not reconstruct it from margin_used — that expression collapses to 1 / initial_margin_rate, which is a per-market constant, not the position's real leverage. Showing that as leverage would be confidently wrong on every position in the market.
funding_paid is paid-positive. A positive value means the position has paid funding; a negative value means it has received funding. It is always present, "0" before any funding accrues, and bounded by the funding history the venue retains. Inverting this sign turns a cost into income on a P&L screen, so it is worth a test.
Reading these values safely
Monetary values are decimal strings, not numbers. equity, pnl, volume, withdrawable, notional_value and the rest are arbitrary-precision decimals serialized as strings so they are lossless. Parse them with a decimal type. Passing them through a float — parseFloat, float(), as f64 — reintroduces exactly the rounding error the string encoding exists to prevent. Leverage fields (leverage, max_leverage) are genuine JSON numbers.
Derived fields have three states, not two. Each of the five computed position fields — notional_value, margin_used, roe, leverage and max_leverage — can be:
a value — computed and authoritative;
null— reported, but not computable; the paired<field>_errorsays why;absent — the server predates the field.
Collapsing any of these into 0 invents data. "Not reported", "not computable" and "zero" are three different answers to a user asking what their position is worth, and only one of them is a number. Render the missing cases as an explicit gap — the CLI prints - — and surface the <field>_error when you have it. The same applies to withdrawable: it is optional in the schema, so an older deployment can omit it, and defaulting that to "0" would tell someone they have nothing available when the truth is that nobody asked.
Those five are exactly the fields carrying a companion <field>_error. funding_paid is not one of them — it is always present, so there is no funding_paid_error to branch on.
Prefer /account/state over two calls. Fetching /account/summary and /positions separately is two independent requests against a live account. A fill landing between them returns an aggregate that disagrees with the position list — open_positions_count says three, the array has four — and the window is real under any load. The consolidated endpoint exists so that one coherent read backs both halves.
Handle the failure codes distinctly. 401 is a credential or clock problem — check that X-Timestamp is within 30 seconds of server time before assuming the key is wrong. 429 means you exceeded the rate budget; see Rate & Connection Limits and back off rather than retrying immediately. 502 on /account/state and /account/summary means the authoritative margin view was unreachable and the server declined to guess — retry, and do not fall back to a locally computed withdrawable.
Example
The numbers above are self-consistent, which is worth tracing once: at a mark price of 86000, notional_value is 0.25 × 86000, unrealized_pnl is 0.25 × (86000 − 84000), margin_used is notional_value × 1/max_leverage, roe is unrealized_pnl / margin_used, and withdrawable equals total_equity − margin_used because there are no open orders reserving margin.
Runnable end-to-end examples live in the SDK repositories: examples/portfolio.ts and examples/portfolio.rs.
Related
Status: development preview on testnet. These routes ship in OpenAPI spec v0.7.2; pin to a spec version in production and check each SDK's release notes before upgrading.
tier,scheduleanddiscountson/account/feesare provisional and finalize with the fee model, andleveragereportsnulluntil the margin state it needs is mirrored. Testnet credentials and balances have no real-world value.
Last updated

