Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/blockchain/Solana/solana-dextrades.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2003,18 +2003,18 @@ Check data here on [DEXrabbit](https://dexrabbit.bitquery.io/solana/pair/9Fv7n7H

Three things about `DEXTradeByTokens` aggregates that are easy to miss:

- **`PriceInUSD` groups by side currency.** Any `Trade { PriceInUSD(minimum: ...) }` or `PriceInUSD(maximum: ...)` selector adds `Trade.Side.Currency.MintAddress` to the grouping key, even if you do not select it, because USD conversion is computed per side currency. A minute in which WSOL traded against 797 different tokens returns 797 rows, one per side currency. The rows do not overlap and `count` stays additive. `Trade { Price(...) }` behaves the same way but groups by the side currency's `Decimals`. To get one row per token and interval, filter `Trade.Side.Currency.MintAddress` to the quote currencies you care about (for WSOL: USDC and USDT; for other tokens add WSOL) and select `Trade { Side { Currency { MintAddress } } }` so the grain is visible. If more than one quote currency traded, you get one row per quote currency; combine them on your side.
- **Use `before`, not `till`, for the end of a candle.** `till` is inclusive. On the pre-aggregated path (below) `Block.Time` is stored at minute resolution, so `till: "…T02:35:00Z"` matches every trade in the 02:35 minute. `since` + `before` gives the half-open interval `[since, end)` on every path.
- **Two backing tables on `dataset: realtime`.** A query that selects only `Block.Time(interval: …)`, `Trade.Price…` measures and `count` is served from a per-minute pre-aggregated table. Adding `Block { Slot(minimum: Block_Slot) }` or `uniq(of: Transaction_Signature)` switches it to the raw trades. The two can differ: the pre-aggregated table does not return the raw fill extremes, while the raw path returns the true highest and lowest fill, including dust-sized trades. Pick the path that matches your definition and keep it fixed. `dataset: combined` serves the price selectors but not `Slot(minimum/maximum)` or `uniq` on this cube.
- **On the pre-aggregated path, price measures are grouped by side currency.** By default (`aggregates: yes`) a `DEXTradeByTokens` query on `dataset: realtime` that selects only `Block.Time(interval: …)`, price measures and `count` is served from a per-minute pre-aggregated table. On that table any `Trade { PriceInUSD(minimum: ...) }` or `PriceInUSD(maximum: ...)` selector adds `Trade.Side.Currency.MintAddress` to the grouping key even if you do not select it, because USD conversion is stored per side currency (`Trade { Price(...) }` groups by the side currency's `Decimals` instead). A minute in which WSOL traded against 797 different tokens returns 797 rows. The rows do not overlap and `count` stays additive. This table also stores `Block.Time` at minute resolution and its extremes are not the raw fill extremes.
- **`aggregates: no` selects the raw trades.** `Solana(dataset: realtime, aggregates: no)` serves the same query from the raw fills: one row per token and interval across all side currencies, exact highest and lowest fill (dust trades included), `Block.Time` at second resolution, and `Block.Slot(minimum/maximum: ...)` and `uniq(...)` available. Selecting one of those raw-only fields switches to the raw path even without the flag. The raw path is not available on `dataset: combined`, and it keeps a much shorter window than the pre-aggregated table (hours to about a day, against roughly 7 days), so collect promptly.
- **Use `before`, not `till`, for the end of a candle.** `till` is inclusive. On the pre-aggregated path `till: "…T02:35:00Z"` matches every trade in the 02:35 minute; on the raw path it adds the fills at second 02:35:00. `since` + `before` gives the half-open interval `[since, end)` on both.

One candle per token and minute from raw trades, half-open interval:
For a price series, pin the side currency to the quote currencies you care about (for WSOL: USDC and USDT; for other tokens add WSOL), because unpriced side currencies push the all-side USD extremes to absurd values. Count activity separately, across all side currencies, with a `count`-only query. One candle per token, minute and quote currency from raw trades, half-open interval:

<details>
<summary>Click to expand GraphQL query</summary>

```graphql
query SolMinuteOHLC($token: String!, $quotes: [String!]!, $since: DateTime!, $end: DateTime!) {
Solana(dataset: realtime) {
Solana(dataset: realtime, aggregates: no) {
DEXTradeByTokens(
where: {
Block: {Time: {since: $since, before: $end}}
Expand Down Expand Up @@ -2043,15 +2043,15 @@ query SolMinuteOHLC($token: String!, $quotes: [String!]!, $since: DateTime!, $en
}
{
"token": "So11111111111111111111111111111111111111112",
"quotes": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCdmmxZ2o8"],
"quotes": ["EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB"],
"since": "2026-09-10T02:34:00Z",
"end": "2026-09-10T02:35:00Z"
}
```

</details>

`count` is the number of DEX fills in which the token is one side; a routed swap with several fills counts each of them. `open` and `close` pick one fill from the first and last slot; when several fills share that slot the choice is not defined by transaction order. For a strict first and last, query the raw trades of those two slots and sort by `Block.Slot`, `Transaction.Index`, `Trade.Index`. If you want a single all-venue candle without choosing quote currencies, use the [Trading API](/docs/trading/crypto-price-api/) `Trading { Tokens }` cube (price index, about 30 days of history).
Selecting `Side { Currency }` gives one row per quote currency; fills add up across those rows, but `uniq` of transaction signatures does not, because a routed transaction can fill against both quotes. Count transactions with one `uniq` over the union filter. `count` is the number of DEX fills in which the token is one side; a routed swap with several fills counts each of them. `open` and `close` pick one fill from the first and last slot; when several fills share that slot the choice is not defined by transaction order. For a strict first and last, query the raw trades of those two slots and sort by `Block.Slot`, `Transaction.Index`, `Trade.Index` (add `Instruction.Index` and `Instruction.InternalSeqNumber` as further tie-breakers). If you want a single all-venue candle without choosing quote currencies, use the [Trading API](/docs/trading/crypto-price-api/) `Trading { Tokens }` cube (price index, about 30 days of history).

## Solana Real time prices from multiple Markets

Expand Down
Loading