> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dune.com/llms.txt
> Use this file to discover all available pages before exploring further.

# prediction_markets.ohlcv_hourly

> Cross-venue hourly OHLCV bars, one row per market-hour with Yes-side prices in probability space [0, 1], volume and trade counts.

export const TableSample = ({tableName, tableSchema}) => <>
    <div className="hidden dark:block">
      <iframe src={`https://dune.com/embeds/3419983/5785629?table_schema_t6f0df=${tableSchema}&table_name_t6f0df=${tableName}&darkMode=true`} style={{
  width: '100%',
  height: '500px',
  border: 'none',
  marginTop: '10px'
}} />
    </div>
    <div className="dark:hidden">
      <iframe src={`https://dune.com/embeds/3419983/5785629?table_schema_t6f0df=${tableSchema}&table_name_t6f0df=${tableName}`} style={{
  width: '100%',
  height: '500px',
  border: 'none',
  marginTop: '10px'
}} />
    </div>
  </>;

The `prediction_markets.ohlcv_hourly` table provides hourly candles per market across Polymarket and Kalshi, including Polymarket Combos (multi-leg parlays, keyed by the combo condition ID). Grain: one row per `(venue, hour, market_id)`, the same grain as `prediction_markets.markets`. Prices are the **probability of Yes** in `[0, 1]`; the probability of No is `1 - close`. Volumes cover the whole market with each trade counted once. Hours without trades are carried forward as a flat bar with zero volume and flagged via `is_forward_filled`.

Market names and attributes are not repeated here; join [`prediction_markets.markets`](/data-catalog/curated/prediction-markets/prediction_markets/markets) on `(venue, market_id)`. `category` is carried because nearly every query filters on it.

**Settlement.** A settled market's last candle closes at its settlement value: `close` pins to the Yes-side payout (`1`/`0`; `0.5` for a void; the exact fraction for scalar settlements), `high`/`low` widen to include it, `open` keeps the last traded price. Forward-fill stops at that candle on both venues; candles with real trades after settlement keep their actual prices.

<Note>
  Polymarket collapses to one Yes-side row per market-hour. When an hour has only a No-side bar, the Yes bar is derived as `1 - P(No)` with high and low swapped. Combo volume comes from the Yes bar only, since every combo match has its taker fill on the Yes token.
</Note>

## Table Schema

| Column | Type | Description |
| - | - | - |
| `venue` | `VARCHAR` | `polymarket` or `kalshi` |
| `block_month` | `DATE` | First day of the calendar month of `hour` (partition key) |
| `hour` | `TIMESTAMP` | Start of the hour the candle covers, UTC |
| `market_id` | `VARCHAR` | Market the candle belongs to: Polymarket `condition_id` (combo condition ID for Combos), Kalshi ticker. Joins `prediction_markets.markets` on `(venue, market_id)` |
| `category` | `VARCHAR` | Unified topic category of the market, same values as `prediction_markets.markets`: `sports`, `crypto`, `politics`, `finance`, `technology`, `culture`, `weather`, `world`, `health`, `other`, `mixed` |
| `open` | `DOUBLE` | Probability of Yes at the first trade of the hour |
| `high` | `DOUBLE` | Highest probability of Yes traded in the hour |
| `low` | `DOUBLE` | Lowest probability of Yes traded in the hour |
| `close` | `DOUBLE` | Probability of Yes at the last trade of the hour. On a settled market's final candle this is the settlement value |
| `vwap` | `DOUBLE` | Volume-weighted average probability of Yes over the hour. NULL when nothing traded |
| `volume_contracts` | `DOUBLE` | Contracts traded in the hour across both sides of the market |
| `volume_usd` | `DOUBLE` | Cash traded in the hour across both sides of the market, in USD. Use `volume_contracts` for a side-independent measure |
| `trade_count` | `BIGINT` | Trades in the hour across both sides of the market |
| `market_outcome` | `VARCHAR` | The market's state as of this candle: `unresolved` until the settlement candle, then `yes`, `no`, `void` (refund) or `scalar` (fractional payout) from that candle onward, the same vocabulary as `prediction_markets.markets.resolved_outcome`. Historical candles never change; for the current state use `prediction_markets.markets` |
| `is_forward_filled` | `BOOLEAN` | TRUE when nothing traded in the hour and the candle repeats the previous close with zero volume |
| `_updated_at` | `TIMESTAMP` | When this row was last written by the pipeline. Unchanged rows keep their stamp |

## Table sample

<TableSample tableSchema="prediction_markets" tableName="ohlcv_hourly" />

## Query performance

`block_month` is the partition key. Always include a `block_month` or `hour` filter.

## Example queries

```sql theme={null}
-- Daily VWAP across both venues for a single category, last 30 days
SELECT
  venue,
  DATE_TRUNC('day', hour) AS day,
  AVG(vwap) AS avg_daily_vwap,
  SUM(volume_usd) AS volume_usd
FROM prediction_markets.ohlcv_hourly
WHERE block_month >= DATE_TRUNC('month', CURRENT_DATE) - INTERVAL '1' MONTH
  AND hour >= NOW() - INTERVAL '30' DAY
  AND category = 'politics'
  AND vwap IS NOT NULL
GROUP BY 1, 2
ORDER BY 1, 2
```

```sql theme={null}
-- Hourly price path of one market, with its name from the dimension
SELECT
  o.hour,
  m.question,
  o.open,
  o.high,
  o.low,
  o.close,
  o.volume_usd,
  o.market_outcome
FROM prediction_markets.ohlcv_hourly o
JOIN prediction_markets.markets m
  ON m.venue = o.venue
  AND m.market_id = o.market_id
WHERE o.venue = 'kalshi'
  AND o.market_id = 'KXNHLGAME-26MAY03MINCOL-MIN'
  AND o.block_month >= DATE '2026-05-01'
ORDER BY o.hour
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.