Liquidity Docs

Market Data

Real-time quotes, historical OHLCV, order book depth, and data feeds for stocks, crypto, and private securities

Liquidity.io provides market data across all asset classes -- public equities, crypto, private securities, pre-IPO, fixed income, commodities, and forex. Data is available via REST polling, Server-Sent Events (SSE), and WebSocket.

Asset Universe

Market RailCategoriesExamplesData Source
PublicStocks, Fixed Income, Commodities, ForexAAPL, TSLA, SPY, GLDMulti-broker feed, on-chain oracle
PrivatePrivates, Pre-IPOSPACEX-PRE, STRIPE-PREInternal ATS
DigitalCryptoBTC, ETH, SOLBitGo Prime, DEX

List Available Assets

GET /v1/assets?marketRail={rail}&category={category}&tradeable=true
ParamTypeValues
marketRailstringpublic, private, digital
categorystringstocks, crypto, privates, pre-ipo, fixed-income, commodities, forex
tradeablebooleanFilter to tradeable assets only
searchstringFull-text search by symbol or name

Response:

{
  "data": [
    {
      "id": "AAPL",
      "symbol": "AAPL",
      "name": "Apple Inc. Common Stock",
      "type": "stocks",
      "exchange": "NASDAQ",
      "status": "APPROVED",
      "price": 249.93,
      "change": -4.30,
      "changesPercentage": -1.69,
      "image": "https://cdn.liquidity.io/assets/AAPL.png"
    },
    {
      "id": "BTC",
      "symbol": "BTC",
      "name": "Bitcoin",
      "type": "crypto",
      "exchange": null,
      "status": "APPROVED",
      "price": 83421.50,
      "change": 1250.00,
      "changesPercentage": 1.52,
      "image": "https://cdn.liquidity.io/assets/BTC.png"
    }
  ],
  "message": "ok"
}

Real-Time Quotes

REST Polling

Poll the quote endpoint for the latest price data. Recommended interval: 5 seconds.

GET /v1/assets/{id}/quote

Response:

{
  "assetId": "AAPL",
  "last": 249.93,
  "open": 252.61,
  "high": 254.91,
  "low": 249.01,
  "prevClose": 254.23,
  "change": -4.30,
  "changePercent": -1.69,
  "volume": 979956,
  "timestamp": "2026-03-19T00:34:44Z"
}

SSE (Primary Real-Time Channel)

SSE is the primary real-time protocol. It is simpler than WebSocket, works through proxies and load balancers, and reconnects automatically on failure.

GET /api/realtime?subscribe=quote:AAPL,quote:BTC,quote:ETH
Authorization: Bearer {iam_access_token}
Accept: text/event-stream

Events:

event: quote
data: {"assetId":"AAPL","last":249.93,"bid":249.87,"ask":250.01,"volume":979956,"timestamp":"2026-03-19T00:34:44Z"}

WebSocket (Legacy)

WebSocket is supported for backwards compatibility. New integrations should use SSE.

wss://api.{env}.liquidity.io/ws

Subscribe to trades:

{
  "type": "subscribe",
  "channel": "trades",
  "symbol": "BTC-USD"
}

Order Book Depth

REST Polling

Poll the order book endpoint for current bid/ask depth. Recommended interval: 3 seconds.

GET /v1/assets/{id}/book

Response:

{
  "assetId": "AAPL",
  "bids": [
    { "price": 239.87, "size": 100 },
    { "price": 239.50, "size": 250 }
  ],
  "asks": [
    { "price": 265.40, "size": 100 },
    { "price": 265.75, "size": 150 }
  ],
  "timestamp": "2026-03-19T00:34:45Z"
}

SSE Book Updates

GET /api/realtime?subscribe=book:AAPL
event: book
data: {"assetId":"AAPL","bids":[{"price":249.87,"size":100}],"asks":[{"price":250.01,"size":100}],"timestamp":"2026-03-19T00:34:45Z"}

WebSocket Book (DEX)

For the on-chain DEX, the WebSocket provides incremental order book updates:

{
  "type": "subscribe",
  "channel": "orderbook",
  "symbol": "BTC-USDT",
  "depth": 20
}

You receive a full snapshot first, followed by incremental updates. A size of 0 means the price level has been removed.


Historical Data (OHLCV)

Chart Endpoint

GET /v1/assets/{id}/chart?range={range}&interval={interval}
ParamValues
range1d, 5d, 1m, 3m, 6m, 1y, 5y
interval1m, 5m, 15m, 1h, 1d

Response:

{
  "data": [
    {
      "time": 1773820800000,
      "open": 255.00,
      "high": 255.01,
      "low": 255.00,
      "close": 255.01,
      "volume": 1084
    },
    {
      "time": 1773824400000,
      "open": 255.01,
      "high": 255.50,
      "low": 254.90,
      "close": 255.45,
      "volume": 2340
    }
  ]
}

Range and Interval Combinations

RangeRecommended IntervalsMax Data Points
1d1m, 5m~390 (1m)
5d5m, 15m~390 (5m)
1m15m, 1h~480 (15m)
3m1h, 1d~540 (1h)
6m1h, 1d~126 (1d)
1y1d~252 (1d)
5y1d~1260 (1d)

Aggregated Market Data

Multi-Venue Orderbook

The @liquidityio/trading SDK aggregates order books across venues for best-execution analysis:

import { Client, Config, NativeVenueConfig, CcxtConfig } from '@liquidityio/trading';

const config = new Config()
  .withNative('liquidity', NativeVenueConfig.liquidDex('https://api.liquidity.io/v1'))
  .withCcxt('binance', CcxtConfig.create('binance').withCredentials('key', 'secret'))
  .withSmartRouting(true);

const client = new Client(config);
await client.connect();

// Aggregated orderbook across all connected venues
const aggBook = await client.aggregatedOrderbook('BTC-USDC');

// Best prices across all venues
const bestBid = aggBook.bestBid();
const bestAsk = aggBook.bestAsk();
console.log(`Best bid: ${bestBid?.price} on ${bestBid?.venue}`);
console.log(`Best ask: ${bestAsk?.price} on ${bestAsk?.venue}`);

// Aggregated depth at each price level
const bids = aggBook.aggregatedBids();
const asks = aggBook.aggregatedAsks();
for (const level of bids.slice(0, 5)) {
  console.log(`Bid ${level.price}: ${level.quantity} total`);
}

// Find best venue for a specific order size
const bestBuy = aggBook.bestVenueBuy(new Decimal('1.0'));
console.log(`Best venue to buy 1 BTC: ${bestBuy?.venue} at ${bestBuy?.price}`);

Multi-Venue Ticker

// Get ticker from all venues for a symbol
const tickers = await client.tickers('BTC-USDC');
for (const t of tickers) {
  console.log(`${t.venue}: bid=${t.bid} ask=${t.ask} last=${t.last} vol=${t.volume24h}`);
}

// Get ticker from a specific venue
const binanceTicker = await client.ticker('BTC-USDC', 'binance');

Data Schemas

Quote Schema

FieldTypeDescription
assetIdstringAsset identifier
lastnumberLast traded price
opennumberOpening price (current session)
highnumberSession high
lownumberSession low
prevClosenumberPrevious session close
changenumberPrice change from previous close
changePercentnumberPercentage change from previous close
volumenumberTrading volume (shares or units)
timestampstringISO 8601 timestamp

OHLCV Schema

FieldTypeDescription
timenumberUnix timestamp in milliseconds
opennumberOpening price for the interval
highnumberHighest price in the interval
lownumberLowest price in the interval
closenumberClosing price for the interval
volumenumberVolume traded in the interval

Trade Schema

FieldTypeDescription
tradeIdstringUnique trade identifier
assetIdstringAsset identifier
pricenumberExecution price
sizenumberTrade size
sidestringbuy or sell (taker side)
timestampstringISO 8601 timestamp

Book Level Schema

FieldTypeDescription
pricenumberPrice level
sizenumberTotal quantity at this price level

Code Examples

TypeScript -- Subscribe to Real-Time Quotes

const BASE_URL = 'https://api.liquidity.io';

function subscribeToQuotes(token: string, assets: string[]) {
  const subscriptions = assets.map(a => `quote:${a}`).join(',');
  const url = `${BASE_URL}/api/realtime?subscribe=${subscriptions}`;

  const eventSource = new EventSource(url, {
    headers: { 'Authorization': `Bearer ${token}` },
  });

  eventSource.addEventListener('quote', (event) => {
    const quote = JSON.parse(event.data);
    console.log(
      `${quote.assetId}: $${quote.last} ` +
      `(${quote.changePercent >= 0 ? '+' : ''}${quote.changePercent}%) ` +
      `vol=${quote.volume}`
    );
  });

  eventSource.onerror = () => {
    console.error('SSE error, EventSource will reconnect automatically');
  };

  return eventSource;
}

// Subscribe to AAPL, BTC, and ETH quotes
const es = subscribeToQuotes(accessToken, ['AAPL', 'BTC', 'ETH']);

// Clean up
// es.close();

TypeScript -- Fetch Historical OHLCV

async function fetchOHLCV(
  assetId: string,
  range: string,
  interval: string,
  token: string,
): Promise<{ time: number; open: number; high: number; low: number; close: number; volume: number }[]> {
  const url = `${BASE_URL}/v1/assets/${assetId}/chart?range=${range}&interval=${interval}`;
  const response = await fetch(url, {
    headers: { 'Authorization': `Bearer ${token}` },
  });

  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${response.statusText}`);
  }

  const json = await response.json();
  return json.data;
}

// Fetch 1-day chart with 5-minute candles
const candles = await fetchOHLCV('AAPL', '1d', '5m', accessToken);
for (const c of candles) {
  console.log(
    `${new Date(c.time).toISOString()} O=${c.open} H=${c.high} L=${c.low} C=${c.close} V=${c.volume}`
  );
}

Python -- Fetch Quotes and Historical Data

import asyncio
import aiohttp
from datetime import datetime

BASE_URL = "https://api.liquidity.io"

async def get_quote(session: aiohttp.ClientSession, asset_id: str, token: str) -> dict:
    url = f"{BASE_URL}/v1/assets/{asset_id}/quote"
    headers = {"Authorization": f"Bearer {token}"}
    async with session.get(url, headers=headers) as resp:
        resp.raise_for_status()
        return await resp.json()

async def get_ohlcv(
    session: aiohttp.ClientSession,
    asset_id: str,
    range_: str,
    interval: str,
    token: str,
) -> list[dict]:
    url = f"{BASE_URL}/v1/assets/{asset_id}/chart?range={range_}&interval={interval}"
    headers = {"Authorization": f"Bearer {token}"}
    async with session.get(url, headers=headers) as resp:
        resp.raise_for_status()
        data = await resp.json()
        return data["data"]

async def get_book(session: aiohttp.ClientSession, asset_id: str, token: str) -> dict:
    url = f"{BASE_URL}/v1/assets/{asset_id}/book"
    headers = {"Authorization": f"Bearer {token}"}
    async with session.get(url, headers=headers) as resp:
        resp.raise_for_status()
        return await resp.json()

async def main():
    async with aiohttp.ClientSession() as session:
        token = "your_access_token"

        # Real-time quote
        quote = await get_quote(session, "AAPL", token)
        print(f"AAPL: ${quote['last']} ({quote['changePercent']:+.2f}%)")

        # Historical data
        candles = await get_ohlcv(session, "AAPL", "1d", "5m", token)
        for c in candles[-5:]:  # Last 5 candles
            ts = datetime.fromtimestamp(c["time"] / 1000).strftime("%H:%M")
            print(f"  {ts} O={c['open']:.2f} H={c['high']:.2f} L={c['low']:.2f} C={c['close']:.2f}")

        # Order book
        book = await get_book(session, "AAPL", token)
        print(f"\nBook: {len(book['bids'])} bids, {len(book['asks'])} asks")
        if book["bids"]:
            print(f"  Best bid: {book['bids'][0]['price']} x {book['bids'][0]['size']}")
        if book["asks"]:
            print(f"  Best ask: {book['asks'][0]['price']} x {book['asks'][0]['size']}")

asyncio.run(main())

Python -- SSE Streaming with sseclient

import json
import sseclient
import requests

def stream_quotes(token: str, assets: list[str]):
    subs = ",".join(f"quote:{a}" for a in assets)
    url = f"{BASE_URL}/api/realtime?subscribe={subs}"
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "text/event-stream",
    }

    response = requests.get(url, headers=headers, stream=True)
    client = sseclient.SSEClient(response)

    for event in client.events():
        if event.event == "quote":
            data = json.loads(event.data)
            print(f"{data['assetId']}: ${data['last']} vol={data['volume']}")

# stream_quotes(token, ["AAPL", "BTC", "ETH"])

Rate Limits

Endpoint TypeLimit
Public market data (/v1/assets/*)100 requests/minute
Authenticated endpoints300 requests/minute
SSE connections per user5
WebSocket connections per user5
Subscriptions per connection50

Rate limit headers are included in all REST responses:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1710807360

When the limit is exceeded, the API returns 429 Too Many Requests with error code RATE_LIMIT_EXCEEDED.


Polling Intervals

If real-time channels (SSE, WebSocket) are unavailable, use REST polling with these recommended intervals:

DataEndpointInterval
QuoteGET /v1/assets/{id}/quote5 seconds
Order bookGET /v1/assets/{id}/book3 seconds
Order statusGET /v1/orders/{id}5 seconds
Chart dataGET /v1/assets/{id}/chart60 seconds

On this page