> ## 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, prices in probability space [0, 1] with 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 OHLCV bars across Polymarket and Kalshi. Grain: one row per `(venue, hour, market_id, outcome)`. Prices are in **probability space \[0, 1]**. Polymarket emits Yes and No bars; Kalshi emits Yes only (No can be derived as `1 - Yes`). Hours without trades carry the previous close forward and are flagged via `is_forward_filled`. Resolved markets are pinned to 1.0 / 0.0 after expiration.

## 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` | Bar timestamp, truncated to the hour                           |
| `market_id`         | `VARCHAR`   | Polymarket `condition_id` / Kalshi `ticker`                    |
| `outcome`           | `VARCHAR`   | Outcome side this bar represents                               |
| `market_name`       | `VARCHAR`   | Market title (denormalized)                                    |
| `category`          | `VARCHAR`   | Unified category enum                                          |
| `category_native`   | `VARCHAR`   | Original upstream category value                               |
| `open`              | `DOUBLE`    | Opening probability of the bar, in `[0, 1]`                    |
| `high`              | `DOUBLE`    | Bar high, in `[0, 1]`                                          |
| `low`               | `DOUBLE`    | Bar low, in `[0, 1]`                                           |
| `close`             | `DOUBLE`    | Closing probability of the bar, in `[0, 1]`                    |
| `vwap`              | `DOUBLE`    | Volume-weighted average price for the bar. NULL when no trades |
| `volume_contracts`  | `DOUBLE`    | Total contracts traded in the hour                             |
| `volume_usd`        | `DOUBLE`    | Total USD notional traded in the hour                          |
| `volume_usd_yes`    | `DOUBLE`    | USD notional traded on the Yes side                            |
| `volume_usd_no`     | `DOUBLE`    | USD notional traded on the No side. NULL for Kalshi (Yes-only) |
| `trade_count`       | `BIGINT`    | Number of fills in the hour                                    |
| `market_end_time`   | `TIMESTAMP` | Market expiration time (denormalized)                          |
| `market_outcome`    | `VARCHAR`   | Resolved outcome (denormalized). NULL while unresolved         |
| `event_market_name` | `VARCHAR`   | Event group label (denormalized)                               |
| `is_forward_filled` | `BOOLEAN`   | TRUE when the bar has no trades and was carried forward        |
| `_updated_at`       | `TIMESTAMP` | When this row was last written by the pipeline                 |

## 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 query

```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 hour >= NOW() - INTERVAL '30' DAY
  AND category = 'politics'
  AND vwap IS NOT NULL
GROUP BY 1, 2
ORDER BY 1, 2
```
