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)
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 want | Use |
|---|---|
| The price of one specific token | Pairs + Ranking: { Position: { eq: 1 } } |
| A firehose of every token on a chain, or one chain-wide number per token | Tokens |
| One number for an asset across all chains (BTC, ETH) | Currencies |
| A specific pool you already know the address of | Pairs + Pool: { Address: ... } — see the note below |
Market.Address is not the pool on EVMPool.Address is the portable pool key and is the right filter on every chain. Market.Address
means different things per chain:
| Chain family | Market.Address | Market.Program | Pool.Address |
|---|---|---|---|
| EVM and Tron | the protocol factory, and an empty string for singleton protocols (uniswap_v4, balancer_v2, curve, fluid_dex) | the pool contract | the pool |
| Solana | the pool | the DEX program | the 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
Positionalways exceeds the row count. Positioncan be0, paired withWeight0.
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 tokensFiltering 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
{
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-duplicateIsQuotedInUsd 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:
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:
Token_Id, not Token_AddressNative 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.
{
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
Tokensprice 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 theIsQuotedInUsdfield 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.Addressfrom 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.AddresswithNetwork(orMarket: { NetworkBid: { is: "bid:eth" } }for lower latency), and addBlock: { 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 byorderBy: { descending: Ranking_Weight }. Rankingdoes not exist onCurrencies. It is available onTrades,Pairs, andTokensonly.
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 useVolume.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 theVolume.Basethat 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. Iffalse, 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.
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.