> Documentation index: https://pmdata.dev/llms.txt. Full docs in one file: https://pmdata.dev/llms-full.txt

# L2

Source: https://pmdata.dev/docs/schemas/predict-fun/l2

> Schema for Predict.fun L2 order books.

**All fields come from the raw Predict.fun WebSocket message.** PMData adds only the receive timestamp `local_timestamp`.

**Data type:** `l2` (`predict_fun`)

Source topic: `predictOrderbook/{marketId}`. One file per market per UTC day of `local_timestamp`. Every row is a complete aggregated order book. Books are priced in the market's first outcome, which may be `Yes`, `Up`, `Over 2.5` or a team name. The other outcome's book is the complement: a bid at price `p` with size `s` is an ask at `1 − p` with size `s`.

| Field | Type | Description |
| --- | --- | --- |
| `market_id` | `int64` | Predict.fun numeric market id. Source: `data.marketId`. |
| `timestamp` | `timestamp[us] \| null` | Time the book was last updated. Source: `data.updateTimestampMs`. Null when Predict.fun sends 0, for an empty book that was never updated. |
| `local_timestamp` | `timestamp[us]` | PMData receive timestamp. When the same book arrives more than once, the earliest receive time. |
| `event_type` | `string` | Topic name: `predictOrderbook`. |
| `bid_prices` | `list<double>` | Bid prices, best first (descending). Source: `data.bids[][0]`. |
| `bid_sizes` | `list<double>` | Size at each price in `bid_prices`. Source: `data.bids[][1]`. |
| `ask_prices` | `list<double>` | Ask prices, best first (ascending). Source: `data.asks[][0]`. |
| `ask_sizes` | `list<double>` | Size at each price in `ask_prices`. Source: `data.asks[][1]`. |
| `order_count` | `int64 \| null` | Number of orders on the book. Source: `data.orderCount`. |

- The four list columns are never null. An empty list means that side has no orders.
- Each row is one book state. PMData collects every market over two independent connections and keeps the earliest copy of each (`market_id`, `updateTimestampMs`) within the day.
- Rows are ordered by `timestamp`, then `local_timestamp`; rows with a null `timestamp` come first.
- To replay, replace the whole book with each row. No start-of-day row is added: the state before a day's first row is the last row of the previous day's file.

Not stored: `lastOrderSettled` and `settlementsPending`.

## Timestamps

All timestamps are UTC with microsecond precision. Predict.fun sends epoch milliseconds. `timestamp` can be earlier than the file's day: Predict.fun re-sends the current book on every subscription, and PMData's connections re-subscribe every hour.
