Skip to content
UDX
On this page

Reading Market Data

Request FIX book snapshots, follow top-of-book or depth updates, receive trades, and cancel subscriptions.

Start with a ticker from Discovering Markets and complete the market-data logon described in 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.

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) for the best bid and offer:

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), 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) Match MDReqID(262) to the request and handle the reason under 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:

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) 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:

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:

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:

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.
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:

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, 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.