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:
| Field | Type | What it gives you |
|---|---|---|
subAccountId | number | Subaccount index |
authority | PublicKey | Wallet that owns this account |
name | string | User-assigned account name |
poolId | number | Pool the account belongs to |
openPerpPositions | PerpPositionInfo[] | Active perp positions with PnL, liquidation price, funding |
openOrders | UISerializableOrder[] | Open orders with price, size, type, flags |
spotBalances | SpotBalanceInfo[] | Spot token balances per market |
marginInfo | AccountMarginInfo | Net 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.
- Base URL:
https://data.api.drift.trade - Data API playground
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/marketsResponse 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-PERPResponse 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=100Query 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 ↗
Function fetchReference ↗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 ↗
Class WebSocketReference ↗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.