Prepared: 2026-07-01 · Mode: deep research · Scope owner: hyperliquid-trader-tracker
Hyperliquid exposes a fully public, unauthenticated, read-only data surface that is explicitly sanctioned for programmatic use — no API key, no signature, no user-agent/CAPTCHA gating (in sharp contrast to third-party analytics sites like Hyperdash, whose GraphQL actively blocks bots). That surface is two endpoints:
POST https://api.hyperliquid.xyz/info— a single JSON-over-HTTP endpoint whosetypefield selects one of ~50 request kinds spanning market data, the perps universe, the spot universe, and per-account state. This is the source of truth for current positions, leverage, margin, fills, and PnL of any address.wss://api.hyperliquid.xyz/ws— a WebSocket carrying market-wide feeds (per-cointrades,allMids,l2Book,candle, …) and per-user feeds (userFills,webData2,clearinghouseState,activeAssetData, …).
For the wallet-tracker use case, three facts are load-bearing and were verified against the official docs:
- The public
tradesfeed carries both counterparties asusers: [buyer, seller]. This lets a single market-data subscription track an unlimited number of wallets by filtering each trade against a watchlist — no per-wallet subscription needed. (Independently verified live in the siblinghyperdash-crawlproject.) userFills.startPositionis the signed position size immediately before a fill. This is the native, authoritative primitive for the user's core requirement:startPosition == 0⇒ "Started trade"; a same-direction fill on a nonzerostartPosition⇒ "Added to position"; opposite ⇒ reduce/close/flip. No inference needed.- Read-only tracking is never rate-limited by trading volume. The per-address limit (1 request per 1 USDC traded) applies only to exchange actions, not to info reads.
clearinghouseState— which returns per-position leverage — costs weight 2, so leverage enrichment is effectively free at watchlist scale.
The binding constraint is the WebSocket cap of 10 unique users per IP for per-user subscriptions. This produces a clean architectural fork: a watchlist of ≤10 wallets can subscribe per-user (userFills gives dir/startPosition/closedPnl/leverage natively); a larger watchlist must use the global trades firehose plus a position state machine and REST enrichment. The sibling hyperdash-crawl codebase already implements the firehose path (verified trades listener + pure apply_fill state machine emitting open/add/reduce/close), so the tracker is largely an assembly-and-strip job (remove Redis/Postgres → in-memory dict; add a push sink).
This report (a) maps the public, open Hyperliquid API surface relevant to observing wallet activity, and (b) grounds the design of hyperliquid-trader-tracker — a service that watches a curated list of wallets and pushes a notification when any of them opens or adds to a position. Exchange (order-placement) endpoints are catalogued only for completeness; the tracker is strictly read-only.
Primary sources are the official Hyperliquid developer docs (hyperliquid.gitbook.io/hyperliquid-docs), fetched 2026-07-01, cross-referenced with mirror providers (Chainstack, QuickNode) where the GitBook omits field-level schemas. Three independent research agents mapped the Info HTTP API, the WebSocket API, and the rate-limit/auth posture; a fourth pass adversarially re-verified the five load-bearing claims against the primary docs. Reusable implementation facts were drawn from the sibling hyperdash-crawl project, whose trades-feed listener has the [buyer, seller] convention verified against the live socket (2026-06-16).
- Perps-first. The user's notification semantics ("Long/Short", "leverage") are perpetuals concepts; spot is mapped but treated as an extension.
- "Store nothing" = no database/persistence of trades or positions. The watchlist itself must live somewhere (in-memory seeded from config/env, or a small config file) — this is flagged as an open question, not assumed.
- Push delivery ≈ Telegram bot, inferred from the provided screenshots (a Telegram "Drops Bot" tracking UI). Confirmed as an open question.
| Property | Finding | Source |
|---|---|---|
Auth for /info |
None. Fully public read-only; user param is just the target address (the real account address, not an agent/API wallet). |
Info endpoint |
| Auth for public WS | None. Market feeds and per-user read subscriptions need only the target address; subscribing is unsigned. | WebSocket |
| Bot blocking | None on the official surface — no user-agent gating, CAPTCHA, or IP ban for polite polling. Enforcement is purely weight-based 429 throttling. | Rate limits |
| Official SDK | hyperliquid-python-sdk (also community Rust/TS, CCXT). |
API overview |
| Base URLs | Mainnet REST https://api.hyperliquid.xyz (/info), WS wss://api.hyperliquid.xyz/ws. Testnet: …-testnet.xyz. |
API overview |
Contrast with third-party analytics. Hyperdash (api.hyperdash.com/graphql) returns 403 BLOCKED_USER_AGENT to non-browser clients and its ToS forbids scraping; its proprietary metrics (copyScore, computed sharpe/winrate) are unavailable elsewhere. But everything the tracker needs — positions, leverage, fills, PnL — is Hyperliquid's own public on-chain data, so the tracker never needs Hyperdash and never needs a browser.
┌──────────────────────────── Hyperliquid public API ───────────────────────────┐
│ │
REST ── POST ───▶│ https://api.hyperliquid.xyz/info {"type": <one of ~50>, ...} (no auth) │
│ ├─ general/market: allMids, l2Book, candleSnapshot, ... │
│ ├─ perps: meta, metaAndAssetCtxs, clearinghouseState, ... │
│ ├─ spot: spotMeta(AndAssetCtxs), spotClearinghouseState, ... │
│ └─ per-user: userFills(ByTime), portfolio, webData2, ... │
│ │
WS ── connect ──▶│ wss://api.hyperliquid.xyz/ws {"method":"subscribe","subscription":{...}} │
│ ├─ market-wide (uncapped): trades, allMids, l2Book, bbo, candle, ... │
│ └─ per-user (≤10 uniq/IP): userFills, webData2, clearinghouseState, ... │
│ + post requests: {"method":"post","id":N,"request":{"type":"info",...}} │
└────────────────────────────────────────────────────────────────────────────────┘
type |
Params | Returns |
|---|---|---|
allMids |
opt dex |
{coin: "price"} object of all mid prices |
l2Book |
coin, opt nSigFigs/mantissa |
{coin, time, levels:[bids,asks]}, level {px,sz,n} |
candleSnapshot |
req:{coin,interval,startTime,endTime} |
OHLCV array; only most recent 5000 candles |
openOrders / frontendOpenOrders |
user, opt dex |
Open orders (frontend variant adds trigger/TP-SL/reduceOnly) |
orderStatus |
user, oid |
{status, order?} |
historicalOrders |
user |
≤2000 recent {order,status,statusTimestamp} |
userRateLimit |
user |
{cumVlm, nRequestsUsed, nRequestsCap, nRequestsSurplus} — self-monitor budget |
maxBuilderFee, perpDeployAuctionStatus |
… | builder/deploy metadata |
Candle intervals: 1m,3m,5m,15m,30m,1h,2h,4h,8h,12h,1d,3d,1w,1M.
type |
Params | Returns |
|---|---|---|
meta |
opt dex |
{universe[], marginTables[], collateralToken}; universe entry {name, szDecimals, maxLeverage, onlyIsolated} |
metaAndAssetCtxs |
opt dex |
[meta, [ctx…]] positionally parallel to universe; ctx has markPx, midPx, oraclePx, funding, openInterest, premium, dayNtlVlm, prevDayPx |
clearinghouseState |
user, opt dex |
User perps state + open positions + leverage — §4 |
userFunding |
user, startTime |
Funding payments {delta,hash,time} |
fundingHistory |
coin, startTime |
{coin,fundingRate,premium,time} |
predictedFundings, perpsAtOpenInterestCap |
… | funding/OI-cap views |
activeAssetData |
user, coin |
{leverage, maxTradeSzs, availableToTrade, markPx} per user+coin |
perpDexs, perpDexLimits |
… | HIP-3 builder-dex metadata |
type |
Params | Returns |
|---|---|---|
spotMeta |
— | {tokens[], universe[]}; pair name e.g. "PURR/USDC" or index "@107" |
spotMetaAndAssetCtxs |
— | [spotMeta, [ctx…]] |
spotClearinghouseState |
user |
{balances:[{coin,token,total,hold,entryNtl}]} |
tokenDetails, spotDeployState, … |
… | token/deploy metadata |
type |
Params | Returns |
|---|---|---|
userFills |
user, opt aggregateByTime |
≤2000 most recent fills — §5 |
userFillsByTime |
user, startTime, opt endTime |
Fills in a time range, paginated; only 10,000 most recent retained |
portfolio |
user |
[[period,{accountValueHistory,pnlHistory,vlm}]]; periods day/week/month/allTime + perp* |
userFees, referral, subAccounts, userVaultEquities, vaultDetails |
user/… |
fees, referrals, subaccounts, vault equity |
userRole, delegations, delegatorSummary/History/Rewards |
user |
account role & staking |
webData2 |
user |
One-shot aggregate: clearinghouseState + openOrders + meta/assetCtxs + spotState + twapStates + flags. Whole-account snapshot in a single call |
Request: {"type":"clearinghouseState","user":"0x…","dex":""} · weight 2 · no auth.
All numeric fields are strings → parse to Decimal (no float drift). leverage.value is the {leverage}x in the notification; leverage.type distinguishes cross/isolated. This is the object the sibling project already normalizes in build_position (leverage.get("value")).
Request: {"type":"userFills","user":"0x…"} (REST) or WS subscription {"type":"userFills","user":"0x…"}.
{
"coin":"AVAX", "px":"18.435", "sz":"93.53", "side":"B", // B=buy/bid, A=sell/ask
"time":1681222254710,
"startPosition":"26.86", // ← SIGNED position size IMMEDIATELY BEFORE this fill
"dir":"Open Long", // advisory display text ONLY — do not branch on it
"closedPnl":"0.0", // nonzero only when the fill reduces/closes
"hash":"0xa166…", "oid":90542681, "crossed":false, // crossed=true ⇒ this side was taker
"fee":"0.01", "feeToken":"USDC", "builderFee":"0.01", "tid":118906512037719
}The classification primitive (authoritative):
| Condition | Meaning | Notification |
|---|---|---|
startPosition == 0 |
opened a brand-new position (dir from side: B→long, A→short) |
"Started trade" |
startPosition ≠ 0, fill same direction |
added to an existing position (closedPnl == 0) |
"Added to position" |
startPosition ≠ 0, fill opposite, ` |
sz | < |
| opposite, ` | sz | == |
| opposite, ` | sz | > |
Snapshot semantics (critical for a notifier). The first userFills/webData2/userFundings WS message has isSnapshot: true — a backfill of recent history. A notifier must skip the snapshot batch (and re-dedupe by tid after any reconnect) or it will re-notify old fills on every (re)connect. dir is advisory: the docs publish only examples, not an exhaustive enumeration, so branch on startPosition/side, not on dir text.
Pagination (REST userFillsByTime): ≤2000 rows/response; time-walk by advancing startTime past the last row's time; only the 10,000 most-recent fills are retained.
type |
Params | Data |
|---|---|---|
trades |
coin |
{coin, side, px, sz, hash, time, tid, users:[buyer,seller]} — §7 |
allMids |
opt dex |
{mids:{coin:"px"}} |
l2Book |
coin, opt nSigFigs/mantissa/fast |
{coin, time, levels:[bids,asks]} |
bbo |
coin |
{coin, time, bbo:[bestBid,bestAsk]} — pushed only on BBO change |
candle |
coin, interval |
{t,T,s,i,o,h,l,c,v,n} |
activeAssetCtx |
coin |
mark/oracle/funding/OI (perp) or supply (spot) |
type |
Params | Data |
|---|---|---|
userFills |
user, opt aggregateByTime |
{isSnapshot?, user, fills:[WsFill]} — §5 |
webData2/webData3 |
user |
Aggregate account state incl. clearinghouseState/leverage/positions (webData3 nests it under perpDexStates) |
clearinghouseState |
user, opt dex |
Full margin/positions state (unambiguous positions+leverage feed) |
activeAssetData |
user, coin |
{leverage, maxTradeSzs, availableToTrade} — perps only |
userEvents |
user |
Tagged union: {fills}/{funding}/{liquidation}/{nonUserCancel} (arrives on channel:"user") |
orderUpdates |
user |
{order, status, statusTimestamp} |
notification, userFundings, userNonFundingLedgerUpdates, spotState, twapStates, userTwapSliceFills |
user |
as named |
Lifecycle: subscribe → subscriptionResponse ack → data pushes on channel:<type>. Server closes any connection idle 60s → send {"method":"ping"} every ~30s, expect {"channel":"pong"}. Post requests over WS: {"method":"post","id":N,"request":{"type":"info","payload":{…}}} → reply on channel:"post" (≤100 in-flight; explorer not supported over WS).
interface WsTrade {
coin: string; side: string; // "B"=buy-aggressor, "A"=sell-aggressor
px: string; sz: string; hash: string; time: number; tid: number;
users: [string, string]; // [buyer, seller] — NOT [maker, taker]
}users[0]bought (+sz),users[1]sold (−sz). Confirmed by the official docs and verified on the live socket byhyperdash-crawl(2026-06-16): across buy-aggressor BTC trades the resting maker consistently appeared at index 1.- A tracker matches its watchlist against both entries (a wallet may be on either side).
- The feed gives executions only — no leverage, no open/close semantics, no PnL. Those come from the state machine (open/add/reduce/close) plus REST
clearinghouseStateenrichment. tidis a 50-bit hash of(buyer_oid, seller_oid); for a globally unique key use(time, coin, tid).
This is why the firehose path scales to unlimited wallets on one market-data connection: one trades subscription per coin covers every wallet trading that coin.
| Scope | Limit | Relevance to tracker |
|---|---|---|
| REST weight / IP | 1200 / min (info + exchange aggregated) | Ample for enrichment |
clearinghouseState, allMids, l2Book weight |
2 | ~600 clearinghouseState/min possible |
| Default info weight | 20 (+1 per 20 items on paginated; +1 per 60 for candles) | — |
| Address limit (1 req / 1 USDC traded, +10k buffer) | exchange ACTIONS only — NOT info reads | Irrelevant — read-only tracking is never throttled by it |
| WS connections / IP | 10 | ≥1; shard per-user subs across them |
| WS unique users (per-user subs) / IP | 10 | The architectural fork |
| WS total subscriptions / IP | 1000 | trades-per-coin fits easily |
| WS inbound msgs / IP | 2000 / min | ping + subs well under |
| Breach behavior | HTTP 429 soft-throttle, no ban | back off exponentially |
Implication: a read-only tracker of tens of wallets never approaches any limit. The only hard wall is 10 unique users for per-user subscriptions — which is exactly what dictates the tiered architecture in the next section.
A judge panel scored three candidate architectures. The winner (88/100) is firehose-first, beating tiered-adaptive (79) and per-user-subscription (68). Rationale: it is the tightest fit to the stated requirements (small watchlist, store nothing, correct open-vs-add, check pre-existing position) while spending the fewest lines of net-new, unverified code — and its ingestion cost is independent of watchlist size because trades/allMids are market subscriptions that never touch the 10-unique-user cap.
wss://…/ws ── trades (every perp coin) ──▶ resolve_deltas(trade, watchlist) [users:[buyer,seller] filter]
── allMids ──▶ marks │ signed ResolvedFill (+sz buyer / -sz seller)
▼
InMemoryBook.ingest(addr, coin, delta, px, ts)
= dict get → apply_fill(state,…) → dict set
│ LiveEvent(s): open / add / reduce / close
▼
notifier.dispatch(event) ──▶ PUSH (Telegram)
open → "Started trade …" add → "Added to position …"
POST /info clearinghouseState (weight 2) ──▶ build_position ──▶ book.seed(…) [SILENT, no push]
· at startup for the initial watchlist · on every /add · optional periodic reconcile (leverage/drift)
The single default path is the firehose. Per-event dispatch (not hyperdash's windowed batching) is correct here because a personal watchlist is low-volume.
With no storage, the in-memory book is empty at boot and for every newly-added wallet — so a naive first fill on a day-old position would mis-fire as "Started trade". Solved by a mandatory synchronous pre-seed, reusing the verified silent primitive store.seed_positions (installs state without emitting):
- On startup (initial list) and on every
/add, POSTclearinghouseState(weight 2) →build_position→seed_state_from_rowinstalls each open coin as one leg at its entry price. - Order matters: seed first, then admit the address to the
resolve_deltasfilter set. Any trade before admission is simply not resolved. - Result: yesterday's BTC long is already in the book, so today's same-direction fill resolves to
EVENT_ADD→ "Added to position", never a false "Started trade". - Unseeded guard: if the seed REST call fails after retries, quarantine that wallet (no emits) until a seed succeeds — an add can never be mislabeled during a failed seed.
The chain is the durable store, queried on demand — "store nothing" holds while cold-start correctness is preserved.
Strictly additive, flag-gated, and switch off cleanly past 10 wallets with the firehose still fully correct underneath:
- Graft 1 —
userFillscross-check: open a per-useruserFillssub (inside the 10-user cap), drop theisSnapshot:truebackfill, and use each live fill'sstartPositionas an authoritative corrector for the firehose-derived book. This closes the one real firehose weakness — a single missedtradesmessage silently drifting the book — without waiting for the eventually-consistent reconcile. - Graft 2 —
webData2push-leverage: a per-userwebData2sub eliminates leverage staleness between reconciles on the small tier. (Note:webData2is a full-state push, not anisSnapshothistory backfill — handle by replacing local state, not deduping fills.)
| Event | Format |
|---|---|
| open | 🟢 Started trade {LABEL}: {COIN} {Long|Short} {size} @ {px} ({lev}x) |
| add | ➕ Added to position {LABEL}: {COIN} {Long|Short} +{size} (~${notional}) @ {px} ({lev}x) |
| reduce (ext.) | ➖ Reduced {LABEL}: {COIN} {Long|Short} -{size} @ {px} | realized {±}${closedPnl} | {remaining} left |
| close (ext.) | 🔴 Closed {LABEL}: {COIN} {Long|Short} {size} @ {px} | realized {±}${closedPnl} |
notional = |delta| × mark (mark from allMids). Lead with the human label so the user knows which wallet without decoding the address. A flip naturally renders as close + Started-trade (the state machine already emits close+open).
src/tracker/
state.py ← vendored VERBATIM from hyperdash live/state.py (apply_fill + PositionState + LiveEvent)
resolve.py ← resolve_deltas + perp_coins_from_meta + seed_state_from_row (pure parts of listener.py)
book.py ← InMemoryBook: dict[(addr,coin)→PositionState] + leverage cache; ingest()=get/apply/set; seed()=silent install
enrich.py ← clearinghouseState → build_position → seed + leverage cache (watchlist-add + reconcile)
hl_client.py ← vendored VERBATIM (async /info client, transient retry)
retry.py ← vendored VERBATIM (backoff/jitter)
listener.py ← trimmed Listener: connection/heartbeat/allMids/_handle_trades → book.ingest → notifier; NO Redis/Postgres
notifier.py ← push sink + message formatting
watchlist.py ← in-memory {address: label}, add/delete/rename
bot.py ← settings UX; on /add triggers enrich.seed BEFORE admitting to the filter
app.py ← asyncio TaskGroup(connection loop, optional reconcile, bot)
tests/ ← port test_live_state.py + resolve_deltas tests; add cold-start test (seeded day-old long → next fill = ADD not OPEN)
Reuse verified against the sibling repo: state.py verbatim; resolve_deltas/perp_coins_from_meta/seed_state_from_row/connection loop/heartbeat/_update_marks lifted; hl_client.py+retry.py verbatim; build_position for leverage. Only the clearly-separable Redis/Postgres layer is stripped — store.py's orchestration collapses to ~10 lines of dict get/apply/set.
Corrections from adversarial re-verification of the load-bearing claims (folded in above):
trades.users = [buyer, seller]is documented, but the docs do not state the position-delta interpretation ("+sz/−sz") — that is a sound inference, not a doc guarantee. A buy can reduce an existing short rather than "grow" a position. Maker/taker is a separate axis exposed viacrossedonWsFill, not by array position.- The 10-unique-user cap is verbatim, but "market subs don't count" is an inference from the "user-specific" scoping (those streams take no
userparam). Market subs still count toward the separate 1000-subscription per-IP cap. startPositionsemantics are confirmed but inferred from JSON examples (the GitBook gives no prose definition; onlydircarries an official "for frontend display" comment). Parse as a signed Decimal (never float — values like10659.65434798lose precision). Edge case: a reducing fill executed exactly at average entry realizesclosedPnl == 0, so don't treatclosedPnl != 0as the sole reduce test.- Info reads are unauthenticated and exempt from the address (USDC-traded) limit, but still subject to the IP 1200 weight/min budget (≤600
clearinghouseState/min on one IP). isSnapshotbackfill behavior applies touserFills/userFundings(time-series).webData2is NOT anisSnapshothistory feed — it's a full account-state push; handle by state-replacement. The snapshot is "can be ignored," i.e. recommended dedupe, not a hard normative MUST.
Design-level residual risks: (a) resolve_deltas depends on the empirically-verified [buyer, seller] ordering — a single point of semantic failure; re-verify on a live socket before shipping. (b) Firehose book drift from a missed trades message (fixed by Graft 1 on a small list, else eventually-consistent reconcile). (c) Boot/seed race window (bounded; narrow with buffer-then-apply). (d) Restart collapses a multi-add leg to a single leg at current entryPx (fine for notifications, not for avg-cost analytics). (e) No dedup by default → a WS reconnect can double-notify; add an in-memory recently-seen tid ring buffer. (f) Notification spam from an active wallet → consider a per-(wallet,coin) debounce.
- Build the firehose-only path first — it is correct at any watchlist size and reuses the most proven code. Ship open+add; leave the one-line reduce/close dispatch hooks.
- Make the pre-seed mandatory and ordered (seed → admit). This is the entire correctness of the pre-existing-position requirement.
- Add the
tidring buffer for reconnect idempotency from day one (cheap, in-memory, high-value). - Re-verify
[buyer, seller]on a live socket before shipping. - Defer the two grafts behind a flag; only worth it if the list stays ≤10 and you want authoritative per-fill cross-check / push leverage.
- Hand to
/python-expertwith the module layout above once the open questions (§ below) are resolved.
- Delivery channel — Telegram bot (matches screenshots) vs an abstracted sink (Telegram/Discord/ntfy/webhook)?
- Watchlist persistence vs "store nothing" — a tiny config file/TOML for
{address: label}(configuration, survives restart) vs purely in-memory re-entered each boot? - Which events notify — open+add only (your two examples), or also reduce/close/flip with realized PnL?
- Watchlist size & growth — firmly ≤10 (enable the per-user grafts) or could grow to dozens/hundreds (pure firehose, skip grafts)?
- Spot vs perps — perps-only (all confirmed API facts are perp) or also spot fills?
- Leverage freshness tolerance — best-effort/last-confirmed acceptable, or exact-per-notification (forces
webData2graft or per-event REST)?
Retrieval: three parallel research agents mapped the Info HTTP API, WebSocket API, and rate-limit/auth posture against the official Hyperliquid GitBook (fetched 2026-07-01), cross-referenced with Chainstack/QuickNode mirrors for field schemas. A synthesis workflow then (a) ran five independent adversarial skeptics that each attempted to refute a load-bearing claim against the primary docs, and (b) ran a three-proposal design panel scored by a high-effort judge that verified reuse claims against the hyperdash-crawl source. Reusable implementation facts (the live-verified [buyer, seller] convention, the apply_fill state machine, the silent seed_positions primitive, build_position's leverage extraction) were confirmed by reading the sibling repo directly. All numeric limits, the [buyer, seller] ordering, startPosition semantics, and isSnapshot behavior are quoted from primary docs in the Bibliography.
Primary (official Hyperliquid docs, fetched 2026-07-01):
- Info endpoint
- Perpetuals > Info endpoint
- Spot > Info endpoint
- WebSocket
- WebSocket > Subscriptions
- WebSocket > Post requests
- WebSocket > Timeouts and heartbeats
- Rate limits and user limits
- API overview
- hyperliquid-python-sdk (official)
Secondary (mirror providers, for field schemas): 11. Chainstack — userFills reference 12. QuickNode — webData2 13. QuickNode — userRateLimit 14. OneKey — rate-limit best practices
Internal:
15. hyperdash-crawl — live-verified trades listener + apply_fill state machine ([buyer, seller] verified on live socket 2026-06-16).
{ "assetPositions": [{ "position": { "coin": "ETH", "szi": "0.0335", // SIGNED size: >0 long, <0 short; zero-size omitted "entryPx": "2986.3", "positionValue": "100.02765", "unrealizedPnl": "-0.0134", "returnOnEquity": "-0.0026789", "leverage": { "type": "isolated", "value": 20, "rawUsd": "-95.059824" }, // ← LEVERAGE "liquidationPx": "2866.26936529", "marginUsed": "4.967826", "maxLeverage": 50, "cumFunding": { "allTime": "514.08", "sinceOpen": "0.0", "sinceChange": "0.0" } }, "type": "oneWay" }], "marginSummary": { "accountValue":"13109.48", "totalMarginUsed":"4.97", "totalNtlPos":"100.03", "totalRawUsd":"13009.45" }, "crossMarginSummary": { "accountValue":"13104.51", "totalMarginUsed":"0.0", "totalNtlPos":"0.0", "totalRawUsd":"13104.51" }, "crossMaintenanceMarginUsed": "0.0", "withdrawable": "13104.51", "time": 1708622398623 }