Skip to main content
Use this page when your integration needs market params, public market metadata, live mark prices, L2 orderbooks, or commodity/equity calendar state. The exchange cache should be the default source for market params in both SDKs. It resolves the PerpAssetMap, global exchange accounts, market accounts, spline accounts, fee params, risk params, and public market metadata such as logos. Use REST to bootstrap, then let the SDK keep a local cache fresh instead of repeatedly polling the same params.

Exchange Cache

In TypeScript, configure createPhoenixClient(...) with exchange metadata streaming, wait for client.exchange.ready(), then read markets from the cache.
import { createPhoenixClient } from "@ellipsis-labs/rise";

const client = createPhoenixClient({
  apiUrl: "https://perp-api.phoenix.trade",
  rpcUrl: "https://api.mainnet-beta.solana.com",
  ws: { connectMode: "eager" },
  exchangeMetadata: { stream: true },
});

const snapshot = await client.exchange.ready();
const sol = client.exchange.market("SOL");
const solMetadata = client.exchange.marketMetadata("SOL");

console.log(snapshot.markets.length);
console.log(sol?.assetId, sol?.tickSize, sol?.baseLotsDecimals);
console.log(solMetadata?.logoUri);

const unsubscribe = client.exchange.onEvent((event) => {
  if (event.type === "marketUpdated") {
    console.log(event.symbol, event.change);
  }
});
The TypeScript order-packet builders and client.ixs instruction builders read from client.exchange. The Rust PhoenixTxBuilder reads from PhoenixMetadata. Keep those caches warm before building orders so price, tick, base-lot, account, and risk-param conversions use the same market view as the rest of your app. References:

Market Stats

Market stats carry live mark price, mid price, oracle price, funding, volume, and open interest. Subscribe for current values; do not poll market stats in a tight loop.
const controller = new AbortController();

for await (const update of client.streams!.marketStats("SOL", controller.signal)) {
  console.log(
    update.symbol,
    update.stats.markPrice,
    update.stats.currentFundingRate
  );
}
In Rust, metadata.apply_market_stats(&stats) updates the cached mark price inputs used by margin calculations. The TypeScript stream adapter converts the raw WebSocket payload into camelCase. timestamp is a bigint in TypeScript and is shown as a string below for display:
{
  "symbol": "SOL",
  "stats": {
    "timestamp": "1719868800000",
    "openInterest": 1000.0,
    "markPrice": 150.1,
    "oraclePrice": 150.0,
    "prevDayMarkPrice": 148.7,
    "dayVolumeUsd": 2500000.0,
    "dayVolumeBase": 16655.1,
    "currentFundingRate": 0.0000125,
    "eightHourFundingRate": 0.0001,
    "annualizedFundingRate": 0.1095
  }
}
For raw WebSocket payloads, see WebSocket market stats. For historical stats, use the REST route GET /v1/market/{symbol}/stats. References:

L2 Orderbook

Use the L2 stream when you need current book levels. Keep one subscription per symbol and fan out internally to your UI or strategy modules.
const controller = new AbortController();

for await (const update of client.streams!.l2Book("SOL", controller.signal)) {
  console.log(update.symbol, update.bids[0], update.asks[0]);
}
Reference: Rust L2 book example.

API Polling

Polling is appropriate for startup snapshots, periodic reconciliation, or services that do not need live updates. It is not a substitute for WebSocket streams in a trading UI or market-making service.
const snapshot = await client.api.exchange().getSnapshot();
const markets = await client.api.markets().getMarkets();
const sol = await client.api.markets().getMarket("SOL");

console.log(snapshot.markets.length, markets.length, sol.symbol);
If you need to poll exchange params, poll on a slow interval and replace the local cache atomically. In TypeScript, prefer exchangeMetadata: { stream: true } when WebSocket access is available. In Rust, rebuild PhoenixMetadata from a fresh get_exchange() snapshot after reconnects or scheduled reconciliation, then continue applying market stats.

Market Metadata And Calendars

The exchange cache includes public market metadata used by apps, including labels and logo URIs where available. Treat these fields as display metadata; trading logic should use the market params and risk params from the cache. Commodity and equity markets can have session windows, after-hours bounds, reopen windows, and stale index behavior. The exchange cache exposes lightweight calendar metadata with the rest of the market snapshot so your UI can show the market’s current calendar source and the next known transition without another API call.
await client.exchange.ready();

const sol = client.exchange.market("SOL");
const publicMetadata = client.exchange.marketMetadata("SOL");
const cachedCalendar = sol?.metadata?.calendar ?? publicMetadata?.calendar;

console.log(publicMetadata?.logoUri);
console.log(cachedCalendar?.id);
console.log(cachedCalendar?.calendarUri);
console.log(cachedCalendar?.nextMarketTransitionUtc);
Use the API clients when you need the full weekly schedule, date overrides, or current/next open state computed by the API.
const calendar = await client.api.markets().getMarketCalendar("SOL");
const nextTransition =
  await client.api.markets().getNextMarketCalendarTransition("SOL");
const nextCommodityTransition =
  await client.api.markets().getNextCommodityMarketTransition();
const commodityCalendar =
  await client.api.markets().getCommodityMarketCalendar();

console.log(calendar.marketCalendarId, calendar.calendar?.weeklySchedule);
console.log(nextTransition.currentState, nextTransition.utcNextTransition);
console.log(nextCommodityTransition.market, nextCommodityTransition.nextMarketState);
console.log(commodityCalendar.calendar.weeklySchedule);

if (calendar.marketCalendarId) {
  const calendarRecord =
    await client.api.markets().getMarketCalendarById(calendar.marketCalendarId);
  console.log(calendarRecord.calendar?.weeklySchedule);
}
TypeScript also exposes getMarketCalendarById(id) when you start from the calendar id stored in exchange metadata. Rust currently exposes the symbol and commodity calendar helpers. API reference: Related Phoenix docs: