Skip to main content

Pairs Cube

The Pairs cube provides trading data for a base token traded against a quote token on a particular DEX or protocol.

Getting the Most Accurate Token Price (Rank 1)

Querying the price of a specific token? Use this pattern

Query the Pairs cube with Ranking: { Position: { eq: 1 } }. This returns the token's price on its top market — the pool currently contributing the most volume to that token's price — rather than a value blended across every pool the token trades in.

Why the top market, and not the blended token price

The Tokens cube reports one price per token per chain, computed as a volume-weighted blend of every pool where the token is the base asset (see Price Index Algorithm). That blend is the right answer when you want a single chain-wide number, and for a token whose liquidity sits in one deep pool the blended price and the top-market price agree closely.

Fragmented tokens behave differently. When the same token trades across many pools — one primary pool plus a long tail of thin ones — every pool contributes to the blend in proportion to its decay-weighted volume. Thin pools quote wider, move on small trades, and can sit at prices the primary market has already left. Their share of the blend pulls the reported number away from the price you could actually trade at.

Filtering Pairs to Ranking.Position = 1 avoids that: you get the quote from the single market carrying the most volume for that token, which is the closest thing to an executable price.

You wantUse
The price of one specific tokenPairs + Ranking: { Position: { eq: 1 } }
A firehose of every token on a chain, or one chain-wide number per tokenTokens
One number for an asset across all chains (BTC, ETH)Currencies
A specific pool you already know the address ofPairs + Pool: { Address: ... } — see the note below
Market.Address is not the pool on EVM

Pool.Address is the portable pool key and is the right filter on every chain. Market.Address means different things per chain:

Chain familyMarket.AddressMarket.ProgramPool.Address
EVM and Tronthe protocol factory, and an empty string for singleton protocols (uniswap_v4, balancer_v2, curve, fluid_dex)the pool contractthe pool
Solanathe poolthe DEX programthe pool

Filtering an EVM pool by Market: { Address: ... } therefore matches the factory and silently returns a different pool's data.

What Pairs adds over Tokens

Pairs is Tokens plus venue and quote identity — there are no Tokens-only field paths. If you do not need Market, Pool or QuoteToken, query Tokens: it is the cheaper shape for the same price and volume data.

Pairs carries no liquidity, reserve or TVL data — there is no such field and nothing in its filter surface. For pool depth, use the chain-level DEXPools cube, or a cloud export for historical depth.

Row fan-out

One row per (Market.Address, Pool.Address, Pool.Id, QuoteToken.Id) per token per interval — not one row per market. A token quoted against two assets on the same market produces two rows.

Pool.Id is empty on Solana, Tron and classic factory-per-pool AMMs. It is populated on singleton-contract protocols — Uniswap v4 and PancakeSwap Infinity — where it carries the pool identity that Market.Address cannot, because there Market.Address is empty and Pool.Address is the shared PoolManager.

Ranking: how Position and Weight behave

Ranking.Position is a competition rank by Ranking.Weight descending — not a dense index:

  • Ties occur, and are followed by a skipped value.
  • Additional gaps appear that ties alone do not explain, so the highest Position always exceeds the row count.
  • Position can be 0, paired with Weight 0.

Ranking.Weight is in [0, 1] per row, and the per-token sum is centred on 1.0 but is not guaranteed to equal it — sums well above and below 1 both occur. Normalise before treating weights as shares; do not assume the blend is an identity.

Position: { eq: 1 } silently drops tokens

Filtering to rank 1 returns only tokens whose top market traded in that interval. A token whose rank-1 market was quiet is omitted entirely — a few percent of tokens per interval, varying by chain. For coverage, widen the interval or fall back to Tokens.

Chain-wide rank-1 sweeps are fast — a few seconds for a short interval, longer for hour-to-day windows returning tens of thousands of tokens.

Latest price of a token from its top market

Run query ➤

{
Trading {
Pairs(
where: {
Token: {
Address: { is: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" }
Network: { is: "Solana" }
}
Ranking: { Position: { eq: 1 } }
Interval: { Time: { Duration: { eq: 60 } } }
Price: { IsQuotedInUsd: true }
}
limit: { count: 1 }
orderBy: { descending: Block_Time }
) {
Token {
Symbol
Address
}
QuoteToken {
Symbol
}
Market {
Protocol
Address
Network
}
Price {
IsQuotedInUsd
Ohlc {
Open
High
Low
Close
}
}
Ranking {
Position
Weight
}
Volume {
Usd
}
Block {
Time
}
}
}
}

Price.Ohlc.Close is the token's latest price on its top market.

Price.IsQuotedInUsd selects a denomination — it does not de-duplicate

IsQuotedInUsd is a denomination mode, not a row multiplier. Markets are not published twice: an unfiltered query returns the USD rendering only, byte-identical to IsQuotedInUsd: true. You cannot retrieve both renderings in one result set, even by asking for both explicitly with any:.

Setting it to false re-renders the same markets and intervals in quote-token units: only the Price.* fields change, while Volume, Ranking and Supply are identical between modes.

You therefore do not need this filter to avoid duplicates — there are none. Set it to false only when you deliberately want the price in quote-token terms. Prices are in USD even when the quote token is WSOL or another non-stable asset, because the index normalizes the quote side — see How Pool Prices Are Normalized.

Stream the same price

Change query to subscription and drop limit/orderBy to receive top-market updates as they happen:

Run Stream ➤

subscription {
Trading {
Pairs(
where: {
Token: {
Address: { is: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263" }
Network: { is: "Solana" }
}
Ranking: { Position: { eq: 1 } }
Interval: { Time: { Duration: { eq: 1 } } }
Price: { IsQuotedInUsd: true }
}
) {
Token {
Symbol
Address
}
QuoteToken {
Symbol
}
Market {
Protocol
Address
}
Price {
IsQuotedInUsd
Ohlc {
Close
}
}
Ranking {
Position
Weight
}
}
}
}

To stream the top market of every token on a chain, replace the Token.Address filter with Token: { Network: { is: "Solana" } } and keep the rank filter.

Watchlist: top-market price for several tokens

Add limitBy to collapse the result to one current row per token:

Group by Token_Id, not Token_Address

Native assets carry an empty Token.Address — ETH on Ethereum, Arbitrum, Base and Optimism, BNB on BSC and MATIC on Matic all share "". Grouping by Token_Address silently collapses every one of them into a single row. Token_Id is unique per token per network.

Run query ➤

{
Trading {
Pairs(
where: {
Token: {
Address: {
in: [
"DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263"
"So11111111111111111111111111111111111111112"
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
]
}
Network: { is: "Solana" }
}
Ranking: { Position: { eq: 1 } }
Interval: { Time: { Duration: { eq: 60 } } }
Price: { IsQuotedInUsd: true }
Block: { Time: { since_relative: { minutes_ago: 10 } } }
}
limit: { count: 10 }
limitBy: { by: Token_Id, count: 1 }
orderBy: { descending: Block_Time }
) {
Token {
Symbol
Address
}
QuoteToken {
Symbol
}
Market {
Protocol
}
Price {
Ohlc {
Close
}
}
Ranking {
Position
Weight
}
Block {
Time
}
}
}
}

Reading Ranking.Weight

Weight is that market's share of the token's total decay-weighted volume, a float in [0, 1]; weights across all contributing pools sum to 1. Treat it as a confidence signal on the blended price:

  • Weight close to 1 — a single pool drives essentially the whole token price. The blended Tokens price and the rank-1 price will be nearly identical, so either works.
  • Low weight — liquidity is fragmented across many pools and the blended price mixes all of them. This is exactly the case where the rank-1 price and the blended price diverge, and where the rank-1 price is the one you want.

Position and Weight are computed over the rolling 1-hour, decay-weighted window described in the Price Index Algorithm — not over the interval of the row you are reading. A rank-1 row can therefore report less Volume.Usd for its own interval than a lower-ranked row does for another.

Things to know

  • Rank 1 does not imply USD. The rank filter selects the market, not the price denomination — always pair it with Price: { IsQuotedInUsd: true } (or read the IsQuotedInUsd field on each row) so you are not mixing USD and quote-token prices.
  • The top market can change. Ranking is recomputed as volume moves, so a token's rank-1 pool — and its quote token — may flip during a stream. Key your state on Market.Address from each message instead of assuming a fixed pool.
  • Always scope the query. A rank filter is not a substitute for a token filter: an unscoped rank-1 query across a whole chain scans very wide and can time out. Filter by Token.Address with Network (or Market: { NetworkBid: { is: "bid:eth" } } for lower latency), and add Block: { Time: { since_relative: { minutes_ago: N } } } for broad queries.
  • Want the runner-up markets too? Use Ranking: { Position: { in: [1, 2, 3] } } to compare a token's main venues — useful for spread and arbitrage checks. You can also sort by orderBy: { descending: Ranking_Weight }.
  • Ranking does not exist on Currencies. It is available on Trades, Pairs, and Tokens only.

Schema and Fields

{
Trading {
Pairs(
where: {Market: {Network: {is: "Solana"}, Address: {in: ["PAIR ADDRESS HERE"]}}, Interval: {Time: {Duration: {eq: 300}}}, Price: {IsQuotedInUsd: true}}
orderBy: {descendingByField: "Block_Time"}
) {
Market {
Protocol
Program
Network
Name
Address
}
Block {
Date
Time
Timestamp
}
Interval {
Time {
Start
Duration
End
}
}
Volume {
Base
Quote
Usd
}
Supply {
TotalSupply
FullyDilutedValuationUsd
MarketCap
}
Price {
Ohlc {
Close
High
Low
Open
}
IsQuotedInUsd #Are the values in USD or Native
}
}
}
}

  • Volume.Base:
    Total amount of base token traded during the interval.
  • Volume.Quote:
    Sum of quote token amounts traded (e.g. USDT, USDC). For USD-base pairs this is not USD—it is the total in quote token units. For USD amounts use Volume.Usd. (As of March 11 2026, see Price Index Algorithm for details.)
  • Volume.Usd:
    Total trade volume in USD. Use this when you need USD amounts.
  • Volume.BaseAttributedToUsd:
    Portion of the Volume.Base that was traded against quote tokens with known USD prices. Used to accurately calculate average USD price.
  • Price.Ohlc.*:
    OHLC candles (Open, High, Low, Close) for the interval, computed using only trades with known USD values.
  • Price.IsQuotedInUsd:
    Boolean flag indicating if the price values are quoted in USD. If false, the price is in quote token terms.
  • Supply: Currency-level metrics for the asset (not pair- or pool-specific). See Supply fields reference for definitions of each subfield.

A rough pseudo-code of how price is calculated:

if quoteInUsd {
vol.AveragePrice.Price = vol.AveragePrice.Usd / vol.AveragePrice.BaseAttributedToUsd
} else {
vol.AveragePrice.Price = vol.AveragePrice.Quote / vol.AveragePrice.Base
}

For an in-depth breakdown of how quote and base are assigned, see Breaking Down Price Streams in Detail. It is not necessary for basic use.

Build with Bitquery

Ready to run this in production?

Get an API key and run these queries in minutes, or talk to us about plans and enterprise delivery.