---
title: Reading Market Data
description: Request FIX book snapshots, follow top-of-book or depth updates, receive trades, and cancel subscriptions.
---

Start with a ticker from [Discovering Markets](/walkthroughs/fix/discovering-markets) and complete the market-data logon described in [FIX Sessions and Recovery](/reference/fix-sessions-and-recovery). Read trading status separately; book messages do not report whether a market is open for trading.

The examples show decoded FIX fields. Your FIX engine encodes the numeric tags and raw values and supplies the header and trailer. Indentation marks repeating-group entries. Replace `<ticker>` with your selected market ticker. Prices use dollars in YES price space and quantities use contracts; see [Markets and Trading](/concepts/markets-and-trading).

## Choose a Book Configuration

The exchange supports aggregated price levels and anonymous individual resting orders. Choose a supported combination below for bid/offer book data.

`MarketDepth(264)=0` means full book, `MarketDepth(264)=1` means top of book, and values from 2 through 25 select that many price levels per side. Aggregated book Yes means `AggregatedBook(266)=Y`; No means `AggregatedBook(266)=N`. Full means `MDUpdateType(265)=FULL_REFRESH(0)`; Incremental means `MDUpdateType(265)=INCREMENTAL_REFRESH(1)`. Omitting `AggregatedBook(266)` selects an aggregated book; omitting `MDUpdateType(265)` selects full refreshes.

| Market depth | Aggregated book | Full refresh / incremental refresh | Supported |
| --- | --- | --- | --- |
| Full book | Yes | Full | ✅ Yes |
| Full book | Yes | Incremental | ❌ No |
| Full book | No | Full | ✅ Yes |
| Full book | No | Incremental | ❌ No |
| Top of book | Yes | Full | ✅ Yes |
| Top of book | Yes | Incremental | ✅ Yes |
| Top of book | No | Full | ✅ Yes |
| Top of book | No | Incremental | ❌ No |
| 2–25 price levels per side | Yes | Full | ✅ Yes |
| 2–25 price levels per side | Yes | Incremental | ❌ No |
| 2–25 price levels per side | No | Full | ✅ Yes |
| 2–25 price levels per side | No | Incremental | ❌ No |

## Read a Book Snapshot

Send [MarketDataRequest(V)](/api-reference/fix/market-data/messages/market-data-request) for the best bid and offer:

```text
MsgType(35)=MarketDataRequest(V)
MDReqID(262)=book-once
SubscriptionRequestType(263)=SNAPSHOT(0)
MarketDepth(264)=1
MDUpdateType(265)=FULL_REFRESH(0)
AggregatedBook(266)=Y
NoMDEntryTypes(267)=2
  MDEntryType(269)=BID(0)
  MDEntryType(269)=OFFER(1)
NoRelatedSym(146)=1
  Symbol(55)=<ticker>
```

The exchange answers with [MarketDataSnapshotFullRefresh(W)](/api-reference/fix/market-data/messages/market-data-snapshot-full-refresh), echoing `MDReqID(262)=book-once` and naming the ticker in `Symbol(55)`. Each `NoMDEntries(268)` entry gives a bid or offer with its price and available quantity. This request creates no ongoing subscription.

| Answer | Next step |
| --- | --- |
| Snapshot with bid or offer entries | Replace your view of the requested sides with the returned state. An absent side has no resting liquidity. |
| Snapshot with `NoMDEntries(268)=0` | Clear both requested sides. The book is empty; the request succeeded. |
| [MarketDataRequestReject(Y)](/api-reference/fix/market-data/messages/market-data-request-reject) | Match `MDReqID(262)` to the request and handle the reason under [Handle a Rejection](#handle-a-rejection). |

Each full refresh replaces the requested book view; do not merge it into an older snapshot and retain entries the new snapshot omitted. An empty book and an unknown ticker are different answers.

For several tickers, add an entry for each under `NoRelatedSym(146)` and adjust its counter. A successful request returns one snapshot per ticker, all carrying the same request ID. A request containing an unknown ticker is rejected as a whole.

## Follow the Best Bid and Offer

To receive ongoing aggregated top-of-book changes, create a subscription with incremental updates:

```text
MsgType(35)=MarketDataRequest(V)
MDReqID(262)=book-live
SubscriptionRequestType(263)=SNAPSHOT_PLUS_UPDATES(1)
MarketDepth(264)=1
MDUpdateType(265)=INCREMENTAL_REFRESH(1)
AggregatedBook(266)=Y
NoMDEntryTypes(267)=2
  MDEntryType(269)=BID(0)
  MDEntryType(269)=OFFER(1)
NoRelatedSym(146)=1
  Symbol(55)=<ticker>
```

Build the initial view from MarketDataSnapshotFullRefresh(W), even though you requested incremental updates. Subsequent [MarketDataIncrementalRefresh(X)](/api-reference/fix/market-data/messages/market-data-incremental-refresh) messages carry only changed sides. The request ID remains `MDReqID(262)=book-live`.

Key each top-of-book side by its ticker and `MDEntryType(269)`. In an incremental message, `Symbol(55)` is inside each entry. Apply entries in FIX sequence order:

| Action | Update your top-of-book view |
| --- | --- |
| `MDUpdateAction(279)=NEW(0)` | Set the previously absent side to the entry's price and quantity. |
| `MDUpdateAction(279)=CHANGE(1)` | Replace that side's price and quantity. The quantity is the new available quantity, not a delta. A price change replaces the old best price. |
| `MDUpdateAction(279)=DELETE(2)` | Remove that side. The entry identifies the removed price and quantity; do not retain it as current liquidity. |

Leave an unchanged side intact. A bid-only subscription receives no update when only the offer changes. If the exchange sends another full refresh, replace your requested view with that snapshot before applying later increments.

If you prefer complete top-of-book snapshots for every update, use `MDUpdateType(265)=FULL_REFRESH(0)` when creating the subscription.

## Read Market Depth

For example, request the full aggregated book and ongoing replacements:

```text
MsgType(35)=MarketDataRequest(V)
MDReqID(262)=depth-live
SubscriptionRequestType(263)=SNAPSHOT_PLUS_UPDATES(1)
MarketDepth(264)=0
MDUpdateType(265)=FULL_REFRESH(0)
AggregatedBook(266)=Y
NoMDEntryTypes(267)=2
  MDEntryType(269)=BID(0)
  MDEntryType(269)=OFFER(1)
NoRelatedSym(146)=1
  Symbol(55)=<ticker>
```

An aggregated entry contains the total remaining quantity at one price. An order-level entry contains one resting order's remaining quantity and an `MDEntryID(278)`; treat that ID as an anonymous book-entry identifier. Aggregated entries do not carry that ID.

A limited-depth request selects price levels per side, not a number of orders. In order-level mode, include all returned orders within those price levels. Preserve the returned price-time ordering within each side.

With MarketDepth(264)=1 and AggregatedBook(266)=No(N), two resting orders sharing the best bid price remain two entries, and the same applies to offers. Both the initial snapshot and subsequent updates are MsgType(35)=MarketDataSnapshotFullRefresh(W). Replacements and cancellations restate the remaining orders; when a best price empties, all orders at the next best price enter the view. A refresh with NoMDEntries(268)=0 clears the requested book. MDUpdateType(265)=IncrementalRefresh(1) is explicitly rejected for this combination, including snapshot-only requests; use MDUpdateType(265)=FullRefresh(0), or omit the update mode.

The top-of-book and depth examples are alternatives for the same ticker. A session can hold only one book/trade subscription per ticker. Cancel an existing subscription before changing its depth, refresh mode, or requested entry types.

## Include Trades

Trades arrive in MarketDataIncrementalRefresh(X). To receive trades together with the best bid and offer, include a third entry type when creating the incremental subscription:

```text
MsgType(35)=MarketDataRequest(V)
MDReqID(262)=book-and-trades
SubscriptionRequestType(263)=SNAPSHOT_PLUS_UPDATES(1)
MarketDepth(264)=1
MDUpdateType(265)=INCREMENTAL_REFRESH(1)
AggregatedBook(266)=Y
NoMDEntryTypes(267)=3
  MDEntryType(269)=BID(0)
  MDEntryType(269)=OFFER(1)
  MDEntryType(269)=TRADE(2)
NoRelatedSym(146)=1
  Symbol(55)=<ticker>
```

The first snapshot contains only the requested book sides; it does not contain a last-trade entry. Later trade entries have `MDEntryType(269)=TRADE(2)` and `MDUpdateAction(279)=NEW(0)`, with the trade's ticker, price, and quantity. Record them as trades rather than applying them to the book.

`AggressorSide(2446)` identifies the buying or selling aggressor. Each trade is published once, from the aggressing side, including negotiated trades. Do not wait for a second print from the other side.

The FIX market-data stream does not send trade corrections or retractions.

For trades alone, request only `MDEntryType(269)=TRADE(2)` and set `NoMDEntryTypes(267)=1`. The initial full refresh then has `NoMDEntries(268)=0`; it is not a historical-trade snapshot. Trades require incremental mode, so do not combine them with a full-refresh depth request.

If a book subscription for this ticker already exists, cancel it before creating the combined subscription. A separate trade request for the same ticker would conflict with that subscription.

## Handle a Rejection

A rejected request receives MarketDataRequestReject(Y). An unknown ticker, for example, produces:

```text
MsgType(35)=MarketDataRequestReject(Y)
MDReqID(262)=book-once
MDReqRejReason(281)=UNKNOWN_SYMBOL(0)
Text(58)=no such instrument
```

| Reason | Next step |
| --- | --- |
| `MDReqRejReason(281)=UNKNOWN_SYMBOL(0)` | Check the ticker and its book availability using [Discovering Markets](/walkthroughs/fix/discovering-markets). |
| `MDReqRejReason(281)=DUPLICATE_MDREQID(1)` | Check for an existing request ID or an existing subscription for a requested ticker. Use the existing subscription or cancel it before replacing it. |
| `MDReqRejReason(281)=UNSUPPORTED_MARKETDEPTH(5)` | Select a supported depth. Use full refreshes for non-aggregated top of book and all depth beyond top of book. |
| `MDReqRejReason(281)=UNSUPPORTED_MDENTRYTYPE(8)` | Select supported entry types and use incremental mode when requesting trades. |
| `MDReqRejReason(281)=UNSUPPORTED_SUBSCRIPTIONREQUESTTYPE(4)` | Correct the request fields and repeating groups using the message reference. |

Read `Text(58)` for the request's specific error. A multi-ticker subscription is also rejected as a whole if a requested ticker is already subscribed; none of its new subscriptions is opened.

## Cancel or Replace a Subscription

Repeat the original MarketDataRequest(V), retaining its `MDReqID(262)`, depth, refresh mode, entry types, and tickers, but change the subscription type. For the `book-live` example:

```text
MsgType(35)=MarketDataRequest(V)
MDReqID(262)=book-live
SubscriptionRequestType(263)=DISABLE_PREVIOUS_SNAPSHOT_PLUS_UPDATE_REQUEST(2)
MarketDepth(264)=1
MDUpdateType(265)=INCREMENTAL_REFRESH(1)
AggregatedBook(266)=Y
NoMDEntryTypes(267)=2
  MDEntryType(269)=BID(0)
  MDEntryType(269)=OFFER(1)
NoRelatedSym(146)=1
  Symbol(55)=<ticker>
```

Canceling a request ID removes all tickers held under that subscription. The exchange sends no application-level cancellation acknowledgment. Messages already in transit can still arrive, so keep the old request ID distinct from any replacement subscription's ID.

To change a subscription, cancel it and create a new request with the desired settings and a new request ID.

## Reconnect and Rebuild State

Follow the fresh market-data connection procedure in [FIX Sessions and Recovery](/reference/fix-sessions-and-recovery#reconnect-to-market-data), then recreate the subscriptions you still need. Rebuild each book from its new initial full refresh before applying later increments. Missed trades are not replayed.
