Skip to main content

Pairs Cube

What it is​

The Pairs cube is one row per pool, quote token and interval: a base token traded against a quote token on one DEX market. Each row carries the pool's OHLC, volume, liquidity and its Ranking in the token's price blend.

It answers two questions: what does this token trade at on its main market, and which pools price it. Pairs is Tokens plus venue and quote identity; there are no Tokens-only fields. If you do not need Market, Pool or QuoteToken, query Tokens instead, it is the cheaper shape for the same price and volume data.

How to get it​

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 holding the largest share of the token's liquidity in the blend, after the staleness discount. It is a single-market price, not a value blended across every pool the token trades in.

Filters that matter:

  • Token: Token: { Address: ..., Network: ... } or Token: { Id: { is: "bid:<chain>:<address>" } }.
  • Rank: Ranking: { Position: { eq: 1 } } for the top market, in: [1, 2, 3] for the main venues.
  • Interval: Interval: { Time: { Duration: { eq: 60 } } }. Durations are 1, 3, 5, 10, 30, 60, 300, 900, 1800 and 3600 seconds.
  • Denomination: Price: { IsQuotedInUsd: true }. Rank 1 selects the market, not the currency the price is quoted in.
  • A known pool: Pool: { Address: ... } works on every chain. See the Market.Address pitfall below before filtering by market.

Change query to subscription for a stream. The same rows are published on Kafka as trading.prices; see Kafka: trading.prices.

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: ... }

Why the top market, and not the blended token price​

The Tokens cube reports one price per token per chain. That price is a liquidity-weighted blend of every pool where the token is the base asset (see Price Index Algorithm). It is the right answer for a single chain-wide number, and for a token whose liquidity sits in one deep pool it agrees closely with the rank-1 price.

Fragmented tokens behave differently. Thin pools get little weight because they hold little liquidity, but a pool with a large reserve that is stale, or whose reserve is only estimated from volume, can outweigh the pool where the trading actually happens. The blend can then sit at a price nobody is trading at.

Filtering Pairs to Ranking.Position = 1 avoids that. You get one market's quote, the one the index trusts most, which is the closest thing to an executable price.

How it is derived​

Quote token choice​

Every pair has a base and a quote; the price is quote units per 1 base. Stablecoins win the quote slot, then native tokens. The full rules are in Breaking Down Price Streams in Detail.

A pool's price is the latest trade price, normalised to USD when the quote token has a USD price:

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

Ranking: how Position and Weight behave​

Ranking.Weight is the pool's share of the token's liquidity, after the staleness discount, so the weights of a token's pools sum to 1.

Liquidity.Usd is the measured reserve where one is known (Source real or real_stale), a launch-curve balance (migration), or an estimate from the last hour's decay-weighted volume (volume). For volume pools weight therefore still follows volume. See How liquidity is calculated.

Ranking.Position orders a token's pools by Weight descending. It is a competition rank, 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. RankingDetail.Verdict is "" on such rows: not ranked in this batch.

Normalise before treating weights as shares. Weight is in [0, 1] per row and the per-token sum is centred on 1.0, but it is not guaranteed to equal it; sums above and below 1 both occur. Pools that did not trade in the interval hold weight but have no Pairs row, so the rows you fetch cover only part of the sum.

Weight and Position are recomputed every batch from the current liquidity state, not from the row's own interval. A rank-1 row can report less Volume.Usd for its interval than a lower-ranked row does. On BSC on 2026-10-22, the rank-1 WBNB pool carried 2.9 % of hourly volume and 50.6 % of liquidity; the rank-2 pool carried 78 % of volume.

Verdict gating applies before weighting. Pools the blend rejected (outlier, ineligible, no_price, retired) keep a row and a Position; filter on RankingDetail.Verdict: { is: "priced" } for the pools whose price the token actually uses. See RankingDetail.

History before 2026-10-19 is volume-weighted

Since 2026-10-19 the blend is liquidity-weighted. Rows before that date in the 30-day history are volume-weighted: Liquidity fields are 0 on them and Weight is the pool's share of decay-weighted volume.

Reading Ranking.Weight​

Treat Weight as a confidence signal on the blended price:

  • Weight close to 1. One pool holds essentially all the liquidity. The blended Tokens price and the rank-1 price will be nearly identical, so either works.
  • Low weight. Liquidity is spread across many pools and the blend mixes all of them. This is where the rank-1 price and the blended price diverge, and the rank-1 price is the one you want.

Fields​

FieldTypeMeaning
Token { Address Id Symbol Name Network NetworkBid IsNative TokenId Did }String / BooleanThe base token being priced. Id is bid:<chain>:<address>; Address is empty for native assets.
QuoteToken { ... }same as TokenThe quote token of this row.
Currency { Id Name Symbol } / QuoteCurrency { ... }StringThe cross-chain currency each token belongs to, for example bid:bitcoin for WBTC.
Market { Address Id Name Network NetworkBid Program Protocol ProtocolFamily }StringThe DEX market. Address is the factory on EVM and Tron and the pool on Solana; Program is the pool contract on EVM and the DEX program on Solana.
Pool { Address Id }StringAddress is the portable pool key on every chain. Id is empty except on singleton-contract protocols (Uniswap v4, PancakeSwap Infinity), where it carries the pool identity.
Block { Date Time Timestamp }String / DateTime / StringTime of the last update in the interval.
Interval { Time { Start End Duration } }DateTime / DateTime / IntThe bar. Duration in seconds.
Price.Ohlc { Open High Low Close }FloatOHLC for the interval, from trades with known USD values.
Price.Average { Estimate Mean SimpleMoving WeightedSimpleMoving ExponentialMoving }FloatAverages over the interval and a 5-entry moving window. Estimate is the price Supply.MarketCap and FullyDilutedValuationUsd are built from.
Price.IsQuotedInUsdBooleantrue: prices in USD. false: prices in quote-token units.
PoolPrice { Price Ohlc { Open High Low Close } Average { … } Source UpdatedAt }Float / String / DateTimeThe liquidity pool's own price from its curve after the last swap, next to the traded Price. null with Source: "" when the pool reports no price. See PoolPrice fields.
Volume.BaseFloatBase token amount traded in the interval.
Volume.QuoteFloatSum of quote-token amounts. Not USD, even for stablecoin quotes; use Volume.Usd.
Volume.UsdFloatTrade volume in USD.
Volume.BaseAttributedToUsdFloatPart of Volume.Base traded against quote tokens with a known USD price. Used for the USD average price.
Liquidity { Usd Source RealShare BaseReserve QuoteReserve QuoteReserveUsd DepthUsd NetQuoteUsd UpdatedAt }Float / String / DateTimeThe pool's balance of the row's quote token, valued in USD, plus how it was measured. See Liquidity fields.
Ranking { Position Weight }Int / FloatThe pool's rank and liquidity share in the token's blend, above.
RankingDetail { Verdict StaleMultiplier }String / FloatWhy the pool got that rank. See RankingDetail.
Supply { CirculatingSupply TotalSupply MaxSupply MarketCap FullyDilutedValuationUsd }FloatCurrency-level figures, repeated on every row of the asset. See Supply fields.

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.

Liquidity.Usd values the quote leg only and can be an estimate. Read Liquidity, RankingDetail and LeadingPool fields before ranking pools by it. For full pool state use the chain-level DEXPools cube, or a cloud export for historical depth.

Examples​

What is a token's latest price on 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.
  • Ranking.Weight says how much of the token's liquidity that market holds.

How do I stream the top-market 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.
  • The rank-1 pool can change mid-stream. Key your state on Market.Address from each message.

How do I get the top-market price for several tokens at once?​

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

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
}
}
}
}
  • Group by Token_Id, not Token_Address: native assets share an empty Token.Address.
  • Widen minutes_ago for tokens whose top market trades rarely.

How do I get candles for one pool I know the address of?​

{
Trading {
Pairs(
where: {Market: {Network: {is: "Solana"}}, Pool: {Address: {is: "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2"}}, Interval: {Time: {Duration: {eq: 300}}}, Price: {IsQuotedInUsd: true}}
limit: {count: 10}
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
}
}
}
}

  • The address is the Raydium AMM v4 SOL/USDC pool. Filter by Pool.Address, which is the pool on every chain.
  • One row per quote token of the pool; add QuoteToken { Symbol } if the pool has more than one.

Pitfalls​

  • Position: { eq: 1 } silently drops tokens. Rank 1 returns only tokens whose top market traded in that interval. A token whose rank-1 market was quiet is omitted, a few percent of tokens per interval, varying by chain. Widen the interval or fall back to Tokens for coverage.
  • Rank 1 does not imply USD. Always pair the rank filter with Price: { IsQuotedInUsd: true }, or read IsQuotedInUsd on each row.
  • The top market can change. Ranking is recomputed every batch as liquidity and staleness change, 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.
  • Always scope the query. 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. Chain-wide rank-1 sweeps take a few seconds for a short interval, longer for hour-to-day windows.
  • Price.IsQuotedInUsd selects a denomination, it does not de-duplicate. Markets are not published twice: an unfiltered query returns the USD rendering only, byte-identical to IsQuotedInUsd: true. false re-renders the same rows in quote-token units; only Price.* changes, Volume, Ranking and Supply are identical. Prices are in USD even when the quote token is WSOL, because the index normalises the quote side; see How Pool Prices Are Normalized.
  • Group by Token_Id, not Token_Address. ETH on Ethereum, Arbitrum, Base and Optimism, BNB on BSC and MATIC on Matic all carry "" as Token.Address. Grouping by address collapses them into one row.
  • Want the runner-up markets too? Use Ranking: { Position: { in: [1, 2, 3] } } to compare a token's main venues, or orderBy: { descending: Ranking_Weight }.
  • Ranking does not exist on Currencies. It is available on Trades, Pairs and Tokens only.
  • Market.Address is not the pool on EVM. It is the protocol factory there, and an empty string for singleton protocols (uniswap_v4, balancer_v2, curve, fluid_dex). Filtering an EVM pool by Market: { Address: ... } matches the factory and silently returns a different pool's data. Use Pool.Address.
Chain familyMarket.AddressMarket.ProgramPool.Address
EVM and Tronthe protocol factory, empty for singleton protocolsthe pool contractthe pool
Solanathe poolthe DEX programthe pool
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.