Skip to main content
These methods return authoritative calculations computed in Core — the same numbers across every client. They are application-scoped and require authentication. 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), optional dataThrough / requestedStartsAt / effectiveStartsAt / historyStartsAt, and coverage ("complete", "partial", or "none").
  • PortfolioSeriesWindow — extends PortfolioWindow with displayInterval ("5m"/"1h"/"4h"/"1d") and calculationInterval ("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 to all
Returns: PortfolioSummary:
  • window: PortfolioWindow
  • valuationStatus: "complete" | "partial"
  • current: current equity split — perpsEquity (string), plus optional totalEquity, spotEquity, unrealizedPnl, and availableValue
  • activity: period activity — volume (string), tradeCount (number), orderCount (number), feesPaid (string)
Example:
(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.For any period with a performance baseline, 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 to all
Returns: PortfolioPerformance:
  • window: PortfolioSeriesWindow
  • calculationMethod: "sampled_twr"
  • valuationStatus: "complete" | "partial"
  • startingEquity?, endingEquity?: string
  • deposits, withdrawals, netExternalFlows: string
  • pnl?, returnPct?: string — omitted when the window lacks a starting equity to measure against
  • maxDrawdown?: { amount, pct, peakAt, troughAt } — positive loss magnitude, peak-to-trough sampled-TWR percentage, and the peak/trough timestamps
  • points: PortfolioPerformancePoint[] — each { timestamp, equity, cumulativePnl, cumulativeReturnPct? }
Example:
(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 to all
Returns: PortfolioRealizedPnl:
  • window: PortfolioSeriesWindow
  • bucketInterval: "1h" | "1d" — the series bucket size (hourly for 1d, daily otherwise)
  • totals: PortfolioRealizedTotals — perpsClosedPnl, spotTradePnl, fundingPnl, feesPaid, netRealizedPnl (all strings)
  • closedTrades: { count, winners, losers, breakEven, positions, winRatePct? } — winners, losers, breakEven, and winRatePct are 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. positions is the total classified positions (winners + losers + breakEven); count stays fill-based (closing fills in the window)
  • bestDay?: { date, netRealizedPnl } — date is a UTC YYYY-MM-DD calendar day
  • points: PortfolioRealizedPnlPoint[] — the totals fields plus a timestamp, one per bucket
Example:
(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 to all
Returns: PortfolioAssets:
  • window: PortfolioSeriesWindow
  • valuationStatus: "complete" | "partial"
  • totalSpotEquity?: string — omitted when any held asset is unpriced
  • performance: { pnl?, returnPct?, calculationMethod: "sampled_twr" }
  • assets: PortfolioAssetRow[] — each { assetId, symbol, totalBalance, availableBalance, lockedBalance, markPrice?, value?, allocationPct?, priceAsOf?, pricingStatus, avgCost?, unrealizedPnl?, unrealizedRoe?, cumRealized? } where pricingStatus is "priced" or "unpriced". The spot cost-basis fields — avgCost (weighted-average cost per unit), unrealizedPnl (costBasisQuantity × (markPrice − avgCost)), unrealizedRoe (percentage return on cost basis), and cumRealized (lifetime realized PnL, gross of fees) — are present when the asset has a cost-basis checkpoint; unrealizedPnl and unrealizedRoe additionally require a mark price, and unrealizedRoe additionally requires a non-zero cost basis
Example:
() => 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.Requires authentication.Returns: PortfolioMargin:
  • asOf: string — snapshot timestamp (ISO 8601)
  • total: PortfolioMarginTotal — equity, collateralBalance, parentAvailableCollateral (parent-only free collateral), withdrawableCollateral, initialMarginRequired, maintenanceMarginRequired, unrealizedPnl (all strings)
  • positions: { total, cross, isolated } — open-position counts
  • riskBuckets: PortfolioRiskBucket[] — each { riskBucketId, marginMode, tradingPairId?, collateral, freeCollateral, withdrawableCollateral, availableOrderCollateral?, initialMarginRequired, maintenanceMarginRequired, unrealizedPnl, positionCount }. availableOrderCollateral is 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 handle undefined. marginMode ("ISOLATED" / "CROSS") is always present and lets you attribute bucket margin to cross or isolated without a second call; tradingPairId is present only on ISOLATED rows, since a cross bucket spans the pairs selected into it and is scoped to none individually (read that membership from the margin-accounts selectedTradingPairIds).
marginMode does not reconcile with the positions.cross / positions.isolated counts, and grouping riskBuckets by mode will not reproduce them. 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:

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"
Returns:
  • 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 profits
  • volume: Total trading volume (quote asset, normalized)
  • totalTrades: Total number of trades executed
  • totalOrders: Total number of orders placed
  • feesPaid: Total fees paid (quote asset, normalized)
  • totalEquity: Total equity (quote asset, normalized) — spot balances plus perpetuals (margin) account equity
  • spotEquity: 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; null when the period has no closed positions
  • maxDrawdown: Peak-to-trough drawdown on running PnL; null when the period has no closed trades
(period: PortfolioPeriod, metric: PortfolioMetric) => Promise<PortfolioChartResponse>
Fetch a time-bucketed chart series for a given period and metric.Parameters:
  • period: "24h" | "7d" | "30d" | "all"
  • metric: "volume" | "pnl"
Returns:
  • metric: The metric returned
  • period: The period requested
  • data: Array of { timestamp: string, value: string } data points (ISO 8601 bucket start times)