Skip to Content

Reading Data

This page covers every way to read Drift state in your app — from the high-level AuthorityDrift caches (what drift-ui-template uses) to the raw Data API REST endpoints.

Account data via AuthorityDrift

Once AuthorityDrift is subscribed (see setup), user account data flows through the userAccountCache as EnhancedAccountData objects. Each object contains pre-computed positions, orders, balances, and margin info for a single subaccount.

Get the active account

import { UserAccountCache, EnhancedAccountData } from "@drift-labs/common"; const accountKey = UserAccountCache.getUserAccountKey(subAccountId, authority); const account: EnhancedAccountData = userAccountLookup[accountKey];

EnhancedAccountData contains:

FieldTypeWhat it gives you
subAccountIdnumberSubaccount index
authorityPublicKeyWallet that owns this account
namestringUser-assigned account name
poolIdnumberPool the account belongs to
openPerpPositionsPerpPositionInfo[]Active perp positions with PnL, liquidation price, funding
openOrdersUISerializableOrder[]Open orders with price, size, type, flags
spotBalancesSpotBalanceInfo[]Spot token balances per market
marginInfoAccountMarginInfoNet USD value, leverage, health

Positions

account.openPerpPositions is an array of PerpPositionInfo objects. Each position includes everything you need for a positions table:

import { PerpPositionInfo, ENUM_UTILS, TRADING_UTILS, MarketId } from "@drift-labs/common"; import { PositionDirection } from "@drift-labs/sdk"; for (const position of account.openPerpPositions) { const isLong = ENUM_UTILS.match(position.direction, PositionDirection.LONG); position.marketIndex; // market index position.baseSize.prettyPrint(); // "1.5" SOL position.notionalSize.toNotional(); // "$150.00" position.entryPrice.toNotional(); // "$100.00" position.liquidationPrice.toNotional(); // "$85.00" // PnL breakdown position.positionPnl.markBased.positionNotionalPnl; // BigNum, unrealized PnL position.positionPnl.markBased.positionPnlPercentage; // number, e.g. 12.5 position.feesAndFundingPnl; // BigNum, cumulative fees + funding position.costBasis; // BigNum position.quoteBreakEvenAmount; // BigNum // Settlement position.totalUnsettledPnl; // BigNum, unsettled PnL position.totalClaimablePnl; // BigNum, claimable now position.totalSettledPnl; // BigNum, already settled }

Use TRADING_UTILS.getMarketTickSizeDecimals(driftClient, marketId) to determine the right number of decimal places for price display.

Open orders

account.openOrders is an array of UISerializableOrder objects:

import { UISerializableOrder, COMMON_UI_UTILS, TRADING_UTILS, ENUM_UTILS } from "@drift-labs/common"; import { PositionDirection } from "@drift-labs/sdk"; for (const order of account.openOrders) { order.orderId; order.marketIndex; order.direction; // PositionDirection enum order.price; // BigNum, limit price (zero for market orders) order.triggerPrice; // BigNum, trigger price for stop/take-profit order.baseAssetAmount; // BigNum, total size order.baseAssetAmountFilled; // BigNum, filled so far order.oraclePriceOffset; // BN, offset from oracle for oracle orders order.reduceOnly; // boolean order.postOnly; // boolean order.immediateOrCancel; // boolean // Human-readable order type label const label = COMMON_UI_UTILS.getUIOrderTypeFromSdkOrderType( order.orderType, order.triggerCondition, order.direction, order.oraclePriceOffset, ).label; // e.g. "Limit", "Stop Market", "Oracle Limit" // Check if order covers the entire position const isEntirePosition = TRADING_UTILS.isEntirePositionOrder(order.baseAssetAmount); }

Spot balances and collateral

account.spotBalances contains a SpotBalanceInfo entry for each spot market the user has a balance in:

for (const balance of account.spotBalances) { balance.marketIndex; balance.baseBalance; // BigNum, token amount in market precision }

For total account collateral, use marginInfo:

account.marginInfo.netUsdValue.toNotional(); // "$1,234.56"

Market data via AuthorityDrift

Oracle and mark prices

After subscribing, AuthorityDrift exposes price caches and emits updates via callbacks:

// One-time read from cache const oraclePrices = drift.oraclePriceCache; // Record<MarketKey, OraclePriceData> const markPrices = drift.markPriceCache; // Record<MarketKey, MarkPriceData> // Continuous updates drift.onOraclePricesUpdate((lookup) => { /* OraclePriceLookup */ }); drift.onMarkPricesUpdate((lookup) => { /* MarkPriceLookup */ });

Each MarkPriceData entry contains markPrice, bestBid, bestAsk, and lastUpdateSlot (all BN values).

In React, use useOraclePriceStore from @drift-labs/react:

import { useOraclePriceStore } from "@drift-labs/react"; import { MarketId } from "@drift-labs/common"; const priceData = useOraclePriceStore((s) => s.getMarketPriceData(MarketId.createPerpMarket(0)) );

Orderbook

AuthorityDrift manages an L2 orderbook via DLOB websocket. Read the current snapshot and subscribe to updates:

import { L2WithOracleAndMarketData, DEFAULT_ORDERBOOK_GROUPING } from "@drift-labs/common"; const currentBook: L2WithOracleAndMarketData = drift.orderbookCache; // currentBook.bids, currentBook.asks, currentBook.bestBidPrice, currentBook.bestAskPrice const subscription = drift.onOrderbookUpdate((newBook) => { // L2WithOracleAndMarketData with updated bids/asks }); // Change price grouping drift.orderbookManager.updateSubscription({ marketId: MarketId.createPerpMarket(0), grouping: 10, // OrderbookGrouping multiplier }); // Cleanup subscription.unsubscribe();

For lower-level orderbook access (REST snapshots, raw websocket), see Orderbook + DLOB websocket.

Candle charts

CandleClient from @drift-labs/common fetches historical OHLCV data and streams live updates:

import { CandleClient, MarketId, UIEnv, JsonCandle } from "@drift-labs/common"; const candleClient = new CandleClient(); const env = UIEnv.createMainnet(); // Fetch historical candles const candles: JsonCandle[] = await candleClient.fetch({ env, marketId: MarketId.createPerpMarket(0), resolution: "15", // CandleResolution: "1", "5", "15", "60", "240", "1440" fromTs: Math.floor(Date.now() / 1000) - 86400, toTs: Math.floor(Date.now() / 1000), }); // Each candle: { ts, fillOpen, fillHigh, fillLow, fillClose, baseVolume } // Subscribe to live updates const key = "sol-perp-15m"; await candleClient.subscribe({ env, marketId: MarketId.createPerpMarket(0), resolution: "15" }, key); candleClient.on(key, "candle-update", (candle: JsonCandle) => { // Update your chart with the new/updated candle }); // Cleanup candleClient.unsubscribe(key);

Data API (REST)

The Data API provides historical and aggregate data via REST endpoints. No authentication required. Use this for dashboards, analytics, or any non-SDK integration.

Market stats

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

GET https://data.api.drift.trade/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" } ]

This is the best single endpoint for building a markets overview or dashboard.

Funding rates

Returns funding rate history for a specific market.

GET https://data.api.drift.trade/fundingRates?symbol=SOL-PERP

Response shape:

[ { "ts": 1700000000, "symbol": "SOL-PERP", "marketIndex": 0, "fundingRate": 0.00012, "oraclePrice": 123.45, "markPrice": 123.50 } ]

Trades

Returns recent trades for a market.

GET https://data.api.drift.trade/trades?symbol=SOL-PERP&limit=100

Query parameters:

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

Response shape:

[ { "ts": 1700000000, "marketIndex": 0, "marketType": "perp", "filler": "...", "taker": "...", "maker": "...", "takerOrderId": 123, "makerOrderId": 456, "baseAssetAmountFilled": 1000000000, "quoteAssetAmountFilled": 123450000, "takerFee": 50000, "makerFee": -25000, "action": "fill", "actionExplanation": "orderFilledWithMatch" } ]

Note: Amounts are in protocol precision (base: 1e9, quote: 1e6). Divide accordingly for human-readable values.

Fetching data in code

const marketsRes = await fetch("https://data.api.drift.trade/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.api.drift.trade/trades?symbol=SOL-PERP&limit=100" ); const trades = await tradesRes.json(); const fundingRes = await fetch( "https://data.api.drift.trade/fundingRates?symbol=SOL-PERP" ); const fundingRates = await fundingRes.json();
Function fetchReference ↗
TypeScript docs unavailable for fetch.

Live data via websockets

The Data API also supports websocket subscriptions for live candles and trades:

const ws = new WebSocket("wss://data.api.drift.trade/ws"); ws.onopen = () => { ws.send(JSON.stringify({ type: "subscribe", symbol: "SOL-PERP", resolution: "1" })); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log("Candle update:", data); }; ws.onerror = (error) => { console.error("WebSocket error:", error); };
Class WebSocketReference ↗
TypeScript docs unavailable for WebSocket.

DLOB + Swift for live order flow

For real-time orderbook and order flow, Drift uses separate services:

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