What Is the NBBO? National Best Bid and Offer
The NBBO is the national best bid and offer — the one consolidated stock quote your broker must match or beat. See how fast it updates, from real tick data.
The NBBO — the national best bid and offer — is the consolidated quote for a US stock: the highest price any buyer is bidding and the lowest price any seller is asking, gathered from every exchange at once. It is the quote your brokerage app shows, and the benchmark your broker must meet or beat when filling your order. Every number below is measured from real consolidated quote records, with the exact query attached.
What is the NBBO? A plain-English definition
A US stock does not trade in one place. NYSE, Nasdaq, and more than a dozen other exchanges each run an order book for the same ticker, and each book has its own best bid and ask at any instant. The NBBO stitches those tops together: the highest bid anywhere and the lowest ask anywhere, published side by side — with the shares available at each — as the national quote.
The stitching is done by the securities information processors, or SIPs: market utilities operated jointly by the exchanges. Whenever the top of any exchange's book changes the national best — a better price, a different share count at the best price, one venue overtaking another — the SIP publishes a fresh NBBO record. Two details are worth fixing early: the bid and the ask can live on two different exchanges at the same moment, and a price change is not required for an update — a size change at the same best price prints a new record too.
Traders call the two best prices the touch: to buy at the touch is to pay the national best ask, to sell is to hit the national best bid. The gap between the two is the bid-ask spread — that page measures what the gap costs to cross; this one is about the quote itself.
How to read an NBBO quote: prices and sizes
Here is a real standing NBBO for Coca-Cola (KO), captured at one ordinary early-afternoon moment on a recent full session.
The exact SQL behind every number
WITH (
SELECT max(session_date)
FROM (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
countIf((toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS regular_bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime(today() - 10)
AND window_start < toDateTime(today() - 3)
GROUP BY session_date
HAVING regular_bars = 390
)
) AS last_session
SELECT formatDateTime(toTimeZone(max(sip_timestamp), 'America/New_York'), '%Y-%m-%d %H:%i:%S') AS quote_time_et,
argMax(bid_size, tuple(sip_timestamp, sequence_number)) AS bid_shares,
toDecimalString(argMax(toFloat64(bid_price), tuple(sip_timestamp, sequence_number)), 2) AS best_bid,
toDecimalString(argMax(toFloat64(ask_price), tuple(sip_timestamp, sequence_number)), 2) AS best_ask,
argMax(ask_size, tuple(sip_timestamp, sequence_number)) AS ask_shares,
round(argMax(toFloat64(ask_price) - toFloat64(bid_price), tuple(sip_timestamp, sequence_number)) * 100, 1) AS spread_cents
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'KO'
AND sip_timestamp >= toDateTime(last_session, 'America/New_York') + INTERVAL 12 HOUR
AND sip_timestamp < toDateTime(last_session, 'America/New_York') + INTERVAL 13 HOUR + INTERVAL 30 MINUTE
AND bid_price > 0
AND ask_price > bid_priceRead it as two standing offers. Buyers' best: $82.81 for 700 shares. Sellers' best: $82.83 for 900 shares. The gap between them measured 2¢, stamped 2026-07-02 13:29:59 ET.
The share counts are the size at the touch — the displayed liquidity at the two best prices — and they matter as much as the prices. A market order smaller than the displayed size typically fills right at the quote; a larger order can exhaust the displayed shares and fill its remainder at the next prices in the book. Displayed size is a floor, not a full inventory: more interest often rests un-displayed at or between the two prices, including in dark pools and other off-exchange venues.
How does an NBBO quote update happen?
Each exchange streams its own best bid and ask to the SIP, which keeps the winner on each side and prints a new consolidated record whenever a winner changes. There is no schedule and no minimum interval — updates land as fast as orders arrive, cancel, and trade.
That pace is hard to picture, so here are the next 10 NBBO updates for Coca-Cola, starting at 1:30 p.m. Eastern on the same session as the snapshot above.
The exact SQL behind every number
WITH (
SELECT max(session_date)
FROM (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
countIf((toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS regular_bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime(today() - 10)
AND window_start < toDateTime(today() - 3)
GROUP BY session_date
HAVING regular_bars = 390
)
) AS last_session
SELECT substring(toString(toTimeZone(sip_timestamp, 'America/New_York')), 12, 12) AS et_time,
round((toUnixTimestamp64Nano(sip_timestamp) - min(toUnixTimestamp64Nano(sip_timestamp)) OVER ()) / 1e6, 2) AS elapsed_ms,
bid_size AS bid_shares,
toFloat64(bid_price) AS best_bid,
toFloat64(ask_price) AS best_ask,
ask_size AS ask_shares
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'KO'
AND sip_timestamp >= toDateTime(last_session, 'America/New_York') + INTERVAL 13 HOUR + INTERVAL 30 MINUTE
AND sip_timestamp < toDateTime(last_session, 'America/New_York') + INTERVAL 14 HOUR
AND bid_price > 0
AND ask_price > bid_price
ORDER BY sip_timestamp, sequence_number
LIMIT 10All 10 records landed within 1.76 milliseconds — the first stamped 13:30:00.044 ET on the tape's own clock. Any of four events prints a row: a better bid, a better ask, a change in the shares at either best price, or one exchange replacing another at the top. For a forensic, session-length look at this stream, see the tick-by-tick microstructure deep-dive.
How often does the NBBO update? Liquid vs. thin stocks
Every listed stock has an NBBO, and the update rate is a liquidity gauge in its own right. The table below averages the same recent sessions for four heavily traded names and two genuinely thin small caps, Nathan's Famous (NATH) and Seneca Foods (SENEA).
The exact SQL behind every number
SELECT ticker,
uniqExact(toDate(toTimeZone(sip_timestamp, 'America/New_York'))) AS sessions,
round(count() / uniqExact(toDate(toTimeZone(sip_timestamp, 'America/New_York')))) AS avg_updates_per_session,
round(count() / uniqExact(toDate(toTimeZone(sip_timestamp, 'America/New_York'))) / 1e6, 3) AS avg_updates_per_session_m,
round((count() / uniqExact(toDate(toTimeZone(sip_timestamp, 'America/New_York')))) / min(count() / uniqExact(toDate(toTimeZone(sip_timestamp, 'America/New_York')))) OVER (), 0) AS multiple_of_quietest
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'NVDA', 'AAPL', 'KO', 'SENEA', 'NATH')
AND sip_timestamp >= toDateTime(today() - 10)
AND sip_timestamp < toDateTime(today() - 3)
AND toDate(toTimeZone(sip_timestamp, 'America/New_York')) IN (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime(today() - 10)
AND window_start < toDateTime(today() - 3)
GROUP BY session_date
HAVING countIf((toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) = 390
)
GROUP BY ticker
ORDER BY indexOf(['SPY', 'NVDA', 'AAPL', 'KO', 'SENEA', 'NATH'], ticker)SPY, the S&P 500 ETF, averaged 4.299 million NBBO updates per session over the window — 3712 times the quietest name on the table. Nvidia averaged 2.041 million a session and Apple 1.398 million. Then comes the cliff: Seneca Foods printed 5175 updates in an average session, and Nathan's Famous 1158. The count travels with liquidity — the same thin names carry the widest quoted gaps, and the quotes on both sides are posted by the market makers who re-price their bids and offers all day long.
Add up every listed symbol and the scale changes again:
The exact SQL behind every number
WITH (
SELECT max(session_date)
FROM (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
countIf((toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) AS regular_bars
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime(today() - 10)
AND window_start < toDateTime(today() - 3)
GROUP BY session_date
HAVING regular_bars = 390
)
) AS last_session
SELECT formatDateTime(last_session, '%Y-%m-%d') AS session_date,
round(count() / 1e6) AS updates_millions,
uniqExact(ticker) AS tickers_quoted,
round(count() / 57600) AS avg_updates_per_second
FROM global_markets.cache_stocks_quotes
WHERE sip_timestamp >= toDateTime(last_session, 'America/New_York')
AND sip_timestamp < toDateTime(last_session + 1, 'America/New_York')On 2026-07-02, the most recent full session in this page's window, the consolidated tape carried 597 million NBBO updates across 12893 quoted symbols — an average of 10368 updates every second of the 16-hour quote day (4:00 a.m. to 8:00 p.m. ET). No person reads a screen at that speed. The NBBO is a feed built for software, and your brokerage app shows you its latest frame.
When the NBBO updates fastest: the open vs. midday
The update rate also keeps a daily rhythm. The chart below averages Apple's NBBO updates per minute in half-hour clock buckets (Eastern Time) across the same sessions, 4:00 a.m. to 8:00 p.m.; the last column states each bucket's pace as a percentage of the 9:30 bucket.
The exact SQL behind every number
SELECT et_time,
avg_updates_per_minute,
round(100 * avg_updates_per_minute / maxIf(avg_updates_per_minute, et_time = '09:30') OVER (), 1) AS pct_of_opening_bucket
FROM (
SELECT formatDateTime(toStartOfInterval(toTimeZone(sip_timestamp, 'America/New_York'), INTERVAL 30 MINUTE), '%H:%i') AS et_time,
round(count() / (uniqExact(toDate(toTimeZone(sip_timestamp, 'America/New_York'))) * 30)) AS avg_updates_per_minute
FROM global_markets.cache_stocks_quotes
WHERE ticker = 'AAPL'
AND sip_timestamp >= toDateTime(today() - 10)
AND sip_timestamp < toDateTime(today() - 3)
AND toDate(toTimeZone(sip_timestamp, 'America/New_York')) IN (
SELECT toDate(toTimeZone(window_start, 'America/New_York')) AS session_date
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY'
AND window_start >= toDateTime(today() - 10)
AND window_start < toDateTime(today() - 3)
GROUP BY session_date
HAVING countIf((toHour(toTimeZone(window_start, 'America/New_York')) * 60 + toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959) = 390
)
GROUP BY et_time
HAVING et_time >= '04:00' AND et_time < '20:00'
)
ORDER BY et_timeIn the first half hour after the opening auction — the 9:30 bucket — Apple's national quote updated an average of 5555 times per minute. The early-afternoon 1:00 bucket ran 2476 a minute — 44.6% of the opening pace — and the 3:30 run-in to the close climbed back to 4621. Outside regular hours the tape goes near-silent: 121 updates a minute in the last premarket bucket, and 27 in the first bucket after the 4:00 p.m. bell — 0.5% of the open.
Why your broker must fill you at the NBBO or better
The NBBO is a regulatory benchmark, not just a convenience. Regulation NMS — the SEC's market-structure rulebook, adopted in 2005 — includes an order-protection rule, Rule 611: a trading venue may not execute at a price worse than a protected quote displayed on another exchange. Alongside it, brokers owe their customers best execution, and the NBBO is the yardstick fills are measured against: a market buy should fill at the national best ask or lower, a market sell at the national best bid or higher. Fills better than the NBBO — price improvement — are routine; fills worse are the exception a broker has to answer for.
FAQ
Is the NBBO the same as the bid-ask spread?
No. The NBBO is the pair of best prices, with the displayed shares at each; the bid-ask spread is the distance between them. The spread is the cost of crossing the quote — the NBBO is the quote.
Can my order fill at a better price than the NBBO?
Yes. The NBBO-or-better standard is a floor, not a ceiling. Brokers and wholesalers routinely fill retail orders inside the spread, and many off-exchange trades print at the NBBO midpoint. That is price improvement, priced off the NBBO itself.
What does size at the touch mean?
The touch is the pair of best prices; size at the touch is the displayed shares at each. In the Coca-Cola snapshot above, 700 shares at the $82.81 bid and 900 shares at the $82.83 ask were the touch liquidity.
Does the NBBO exist after hours?
Consolidated quotes stream from 4:00 a.m. to 8:00 p.m. ET, and a national quote exists through premarket and after-hours trading — at a fraction of the daytime pace. On Apple above: 121 updates a minute in the last premarket bucket versus 5555 right after the open.
What is a locked or crossed market?
A locked market shows the best bid equal to the best ask — a spread of zero — and a crossed market shows the bid above the ask. Reg NMS bars exchanges from displaying quotes that would lock or cross the market; the fleeting locked or crossed records that do occur show up only in raw tick data during fast moments.
Data notes: windows and filters
Every window ends at least three days before the page was generated — the consolidated quote feed carries a short ingest lag at its front edge, and the buffer keeps a partially loaded day out of the counts. Every panel also screens for full-length sessions — a day counts only when SPY prints all 390 regular-hours minute bars — keeping early closes and holidays out of the picks and averages. The two Coca-Cola panels exclude one-sided records (a zero bid or ask) and crossed records (bid at or above ask) — display-quality filters for reading a single standing quote; the three counting panels count every disseminated record as-is. "Session" means the Eastern-Time calendar day, extended hours included.
Every panel above ships with the exact SQL that produced it — open one, swap in a ticker you own, and count its NBBO updates on the Strasmore terminal.