Documentation Index
Fetch the complete documentation index at: https://docs.moralis.com/llms.txt
Use this file to discover all available pages before exploring further.
Question it answers
“Give me 1-hour OHLCV candles for pool/pair 0x… — open, high, low, close, volume, and trade count per hour.” Mirrors Moralis GET /pairs/{address}/ohlcv.
Candles are built by aggregating swaps, not reported by an exchange. This recipe is a downstream aggregation on top of the same trade ingest as Swaps by Pair: the sync lands every trade once (USD-enriched in-block), then a candle surface buckets those trades into fixed 1-hour candles per (pool_address, hour). “Price” per fill is the bought-leg (token1) in-block USD price already on the trade (price_usd); volume is sum(abs(notional_usd)) and trades is the fill count.
What you get
One candle row per(pool_address, bucket_start), where bucket_start is the start of a 1-hour window. Only priced trades (a same-block USD price update for the bought leg) contribute:
| Column | Description |
|---|---|
chain_id | Chain the pool lives on |
pool_address | The DEX pair / pool |
bucket_start | Start of the 1-hour candle window |
open | First trade’s price_usd in the bucket (by event_ts, tiebroken by vendor_event_id) |
high | max(price_usd) across the bucket |
low | min(price_usd) across the bucket |
close | Last trade’s price_usd in the bucket |
volume | sum(abs(notional_usd)) — absolute traded USD over the bucket |
trades | Count of priced fills in the bucket |
fact_swaps / swaps) carrying every fill — tx_hash, trader_address, token0/1_address, amount0/1, side, source_kind, protocol, price_usd, notional_usd — so you can drop to the underlying trades whenever you need detail behind a candle.
Source
The trade ingest is identical to Swaps by Pair: two projection branches expand the per-block swap arrays into one row per fill —tokenSwaps (pool fills) · aggregateTokenSwaps (aggregator routes)
Each fill is USD-enriched inline from the same block’s tokenPriceUpdates (reversed so the chronologically-last update wins on duplicate keys) — no separate price join at read time. The candle surface then aggregates these priced fills by hour.
Destination
| Destination | Trade table | Candle surface | Read pattern |
|---|---|---|---|
| ClickHouse (first-class) | fact_swaps | candles (VIEW over candles_agg); candles_exact (reorg-exact) | Prefix scan on (chain_id, pool_address, bucket_start) |
| Postgres | swaps | candles (always-fresh VIEW) + candles_mat (REFRESHable matview) | Index on (pool_address, bucket_start DESC) |
| MySQL | swaps | candles (always-fresh VIEW) | Index on (pool_address, block_timestamp) |
candles is a low-latency accelerator backed by an AggregatingMergeTree that is sign-aware for additive measures, and candles_exact reads fact_swaps FINAL for always-exact OHLC. On Postgres/MySQL the candles VIEW aggregates swaps at read time and is correct the moment a backfill lands.
Full schema
Below are the trade fact table and the candle surfaces this recipe produces. The candle columns are a fixed shape (open/high/low/close/volume/trades); the underlying trade table is the wider starting point — keep the columns you need (see Schema & flexibility). Raw uint256 amounts are stored as text on ClickHouse and NUMERIC(76,0) on Postgres (they exceed standard numeric precision); USD columns are wide decimals so a low-decimals token × price never overflows.
ClickHouse — fact_swaps + candles
ClickHouse — fact_swaps + candles
sign column on fact_swaps drives reorg collapsing. candles is the low-latency accelerator; candles_exact is always reorg-exact (see fidelity gaps). A single-node setup can use the non-replicated engines (CollapsingMergeTree(sign), AggregatingMergeTree) without the replication path.Postgres — swaps + candles
Postgres — swaps + candles
DECIMAL(38,18) for the USD columns and DECIMAL(76,0) for raw amounts, and ships the candles VIEW only. position is the block-level cursor used during backfill. To change the bucket interval, swap date_trunc('hour', …) (and the ClickHouse toStartOfHour / partition expression) for your target window.Example reads
Newest 24 hourly candles for one pool (ClickHouse, fast accelerator):FINAL before aggregating):
candles VIEW reads the same way, keyed on pool_address:
Modes
Shipped defaults: ClickHousehybrid (backfill → realtime), Postgres / MySQL historical (one-shot backfill). For live/reorg-safe ingestion, use ClickHouse — see the overview.
Realtime on Postgres / MySQL is not supported for this shape. The realtime reorg path needs a single-column unique on the block-level position, but trades are array-expanded (many per block), so these tables can only carry a composite unique. Run realtime/hybrid on ClickHouse, where the collapsing log table corrects reorgs per-block and the candle accelerator is sign-aware. The Postgres/MySQL configs are intended for
historical backfill — re-run the backfill (and REFRESH the candle matview) to pick up corrections.Multichain
The recipe is chain-parametrized — point it at any supported EVM chain or Solana, and the candle math is chain-agnostic. On Solana, the samelogIndex can repeat across events in one instruction, so the pool-fill event identity is widened (with token0Address, token1Address, token0Amount) to keep trade rows distinct; the candle surface it produces is identical in shape.
Fidelity gaps
- Fixed 1-hour interval (v1). Moralis’
/pairs/{address}/ohlcvtakes atimeframeparam (1m/5m/1h/1d/…); this recipe ships a single fixed 1-hour bucket. For other intervals, change the bucket expression (toStartOfHour/date_trunc('hour', …)/ the MySQL modulus) to your target window. - Trade-reconstructed, not exchange-reported. Candles are built from on-chain swap fills, so they may differ slightly from a DEX’s own reported OHLC (which can apply off-chain smoothing or a different price reference). No off-chain smoothing is applied.
- Price = bought-leg in-block USD; no carry-forward. A candle only includes trades whose bought-leg token had a same-block
tokenPriceUpdate. Thin/illiquid pools with no in-block price update in an hour produce no candle for that hour (a gap), rather than a flat carry-forward candle. Dense pools (the majority of volume) are unaffected. - ClickHouse
candleshigh/low under reorg. The fast accelerator’shigh/loware monotonic state functions; a reorg−1row cannot retract an extreme, so if a reorg removes an hour’s all-time high/low,candlesmay stay slightly wide until the next canonical trade re-establishes the range. Readcandles_exactwhen post-reorg precision matters.volumeandtradesare sign-weighted and always exact on both surfaces. volumeis absolute traded USD.notional_usdcarries the signed token1 delta (V3/V4 report signed swap amounts — negative when the token leaves the pool), sovolumeusesabs(notional_usd)(×reorg-sign on ClickHouse) — otherwise buy/sell legs cancel and volume goes negative. This is the canonical OHLCV “traded value” definition.- Missing-decimals volume outliers. A handful of exotic tokens arrive with
token1decimals absent/0 (coalesced to 0 in the shared swap transform); their raw amount isn’t decimal-scaled andnotional_usdis wildly inflated, producing an implausibly large candlevolume. OHLC prices are unaffected (they use per-unitprice_usd). Filtervolume < 1e12for a clean volume distribution; a production deployment should source token decimals from a metadata table rather than the in-event field.
Related
Swaps by Pair
The per-trade ingest these candles aggregate — every fill on a pair.
Trading & Charting
The use case OHLCV candles power.

