Skip to content

Exchange auctions

Imbalance and auction data from the venue that runs the auction.

Bloomberg publishes auction imbalance, indicative prices, auction state, and auction results only on the listing where the auction runs. xbbg.ext routes each input to that listing and checks Bloomberg's answer before it returns or streams any data.

WARNING

Auction fields need the matching exchange entitlements. Values are raw and venue-specific: read Reading the data before you build on them.

Why venue routing matters ​

A composite ticker such as SPY US Equity returns no auction fields from reference data and only some of them in streams. A pricing-source suffix on an equity ISIN (/isin/<ISIN>@UP) is silently ignored, so Bloomberg answers with the composite. Every auction helper therefore works in three steps:

  1. 01Route

    Look up the input's market sector, exchange codes, and pricing source, and build the venue topic.

  2. 02Validate

    Ask the venue topic for its EXCH_CODE or PRICING_SOURCE and compare it with the expected value.

  3. 03Return or subscribe

    Only validated venues carry data. Inputs that fail stay in the result with a status and an error message.

HelperAsyncPurpose
resolve_venuesaresolve_venuesRoute and validate inputs; no auction data
auction_snapshotaauction_snapshotCurrent auction fields from validated venues
subscribe_auctionasubscribe_auctionLive Subscription on the validated venues
stream_auctionastream_auctionSimple iteration over live auction rows
AUCTIONField groups
imbalance_sideMap imbalance codes to "buy", "sell", or "none"

Resolve venues ​

python
from xbbg import ext

# SPY US Equity -> SPY UP Equity, IBM US Equity -> IBM UN Equity,
# US0378331005 (Apple's ISIN) -> AAPL UW Equity
venues = ext.resolve_venues(["SPY US Equity", "IBM US Equity", "US0378331005"])

resolve_venues(securities, *, pcs_overrides=None, backend=None) takes one identifier or a list of them. A bare ISIN with a valid ISO 6166 check digit is looked up as /isin/<ISIN>. The result has one row per input, in input order, duplicates included.

InputVenue topicmethodChecked against
Equity or ETF composite ticker, or its ISIN{TICKER} {EQY_PRIM_EXCH_SHRT} Equityexchange_tickervenue EXCH_CODE
Exchange ticker such as SPY UP Equityunchangedas_isvenue EXCH_CODE
Preferred (Pfd) priced on its exchange (PRICING_SOURCE is EXCH)/isin/<ISIN>@<PCS>pcs_suffixvenue PRICING_SOURCE
Other preferredunchangedas_isvenue PRICING_SOURCE
statusMeaning
resolvedThe venue returned the expected exchange code or pricing source.
unresolvedA routing or validation field was missing, for example because Bloomberg rejected the input.
unsupportedThe market sector is not Equity or Pfd, or a preferred's exchange has no known pricing source.
mismatchThe venue answered with a different exchange code or pricing source, for example after an ignored suffix.

Only resolved rows are usable venues; the others never carry data, and error explains why. The columns are input_order, security (your input), lookup, kind (the lower-cased market sector, or unknown), composite, venue_topic, venue_figi, method, exch_code, mic, pricing_source, status, and error. venue_figi, exch_code, and pricing_source are filled only for resolved rows.

Preferred pricing sources ​

Preferreds route through a packaged exchange-to-PCS table: NEW YORK → SNY2; NASDAQ/NGS, NASDAQ/NGM, and NASDAQ/NCM → NASP; NYSE AMERICAN → AMEX. Every route is still validated against the returned PRICING_SOURCE. For other exchanges, or to replace a default, pass pcs_overrides, a mapping from the preferred's exchange name to a pricing source. Names match case- and whitespace-insensitively, values are upper-cased, and overrides win over the packaged table:

python
from xbbg import ext


def preferred_venues(isins: list[str]):
    return ext.resolve_venues(isins, pcs_overrides={"NEW YORK": "SNY2"})

Routing cache ​

Successful routing lookups are cached for the process for 12 hours, keyed by the normalized input and the effective pcs_overrides, with at most 4,096 routes (oldest first out). Cache hits do not extend the 12 hours, and a failed validation drops the cached route. Validation and data requests run on every call, so a route that has gone stale shows up as mismatch or unresolved rather than as wrong data.

Snapshot auction fields ​

python
from xbbg import ext

snap = ext.auction_snapshot(["SPY US Equity", "IBM US Equity"])
results = ext.auction_snapshot("IBM US Equity", ext.AUCTION.RESULTS, backend="pandas")

auction_snapshot(securities, fields=AUCTION.DEFAULT, *, pcs_overrides=None, backend=None) routes every input, then fetches the fields and the validation codes from the venues in one reference-data request. The columns are input_order, security, venue_topic, status, and error, followed by one column per requested field. Rows that fail routing or validation keep null field values.

Field types follow Bloomberg's field metadata: time-of-day values become Time64 (microseconds) with no invented date, full datetimes become UTC timestamps, and dates become Date32. Integer fields are returned as Int64, and a temporal field whose values are mixed or unparseable stays text.

Field groups ​

ext.AUCTION holds tuples of field names; concatenate them to combine groups, for example ext.AUCTION.IMBALANCE + ext.AUCTION.QUOTES.

GroupFields
IMBALANCEORDER_IMB_BUY_VOLUME, ORDER_IMB_SELL_VOLUME, IMBALANCE_INDIC_RT, IMBALANCE_TIMESTAMP_RT, PAIRED_VOLUME_AT_REFERENCE_PX_RT, REFERENCE_PRICE_RT, MARKET_ORDER_IMBALANCE_VOLUME_RT, MARKET_ORDER_IMBALANCE_SIDE_RT, NEAR_REFERENCE_PX_VARIATION_RT, IMBALANCE_CROSS_TYPE_RT
INDICATIVEINDICATIVE_NEAR, INDICATIVE_FAR, THEO_PRICE, VOLUME_THEO, THEORETICAL_TIME_TODAY_RT, IMBALANCE_BUY, IMBALANCE_SELL
STATEAUCTION_TYPE_REALTIME, IN_AUCTION_RT, TIME_AUCTION_CALL_CONCLUSION_RT, SUB_SEC_TM_AUCT_CALL_CNCLSN_RT, AUCTION_EXTENSION_RT, MARKET_OR_LIMIT_CLOSE_ENTRY_RT, MOC_ELIGIBLE_RT, RT_TRADING_PERIOD, RT_EXCH_MARKET_STATUS, RT_SIMP_SEC_STATUS
HALTSTRADING_HALT_REASON_TYPE_RT, LULD_EVENT_CODE_RT, INTRADAY_AUCTION_VOLUME_RT
RESULTSOFFICIAL_CLOSE_AUCTION_PRICE_RT, OFFICIAL_CLOSE_AUCTION_VOLUME_RT, CLOSING_AUCTION_VOLUME_RT, CLOSING_AUCTION_VOLUME_DATE_RT, NUM_TRADES_CLOSING_AUCTION_RT, OFFICIAL_OPEN_AUCTION_PRICE_RT, OFFICIAL_OPEN_AUCTION_VOLUME_RT, OPENING_AUCTION_VOLUME_RT, PX_OFFICIAL_CLOSE_RT
COMPOSITEPRIMARY_MARKET_CLOSING_PRICE_RT, TIME_OF_CLOS_PX_ON_PRIM_MKT_RT, PRIMARY_MARKET_OPENING_PRICE_RT (opt-in)
QUOTESBID, ASK, BID_SIZE, ASK_SIZE (opt-in)
DEFAULTIMBALANCE + INDICATIVE + STATE + HALTS + RESULTS (39 fields)

ext.AUCTION.ZERO_PRICE_FIELDS is a separate list, not a group: THEO_PRICE, INDICATIVE_NEAR, INDICATIVE_FAR, IMBALANCE_BUY, IMBALANCE_SELL, and REFERENCE_PRICE_RT.

The groups use streaming names such as THEO_PRICE and BID, which reference data also accepts. Live subscriptions reject static names such as PX_THEO and PX_BID. Snapshots and streams can deliver different scalar types for the same field: IN_AUCTION_RT, for example, can arrive as Y/N text on one path and as a boolean on the other.

Stream auction data ​

python
import asyncio

from xbbg import ext


async def watch_auctions() -> None:
    sub = await ext.asubscribe_auction(["SPY US Equity", "IBM US Equity"])
    try:
        async for table in sub:
            print(table.to_pylist())
            break
    finally:
        await sub.unsubscribe()


asyncio.run(watch_auctions())

asubscribe_auction(securities, fields=AUCTION.DEFAULT, *, pcs_overrides=None, rows=True, on_field_error="warn", zero_as_null=None, **subscribe_kwargs) returns a Subscription; subscribe_auction is its synchronous wrapper.

  • Preflight. Every input is resolved before anything is subscribed; identical input strings collapse to one. If the list is empty, any input fails to resolve, or two different inputs route to the same venue, BlpValidationError names the inputs and nothing is subscribed.
  • Your labels. Rows, status, and latest() use the identifiers you passed, not the venue topics. xbbg sets aliases itself, so passing aliases raises BlpValidationError. remove() takes your labels; add() expects already resolved venue topics (optionally with aliases), so run resolve_venues first.
  • Rejected fields. on_field_error is "warn" (BlpFieldWarning), "raise" (fail the affected securities), or "ignore" (record in sub.field_errors only).
  • Zero prices. By default zero_as_null is AUCTION.ZERO_PRICE_FIELDS intersected with the requested fields; it affects latest() and, since 1.8.0, delivery="state" images, never delta rows. Pass zero_as_null=() to keep the zeros.
  • Everything else passes through to asubscribe, for example on_delayed, isolated, raw, tick_mode, output, or conflate. See Streaming for these options and for subscription lifecycle and diagnostics.

astream_auction(...) and stream_auction(...) run the same preflight with the same pcs_overrides, on_field_error, and zero_as_null handling, always deliver rows, and pass other keywords to astream and stream. stream_auction iterates synchronously through xbbg's managed background loop; close it when you stop early:

python
from xbbg import ext

auction_rows = ext.stream_auction(["IBM US Equity"], ext.AUCTION.IMBALANCE)
try:
    for batch in auction_rows:
        print(batch)
        break
finally:
    auction_rows.close()

Boards without rows ​

A board you poll, rather than iterate, keeps only current values:

python
import asyncio

from xbbg import ext


async def auction_board() -> None:
    board = await ext.asubscribe_auction(["SPY US Equity", "IBM US Equity"], rows=False)
    try:
        await asyncio.sleep(5)
        print(board.latest())  # one row per security
    finally:
        await board.unsubscribe()


asyncio.run(auction_board())

With rows=False nothing is queued, so a polled subscription cannot overflow, and iterating it raises RuntimeError. latest() returns one row per security: topic (your label), last_update (UTC), live (a non-initial update has arrived), delayed, and the current value of each field. latest(backend=...) converts like any request result. If Bloomberg reports DATALOSS, a board re-subscribes for a fresh image instead of ending: live turns false and DataLoss and then FeedRecovered appear in board.events. Once the subscription has ended, latest() raises.

Reading the data ​

  • Values are raw and venue-specific. INDICATIVE_NEAR and INDICATIVE_FAR are NYSE's continuous-book and closing-only clearing prices but Nasdaq's near and far indicative prices, and IMBALANCE_CROSS_TYPE_RT codes differ by venue.
  • IMBALANCE_BUY and IMBALANCE_SELL are prices, not quantities. For imbalance-side codes use ext.imbalance_side(code).
  • Zero means missing for some prices. THEO_PRICE and VOLUME_THEO reset to 0 at the start of each auction call, and Bloomberg sends 0 for a price it does not have. Auction subscriptions therefore show the ZERO_PRICE_FIELDS as missing in latest() (and in state deliveries); delta rows always carry the raw values.
  • Imbalance values can outlive the auction. Use AUCTION_TYPE_REALTIME, IN_AUCTION_RT, and the live column of latest() to tell current values from leftovers.
  • Times have no date. Time-of-day fields such as IMBALANCE_TIMESTAMP_RT are times in the Terminal's local time zone, in snapshots and streams alike. Date fields such as CLOSING_AUCTION_VOLUME_DATE_RT are dates.
  • Bloomberg keeps no imbalance history. Record the stream if you need it later.
python
from xbbg import ext

ext.imbalance_side("MBUY")  # "buy"   (BUY, MBUY, RBUY)
ext.imbalance_side("RSEL")  # "sell"  (SELL, MSEL, RSEL)
ext.imbalance_side("NIMB")  # "none"  (NOIM, NIMB)
ext.imbalance_side("XXXX")  # None for unknown codes

Codes are matched case-insensitively after trimming whitespace.

Record a stream to Parquet ​

Raw batches convert to PyArrow record batches that can be appended to Parquet (install xbbg[pyarrow]). Keep __xbbg_present so a reader can tell unchanged fields from explicit clears, and start a new file when the schema changes:

python
import asyncio

import pyarrow.parquet as pq

from xbbg import ext


async def record_auction() -> None:
    sub = await ext.asubscribe_auction(["IBM US Equity"], raw=True)
    writer, part = None, 0
    try:
        async for batch in sub:
            batch = batch.to_pyarrow()
            if writer is None or batch.schema != writer.schema:
                if writer is not None:
                    writer.close()
                part += 1
                writer = pq.ParquetWriter(f"ibm-auction-{part}.parquet", batch.schema)
            writer.write_batch(batch)
    finally:
        await sub.unsubscribe()
        if writer is not None:
            writer.close()


asyncio.run(record_auction())

Subscription rows are deltas, not complete images; see Streaming for the presence bitmap and data-loss semantics.

Auction results history ​

Auction results, unlike imbalance data, have history on the venue listing. Request it from the listing that resolve_venues returns; the composite returns none:

python
import xbbg

closing_volume = xbbg.bdh("IBM UN Equity", "OFFICIAL_CLOSE_AUCTION_VOLUME", "2024-01-02", "2024-03-28")

Delayed data ​

Delayed data does not need a subscription to detect: xbbg.delay_status(...) reports per security whether this session's data is delayed, and bdp, bdh, bdib, and bdtick accept on_delayed=. Auction subscriptions warn when a stream is delayed, like every subscription; pass on_delayed= to asubscribe_auction to change that. See Entitlements and delayed data and Streaming.

The LangGraph adapters expose xbbg_resolve_venues and xbbg_auction_snapshot (LangGraph tools), and the MCP server exposes resolve_venues and auction_snapshot (MCP server).

Streaming

Subscription options, shared feeds, deltas, data loss, and cleanup.

Entitlements

Delayed-data checks, entitlement IDs, and support RequestIds.

xbbg is independent open-source software and is not affiliated with, endorsed by, sponsored by, or approved by Bloomberg Finance L.P.