getSummary, getPerformance, getRealizedPnl, getAssets, and the two sdk.profile methods below read from a dedicated replica, so they may reflect replica lag and can trail a live position or balance read by a short interval. Do not reconcile a number from this page against a live one to the cent. A reader outage returns a retryable 503 (gRPC Unavailable) rather than falling back to the writer, so treat unavailability as transient and retry. getMargin() is the exception: it is writer-backed rather than replica-backed, as is trade history. Its withdrawable-collateral bounds are still not unconditionally live, and the fallback has two scopes: if the matching engine serves no bounds at all, the account total and every risk bucket row fall back to a persisted reconstruction; if it serves bounds but one bucket is missing, only that row falls back. The reconstruction uses the same formulas the withdrawal gates enforce, but cannot see their resting-order reserves or the parent margin account’s live allocation constraint, so treat a fallback value as an estimate rather than an enforceable bound. Do not make these analytics the sole input to a real-time control of your own — a withdrawal gate, a risk limit, or a liquidation decision; read the live surfaces for that.
Historical methods accept an optional period of "1d", "1w", "1m", or "all", defaulting to all when omitted. getMargin() is current-only and takes no period.
All decimal amounts and percentages are returned as strings. Every response carries a window (or asOf) describing the query cutoff and how much history the retained data actually covers. Dependent values that cannot be computed — a return over a window with no starting equity, or the value of an asset with no spot price — are omitted rather than reported as 0; branch on their presence before displaying.
Two shared shapes appear across these responses:
PortfolioWindow—period,asOf(query cutoff, ISO 8601), optionaldataThrough/requestedStartsAt/effectiveStartsAt/historyStartsAt, andcoverage("complete","partial", or"none").PortfolioSeriesWindow— extendsPortfolioWindowwithdisplayInterval("5m"/"1h"/"4h"/"1d") andcalculationInterval("1m"/"5m"/"15m"/"1h"/"4h"/"1d").
valuationStatus is "complete" when every input had a price and "partial" when at least one dependent value was omitted for a missing price.
(params?: { period }) => Promise<PortfolioSummary>
Return the current equity breakdown plus trading activity over the requested window.Requires authentication.Parameters:
PortfolioPeriodParams (optional):period:"1d" | "1w" | "1m" | "all"— defaults toall
PortfolioSummary:window:PortfolioWindowvaluationStatus:"complete" | "partial"current: current equity split —perpsEquity(string), plus optionaltotalEquity,spotEquity,unrealizedPnl, andavailableValue.availableValueis what you can spend or withdraw now: USDC available on spot plus the parent margin account’swithdrawableCollateral. Other spot assets and unrealized margin gains are not counted, and it is served even whenvaluationStatusispartialactivity: period activity —volume(string),tradeCount(number),orderCount(number),feesPaid(string)
(params?: { period }) => Promise<PortfolioPerformance>
Return transfer-neutral dollar PnL and a sampled time-weighted return (TWR) series for the
window. Deposits and withdrawals are excluded from PnL so external flows do not distort return. Equity covers every margin account you hold (the default account and sub-accounts) plus your spot holdings.
deposits, withdrawals and netExternalFlows cover the requested period, so the deposits that first funded an account count when the account was created inside the period. The period boundaries follow the sampled history rather than the exact request time: the start can fall up to one hour before or one sampling interval after requestedStartsAt, and the end is the latest completed sample (dataThrough), so these are period totals at sample resolution, not exact to the second. For all they cover the account’s whole performance history. startingEquity, pnl, returnPct and modifiedDietzReturnPct are measured from the first sample with positive equity.For any period with retained history, unpriceable external withdrawals are omitted from withdrawals and the dependent deposits total; successful responses with these omissions report valuationStatus: "partial". A recognized quote asset without a valuation pair is valued at 1, so it is not omitted for lacking a pair. Reconciliation checks still apply: if derived deposits become negative, the request fails as unavailable.Requires authentication.Parameters: PortfolioPeriodParams (optional):period:"1d" | "1w" | "1m" | "all"— defaults toall
PortfolioPerformance:window:PortfolioSeriesWindowcalculationMethod:"sampled_twr"valuationStatus:"complete" | "partial"startingEquity?,endingEquity?: stringdeposits,withdrawals,netExternalFlows: stringpnl?,returnPct?: string — omitted when the window lacks a starting equity to measure against.returnPctis time-weighted and is also omitted once equity has touched zero in the windowmodifiedDietzReturnPct?: string — pnl divided by the starting equity plus each deposit minus each withdrawal, each weighted by the share of the window it was in the account (a flow is taken at the middle of its sample interval). Never below -100%, since an account cannot lose more than it received. UnlikereturnPctit stays defined after equity touches zero. Omitted when the window has no positive-equity sample, or when withdrawals leave that time-weighted capital below 5% of what it would have been without them (the starting equity plus the time-weighted deposits). It is not bounded above: a capital just over that limit can still give a gain of up to about 20 times the return on the full base.maxDrawdownandcalculationMethoddescribe the time-weightedreturnPctseries only and can cover less of the window thanmodifiedDietzReturnPct- To show a single return, use
returnPctand fall back tomodifiedDietzReturnPctwhenreturnPctis omitted, and say which of the two is shown: they answer different questions (the strategy’s performance versus your money’s). maxDrawdown?:{ amount, pct, peakAt, troughAt }— positive loss magnitude, peak-to-trough sampled-TWR percentage, and the peak/trough timestampspoints:PortfolioPerformancePoint[]— each{ timestamp, equity, cumulativePnl, cumulativeReturnPct? }. The points chartcumulativePnland the time-weightedcumulativeReturnPct; there is no per-point Modified Dietz series
(params?: { period }) => Promise<PortfolioRealizedPnl>
Return realized PnL for the window, split by source. Spot-withdrawal disposal PnL is excluded.Requires authentication.Parameters:
PortfolioPeriodParams (optional):period:"1d" | "1w" | "1m" | "all"— defaults toall
PortfolioRealizedPnl:window:PortfolioSeriesWindowbucketInterval:"1h" | "1d"— the series bucket size (hourly for1d, daily otherwise)totals:PortfolioRealizedTotals—perpsClosedPnl,spotTradePnl,fundingPnl,feesPaid,netRealizedPnl(all strings)closedTrades:{ count, winners, losers, breakEven, positions, winRatePct? }—winners,losers,breakEven, andwinRatePctare position-based: each position (one flat→open→flat round-trip) is classified once by its net realized PnL after all fees, not per closing fill.positionsis the total classified positions (winners + losers + breakEven);countstays fill-based (closing fills in the window)bestDay?:{ date, netRealizedPnl }—dateis a UTCYYYY-MM-DDcalendar daypoints:PortfolioRealizedPnlPoint[]— thetotalsfields plus atimestamp, one per bucket
(params?: { period }) => Promise<PortfolioAssets>
Return per-asset spot holdings priced by asset ID, with allocation percentages and window-scoped
spot performance. Rows for assets without a spot price are returned
unpriced, with value,
allocationPct, and markPrice omitted.Requires authentication.Parameters: PortfolioPeriodParams (optional):period:"1d" | "1w" | "1m" | "all"— defaults toall
PortfolioAssets:window:PortfolioSeriesWindowvaluationStatus:"complete" | "partial"totalSpotEquity?: string — omitted when any held asset is unpricedperformance:{ pnl?, returnPct?, modifiedDietzReturnPct?, calculationMethod: "sampled_twr" }—returnPctis time-weighted and is omitted once spot equity has touched zero;modifiedDietzReturnPctis defined as for the performance endpointassets:PortfolioAssetRow[]— each{ assetId, symbol, totalBalance, availableBalance, lockedBalance, markPrice?, value?, allocationPct?, priceAsOf?, pricingStatus, avgCost?, unrealizedPnl?, unrealizedRoe?, cumRealized? }wherepricingStatusis"priced"or"unpriced". The spot cost-basis fields —avgCost(weighted-average cost per unit),unrealizedPnl(costBasisQuantity × (markPrice − avgCost)),unrealizedRoe(percentage return on cost basis), andcumRealized(lifetime realized PnL, gross of fees) — are present when the asset has a cost-basis checkpoint;unrealizedPnlandunrealizedRoeadditionally require a mark price, andunrealizedRoeadditionally requires a non-zero cost basis
(params?: PortfolioMarginParams) => Promise<PortfolioMargin>
Return the current margin picture: parent-account totals and per-risk-bucket projections, kept
separate. Parent free collateral does not include risk-bucket free collateral. This method is
current-only and takes no period. By default it describes the default margin account; pass
Throws:
marginAccountId to describe one of your sub-accounts instead, and includeAccounts to add the
owner rollup across every open margin account.Requires authentication.Parameters: PortfolioMarginParams (optional):marginAccountId?: string — one of your margin accounts (the default one or a sub-account) to describe instead of the default one;total,riskBucketsand thepositionscounts are then that account’s own. Without it,totalandriskBucketsdescribe the default margin account while thepositionscounts stay owner-wide across every margin accountincludeAccounts?: boolean — also returnaccountsandownerTotal
PortfolioMargin:asOf: string — snapshot timestamp (ISO 8601)marginAccountId?: string — the margin accounttotalandriskBucketsdescribe (and thepositionscounts too, when the request namesmarginAccountId; otherwise those stay owner-wide); absent before your first margin account existsaccounts?:PortfolioMarginAccount[]— withincludeAccounts: every open margin account, the default one first, then sub-accounts by key; each{ marginAccountId, subaccountKey, total }, wheresubaccountKeyis"default"for the default margin account andtotalis aPortfolioMarginTotalwhosewithdrawableCollateralis the persisted reconstruction of the engine’s boundownerTotal?:PortfolioMarginTotal— withincludeAccounts: the sum ofaccounts’ totalstotal:PortfolioMarginTotal—equity,collateralBalance,parentAvailableCollateral(parent-only free collateral),withdrawableCollateral,initialMarginRequired,maintenanceMarginRequired,unrealizedPnl(all strings)positions:{ total, cross, isolated }— open-position countsriskBuckets:PortfolioRiskBucket[]— each{ riskBucketId, marginMode, tradingPairId?, collateral, freeCollateral, withdrawableCollateral, maxRemovableCollateral?, availableOrderCollateral?, initialMarginRequired, maintenanceMarginRequired, unrealizedPnl, positionCount }.availableOrderCollateralis the engine-served capacity for new orders in that bucket (parent auto top-up included, not additive across rows — see the margin-accounts docs for the full semantics); it is present only on live-engine reads, so handleundefined.maxRemovableCollateralis the largest removal the engine accepts when it may also lower the posted margin of an isolated bucket’s one open position (equal towithdrawableCollateralotherwise), also live-engine only.marginMode("ISOLATED"/"CROSS") is always present and lets you attribute bucket margin to cross or isolated without a second call;tradingPairIdis present only onISOLATEDrows, since a cross bucket spans the markets where it has an open position and is scoped to none individually (read that membership from the margin-accountsselectedTradingPairIds).
marginMode does not reconcile with the positions.cross / positions.isolated counts, and grouping riskBuckets by mode will not reproduce them. Without marginAccountId, those counts are computed by a separate query over every margin account for your user/application pair, while riskBuckets comes from the single oldest (parent) account, and they attribute a legacy position carrying no risk-bucket reference to cross whether or not a cross bucket row exists. Treat them as account-wide totals, not as a checksum over the rows. For the same reason these labels are not a join key against the margin-accounts surface — that surface emits rows this one has no counterpart for, and the two disagree on legacy-position attribution on persisted-fallback reads.parentAvailableCollateral is an equity figure: it credits settled realized PnL, accrued
funding, and unrealized gains, none of which are principal a transfer can move. The bound the
engine actually enforces on transfers-out and withdrawals — and, because allocating collateral to
a risk bucket passes the same principal-gated door, the effective ceiling on funding a new
isolated or first-use position — is total.withdrawableCollateral. The two can differ without
limit (e.g. a large banked realized PnL lifts parentAvailableCollateral far above what any
transfer would accept). Size transfers, withdrawals, and new isolated/first-use positions from
withdrawableCollateral; treat parentAvailableCollateral/freeCollateral as trading-margin
headroom for existing cross exposure.Example:400 when marginAccountId is not a UUID; 404 when it is not one of your margin
accounts; 401 without authentication; 429 past the read budget; 503 when portfolio data is
unavailable; 500 on an internal error.Aggregate stats and chart (sdk.profile)
Two earlier portfolio methods live under the sdk.profile namespace. They return a single aggregate snapshot and a simple time-bucketed series, and remain supported. Prefer the authoritative sdk.portfolio methods above for richer breakdowns and explicit history coverage. The v1.0.21 fee-total corrections apply to both methods below.
(period: PortfolioPeriod) => Promise<PortfolioStats>
Fetch aggregate trading statistics for the authenticated user over a given time period.Parameters:
period:"24h"|"7d"|"30d"|"all"
pnl: Average-cost realized PnL over the period (quote asset, normalized) — net of fees, across spot and perps incl. funding; excludes unrealized PnL. Spot withdrawals are booked as fair-value disposals(last trade price − avg cost) × qty; deposits and withdrawals are priced at the last observed trade price in event order; transfers that predate any trade on the pair are PnL-neutral; short-entry fees reduce short profitsvolume: Total trading volume (quote asset, normalized)totalTrades: Total number of trades executedtotalOrders: Total number of orders placedfeesPaid: Total fees paid (quote asset, normalized)totalEquity: Total equity (quote asset, normalized) — spot balances plus perpetuals (margin) account equityspotEquity: Spot account equity (quote asset, normalized)perpsEquity: Perpetuals (margin) account equity (quote asset, normalized)winLossRatio: Position-level win rate — winning positions over winning + losing positions, break-even excluded (number); each position (one flat→open→flat round-trip) is classified once by its net realized PnL after all fees, not per fill;nullwhen the period has no closed positionsmaxDrawdown: Peak-to-trough drawdown on running PnL;nullwhen the period has no closed trades
(period: PortfolioPeriod, metric: PortfolioMetric) => Promise<PortfolioChartResponse>
Fetch a time-bucketed chart series for a given period and metric. Equity covers every margin account you hold (the default account and sub-accounts) plus your spot holdings.Parameters:
period:"24h"|"7d"|"30d"|"all"metric:"volume"|"pnl"
metric: The metric returnedperiod: The period requesteddata: Array of{ timestamp: string, value: string }data points (ISO 8601 bucket start times)

