Esc

    Reference

    Feeds and symbols

    How the oracle names a feed, how a feed ID derives from its symbol, how numbers are encoded, and which feeds and venues exist today.

    A feed is one quantity that the oracle publishes, such as the spot price of BTC in USD. A canonical symbol names each feed. The feed ID is the keccak256 hash of that symbol.

    Canonical symbols

    A symbol has this form:

    text
    <CLASS>.<BASE>/<QUOTE>[.<KIND>]

    The symbol string is the only source of identity. The rules are:

    Part Rule
    CLASS CRYPTO is the only class.
    BASE, QUOTE 1 to 16 characters of A–Z and 0–9, with at least one letter. 1000PEPE is valid. 123 is not.
    KIND Optional. One of the suffixes in the table below. No suffix means a spot price.
    Whole string ASCII, uppercase, no whitespace.
    Suffix Feed kind Exponent
    none Composite spot price −8
    PERP_MARK Composite perpetual mark price −8
    PERP_INDEX Composite perpetual index price −8
    PERP_MID Composite perpetual mid, from the books of the perpetuals −8
    FUNDING_8H Funding rate normalised to 8 hours, as a fraction −9
    OPEN_INTEREST Aggregate open interest, in base units −8

    Valid symbols:

    text
    CRYPTO.BTC/USD                  spot price
    CRYPTO.USDT/USD                 the stablecoin peg
    CRYPTO.BTC/USD.PERP_MARK        perpetual mark price
    CRYPTO.BTC/USD.PERP_INDEX       perpetual index price
    CRYPTO.BTC/USDT.PERP_MID        perpetual mid, from the books of the perpetuals
    CRYPTO.BTC/USD.FUNDING_8H       funding rate over 8 hours
    CRYPTO.1000PEPE/USDT.PERP_MARK  numeric prefix in the asset code

    The parser refuses each of these:

    text
    crypto.btc/usd        lowercase
    CRYPTO.BTC-USD        wrong separator
    BTC/USD               no class
    CRYPTO.BTC/USD.FOO    unknown kind
    EQUITY.AAPL/USD       unknown class
    CRYPTO.123/USD        digits only

    Two implementations that agree on this grammar agree on every feed ID.

    Feed IDs

    A feed ID is 32 bytes:

    text
    feed_id = keccak256(canonical_symbol as ASCII bytes)

    No registry coordinates the feed IDs. Anyone derives the same ID from the same string. The kind suffix is part of the string, so CRYPTO.BTC/USD and CRYPTO.BTC/USD.PERP_MARK have different IDs.

    Symbol Feed ID
    CRYPTO.BTC/USD 0x0523e79c7ed211911a19afaa4def68c896bc72d674bf33c5c64d4d7089e320e2
    CRYPTO.ETH/USD 0x2473e24bc41464f61b79547860ce69c012a19808f3057492fb5f95e22a5e40e4
    CRYPTO.USDT/USD 0x09c19a99408ed93ad59886c676dda3da0d1e3215c8d349a913b290ef81b676d4
    CRYPTO.BTC/USD.PERP_MARK 0xc159655a2f44a71fc9815e636c2b0bd999206a00ba73666124dd11e6eb6a132e
    CRYPTO.BTC/USD.FUNDING_8H 0xc04929eacfbc432a23afbc552de5122b922f2bb7c29bf83d0418aa01498e8d76

    Tip

    Pin the symbol-to-ID mapping for the feeds that you use. Do not trust a mapping that a server gives you. Compute the ID yourself, or check it against this table.

    Numbers

    The oracle never uses floating point for a price.

    Inside a node. The node computes with 128-bit fixed-point numbers at a scale of 10^-12, and rounds halves away from zero. A recorded set of observations therefore replays to the same price, bit for bit, on another machine.

    On the wire. Each value is a mantissa and an exponent: value = mantissa × 10^expo. The node converts once, at publish time, and rounds halves away from zero.

    Field Type Note
    price i64 Mantissa.
    conf u64 Mantissa at the same exponent as price. Never negative.
    expo i32 −8 for prices, −9 for funding rates.

    For example, a price mantissa of 6431250000000 at exponent −8 is 64312.5. A funding rate of 0.0001 (1 bp) at exponent −9 is the mantissa 100000. Funding gets three more digits because it is a small fraction.

    In JSON. Each decimal is a string, and each 64-bit time is a string. A JavaScript number loses precision past 2^53, and a nanosecond timestamp is far larger than that. A resolved price from the SDK looks like this:

    json
    {
      "feed_id": "0x0523…20e2",
      "symbol": "CRYPTO.BTC/USD",
      "status": "ok",
      "price": "86599.95",
      "conf": "19.71359135",
      "nodes": 3,
      "halted_nodes": 0,
      "concerns": [],
      "publish_time_ns": "1791299498663252000",
      "spread_bps": "0"
    }

    The confidence interval

    conf is a symmetric ± band around the price. It is roughly a 1σ estimate of how wrong the price can be. It is not decoration. It is the main signal that a consumer uses to decide whether to trust an update.

    A wide conf is how the oracle says "the markets are dislocated" without a false price and without a halt. Each node computes conf as the widest of three terms:

    • how much the venues disagree;
    • the actual spread of the books;
    • a floor of 1 bp of the price.

    The SDK then makes conf at least half the spread between the nodes. See Aggregation and Trust model.

    USDT is not USD

    Binance, Bybit, OKX, KuCoin, MEXC, Bitget and Gate quote in USDT. Coinbase, Kraken and Bitstamp are the only venues in scope that quote natively in USD. If all three fail, that is a distinct failure class, not "three of ten sources down".

    Bitfinex has USD books, but a Bitfinex dollar is a balance at Bitfinex, and it trades apart from a dollar on Coinbase or Kraken. On 2026-10-25, BTC and ETH cost 12 to 16 bp more in Bitfinex dollars, and Bitfinex's USDT book sat at par while the US venues quoted 0.9987. Bitfinex and Tether are one group. The feeds therefore take only Bitfinex's USDT books, converted through the peg like those of Binance, Bybit, OKX, KuCoin and MEXC.

    CRYPTO.USDT/USD is therefore a feed like any other. The node prices it from the native-USD venues. A /USD feed converts each USDT-quoted source through it:

    text
    usd_price = usdt_price × price of CRYPTO.USDT/USD

    The uncertainty of the peg adds to the uncertainty of the price, in quadrature. A peg that wobbles makes the whole catalogue wider. It does not misprice it silently. On a live run, with the peg at 1.0 bp and the aggregate floor at 1.0 bp, CRYPTO.BTC/USD published 1.414 bp: exactly √2 × 1 bp.

    If the peg feed halts, every feed that depends on it halts too. A USDT number under a /USD symbol would be wrong by the drift of the peg, and nobody would notice.

    The same books are also available without conversion, under a /USDT symbol such as CRYPTO.BTC/USDT. Those feeds carry no peg risk.

    Warning

    CRYPTO.USDT/USD must never come from a venue that quotes in USDT. It would then report 1.0 by construction, on exactly the day that it stops being true. The node config does not check this rule. The operator must follow it.

    Feeds and venues today

    Every node serves the same feeds: the network's feed set, about 240 feeds, which oracle-node init writes into each node's config. GET /v2/feeds on a node lists them, with symbol, feed ID and exponent. GET /v1/catalog on the web proxy lists what the proxy serves.

    Venues

    Venue Wire index Spot Mark Index Funding
    Binance 0 yes yes yes yes, over its own interval
    Bybit 1 yes yes yes yes, over its own interval
    OKX 2 yes yes no yes, over its own interval
    Coinbase 3 yes no no no
    Kraken 4 yes yes yes yes, hourly
    Deribit 5 no yes yes yes, normalised to 8 hours
    Hyperliquid 6 yes yes yes yes, hourly
    Bitfinex 7 yes yes yes yes, every 8 hours
    MEXC 8 yes yes yes yes, over its own interval
    KuCoin 9 yes yes yes yes, over its own interval
    Bitstamp 10 yes no no no
    Bitget 11 yes yes yes yes, over its own interval
    Gate 12 yes yes yes yes, over its own interval
    Lighter 13 no yes yes yes, hourly
    dYdX 14 no yes no yes, hourly

    The wire index is the bit of the venue in the source_bitmap of a price update. The indexes never change. Indexes 15 to 31 are not assigned. Bitstamp quotes natively in USD and names a market in lowercase, such as btcusd; the feeds read its spot books only. Bitget's USDT perpetuals count in coins; its coin-margined ones, such as BTCUSD_CM, count in USD and price in USD, so they feed CRYPTO.BTC/USD.PERP_MARK and the index with Deribit and Kraken Futures. Its interval, next funding time and last settled rate come on the socket. Gate names a market BTC_USDT; its perpetuals count in contracts of quanto_multiplier coins. Lighter's perpetuals are USDC-margined, taken at par like Hyperliquid's, and named by their market number: 1 is BTC and 0 is ETH. Its rates are in percent, which the node turns into fractions. dYdX is read from its indexer: its mark is the oracle price, taken at par in USDC, and its books are thin, so the feeds take its marks only. Hyperliquid quotes in USDC, which the feeds take at par; its index price is the venue's oracle price, and a spot pair is named by its index, such as @142 for BTC/USDC. Bitfinex names Tether UST: tBTCUST is BTC/USDT, and tBTCF0:USTF0 is the Tether-margined BTC perpetual. Its index is the spot price that the venue sends with the mark. Its live funding rate is the premium accrued in the current 8 hours beyond the venue's dead band of ±0.05%; the venue's data shows this rule, but its docs do not state it. KuCoin names BTC XBT on its perpetuals, as in XBTUSDTM, and sizes them in contracts of multiplier coins. Its socket opens with a token from a REST call. The interval of each perpetual, 1, 4 or 8 hours, its next funding time and its last settled rate come over REST once a minute. MEXC's spot socket sends protobuf, decoded with the venue's published schema; its perpetuals, BTC_USDT, count in contracts of contractSize coins, and their interval and last settled rate come over REST once a minute.

    Two markets are deliberately absent:

    • Coinbase perpetuals. They trade on Coinbase International. Its market-data socket needs an API key, a passphrase and an HMAC signature for each subscription. The node has no credential path for ingest, so such a config is a startup error.
    • Binance coin-margined futures. They use a different host with its own contract list. The node refuses them. It does not fall back to the USD-margined host, which would stream a different contract under a name that looks correct.

    The feed set

    The network has four groups of feeds. The registry canister serves the whole set as a signed document, and each node takes a new version while it runs.

    Group Sources Note
    CRYPTO.USDT/USD Coinbase, Kraken spot The peg. Native-USD venues only.
    CRYPTO.<ASSET>/USD, about 75 feeds Coinbase, Kraken and Bitstamp in USD; Binance, Bybit, OKX, Bitfinex, KuCoin, MEXC, Bitget and Gate through the peg; Hyperliquid in USDC at par Spot, for the most traded assets. BTC, ETH and SOL use an impact price.
    CRYPTO.<ASSET>/USDT.PERP_MARK, about 140 feeds Binance, Bybit, OKX, Hyperliquid, Bitfinex, KuCoin, MEXC, Bitget, Gate, Lighter and dYdX perpetuals USDT-margined marks.
    CRYPTO.USDC/USDT, CRYPTO.USDC/USD, 8 /USDC feeds and 6 feeds quoted in BTC or ETH The venues' books with no conversion. CRYPTO.USDC/USD takes Kraken's USD book and the USDT books through the peg For the arbitrage board. A market with $0.1M a day counts, and CRYPTO.BNB/ETH has one source. XRP/BTC and TRX/BTC are left out: at 8 decimals, one step is 6 and 24 bp.

    A few feeds have other shapes: CRYPTO.BTC/USDT and the BTC and ETH PERP_MID feeds come from the books without conversion; the BTC and ETH /USD.PERP_MARK and PERP_INDEX feeds come from Deribit and Kraken Futures, which quote in USD; the two FUNDING_8H feeds come from Deribit alone, on purpose.

    A spot feed takes a venue market only with $1M or more a day, and needs three such markets, so that one quiet venue cannot halt it. A mark feed needs two.

    What is not served

    • OPEN_INTEREST. The symbol is valid, but no feed publishes it yet. The open interest of a perpetual comes with its funding update instead; see Streams.
    • Funding from several venues. Only Deribit publishes a rate that is truly normalised to 8 hours. The other venues publish a rate over their own interval, and the aggregator does not convert between intervals. A median across them mixes numbers that do not compare. See Funding is not normalised.