Skip to Content

Reading Data

This page covers every way to read Velocity state in your app — from the subscribed VelocityClient/User caches, to the stateless VelocityCore decoders, to the Data API REST endpoints.

Account data via VelocityClient / User

Once velocityClient is subscribed (see setup), account data is available synchronously from the User wrapper for the active (or any) subaccount.

Get the active account

const user = velocityClient.getUser(); // active subaccount const otherUser = velocityClient.getUser(1); // subaccount 1 const userAccount = user.getUserAccount(); // raw decoded UserAccount userAccount.authority; userAccount.subAccountId; userAccount.name; // number[] — decode with `decodeName()`

Positions

import { decodeName } from "@velocity-exchange/sdk"; for (const position of userAccount.perpPositions) { if (position.baseAssetAmount.isZero()) continue; position.marketIndex; position.baseAssetAmount; // BASE_PRECISION (1e9), signed: + long, - short position.quoteAssetAmount; // QUOTE_PRECISION (1e6) position.quoteEntryAmount; position.quoteBreakEvenAmount; position.lastCumulativeFundingRate; position.openOrders; position.openBids; position.openAsks; } // Higher-level PnL/health accessors live on `User` — see PnL & Risk const unrealizedPnl = user.getUnrealizedPNL(true, 0); // withFunding=true, market 0 const health = user.getHealth(); // 0-100

See PnL & Risk for getTotalCollateral, getMarginRequirement, getFreeCollateral, getLeverage, and isolated-position variants.

Open orders

for (const order of userAccount.orders) { if (order.status !== 1 /* OrderStatus.Open */) continue; order.orderId; order.marketIndex; order.direction; order.price; // PRICE_PRECISION (1e6), 0 for market orders order.triggerPrice; order.baseAssetAmount; order.baseAssetAmountFilled; order.oraclePriceOffset; // BN (i64) — always wrap in `new BN(...)` when constructing order.reduceOnly; order.bitFlags; // OrderBitFlag bitmask: postOnly / reduceOnly / HasBuilder / IsIsolatedPosition }

Spot balances and collateral

for (const position of userAccount.spotPositions) { if (position.scaledBalance.isZero()) continue; position.marketIndex; position.balanceType; // { deposit: {} } | { borrow: {} } position.scaledBalance; // SPOT_BALANCE_PRECISION (1e9); multiply by the market's cumulative interest for token amount } const totalCollateral = user.getTotalCollateral(); // BN, QUOTE_PRECISION (1e6)

Decoding accounts without a subscription: VelocityCore

For read-only tooling (indexers, one-off scripts, serverless functions) where a fully subscribed VelocityClient is overkill, VelocityCore decodes accounts directly from an RPC fetch or a raw buffer:

import { VelocityCore } from "@velocity-exchange/sdk"; import { Connection } from "@solana/web3.js"; const connection = new Connection("<RPC_URL>"); // Fetch + decode a User account in one call, no subscription required const userAccount = await VelocityCore.fetchUserAccount(connection, userAccountPublicKey); // Or decode a buffer you already have (e.g. from a websocket account notification) const decoded = VelocityCore.decodeUserAccount(rawAccountBuffer); // PDA helpers (state, user, perp/spot market, vaults) are re-exported statically const userPda = VelocityCore.pdas.getUserAccountPublicKeySync(programId, authority, 0);

For account types beyond User, build a coder directly against the bundled IDL:

import { VelocityCore } from "@velocity-exchange/sdk"; const coder = VelocityCore.coder(); // defaults to VelocityCore.defaultIdl() const perpMarket = coder.accounts.decode("perpMarket", rawAccountBuffer);

IDL account names are camelCase in Anchor 1.0. Any string-keyed coder call must use 'perpMarket', 'spotMarket', 'user', 'userStats', 'state' — not the PascalCase Drift used with Anchor 0.29 ('PerpMarket', 'SpotMarket', …). Passing the old casing throws or silently returns undefined depending on the coder version.

MarketStatus discriminants shifted. Velocity’s surviving MarketStatus variants are Initialized (0), Active (1), ReduceOnly (2), Settlement (3), Delisted (4) — Drift had ReduceOnly (6), Settlement (7), Delisted (8). A raw/cached decoder built against Drift’s numbering will silently misread these. Always decode against the current sdk/src/idl/velocity.json, never a hardcoded enum copied from a Drift integration. PerpMarketAccount is also a different size (1304 bytes vs Drift’s 1216) — see Account Model for the full layout diff.

Market data

Oracle and mark prices

const oraclePriceData = velocityClient.getMMOracleDataForPerpMarket(0); // MMOraclePriceData const perpMarket = velocityClient.getPerpMarketAccount(0); perpMarket.marketStats; // mark/oracle TWAPs live here, not on the top-level PerpMarket perpMarket.oracle; // top-level now (moved off amm.* in the AMM decoupling) perpMarket.oracleSource;

Orderbook (DLOB)

For a live L2/L3 orderbook, subscribe to the DLOB directly with the SDK’s SlotSubscriber / OrderSubscriber / DLOBSubscriber classes — see DLOB for the full setup sequence and Orderbook + DLOB websocket for the hosted DLOB server’s REST/websocket API if you’d rather not run your own DLOB.

Data API (REST)

The Data API provides historical and aggregate data via REST endpoints, without running your own indexer. Use it for dashboards, analytics, or any non-SDK integration.

Provisional endpoint. Velocity’s hosted Data API host is not yet finalized. The examples below use data.velocity.exchange as a placeholder pattern — confirm the real host before shipping against it. See Data API and the migration report’s open questions.

Market stats

Returns aggregate stats for all markets — volume, open interest, funding rate, oracle price, and market status.

GET https://data.velocity.exchange/stats/markets

Response shape:

[ { "marketIndex": 0, "symbol": "SOL-PERP", "marketType": "perp", "oraclePrice": 123.456, "volume24h": 50000000.0, "openInterest": 12000000.0, "fundingRate": 0.00012, "fundingRate24hAvg": 0.00010, "status": "active" } ]

Funding rates

GET https://data.velocity.exchange/fundingRates?symbol=SOL-PERP

Trades

GET https://data.velocity.exchange/trades?symbol=SOL-PERP&limit=100

Query parameters:

  • symbol — Market symbol (required)
  • limit — Max results (default varies, max typically 1000)
  • pageIndex — For pagination

Note: Amounts are in protocol precision (base: 1e9, quote: 1e6). Divide accordingly for human-readable values. See the Data API glossary for the full column reference, and note that spot-fulfillment-related columns no longer apply (spot DLOB trading and external fulfillment are both removed on Velocity).

Fetching data in code

const marketsRes = await fetch("https://data.velocity.exchange/stats/markets"); const markets = await marketsRes.json(); for (const m of markets) { console.log(`${m.symbol}: price=${m.oraclePrice} OI=${m.openInterest} funding=${m.fundingRate}`); } const tradesRes = await fetch( "https://data.velocity.exchange/trades?symbol=SOL-PERP&limit=100" ); const trades = await tradesRes.json();
Function fetchReference ↗
TypeScript docs unavailable for fetch.

DLOB + Swift for live order flow

For real-time orderbook and order flow, Velocity uses separate services (both hostnames below are provisional pending final infra naming):

  • DLOB server (provisional: https://dlob.velocity.exchange) — Orderbook snapshots and streaming. See Orderbook + DLOB websocket.
  • Swift server (provisional: https://swift.velocity.exchange) — Signed message orders for fast execution. See Swift.
Last updated on