Strasmore Research
Learn am Matt ConnorBy Matt Connor · Updated 2026-07-25 · data as of July 25, 2026 · refreshed weekly

Wetin be NBBO? Meaning wey simple for anybody

NBBO na di national best bid and offer, di one consolidated stock quote wey your broker must match or beat. See how e dey update fast-fast from real tick data.

Di NBBO, wey be di national best bid and offer, na di consolidated quote for one US stock: di highest price wey any buyer dey bid and di lowest wey any seller dey ask, across every exchange at once. Na im be di quote wey your app dey show and di benchmark wey your broker must meet or beat for your order. Every number wey dey below come from real quote records, query attach.

Wetin be NBBO? Meaning wey simple for anybody

One US stock no dey trade for only one place. NYSE, Nasdaq, and more than twelve oda exchanges, each one dey run im own order book for di same ticker, each one get im own best bid and ask. NBBO na im dey join all dose tops togeda: di highest bid for anywhere, di lowest ask for anywhere, side by side wit di shares wey dey available for each. Na di securities information processors, or SIPs — market utilities wey di exchanges dey run togeda — dey do di joining.

Two tins dey important to know early. Di bid and di ask fit siddon for two different exchanges at di same time. And price no need change before update show: if size change for di same best price, e go still print new record. Traders dey call di two best prices di touch; di gap between dem na di bid-ask spread.

How to read NBBO quote: price, size and speed

Na ten NBBO record wey follow each other for Coca-Cola (KO) from 1:30 p.m. Eastern time for one recent full session — na di national quote as e dey land.

QueryKO — ten straight NBBO updates wey start from 1:30 p.m. ET for one recent 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 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,
       round((toFloat64(ask_price) - toFloat64(bid_price)) * 100, 1) AS spread_cents
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 10

Read di first row as two standing offers, wey dem stamp for 13:30:02.886 ET. Di best wey buyers get: $83.3 for 200 shares. Di best wey sellers get: $83.31 for 200 shares. Di gap between dem na 1¢.

Di share counts na di size at di touch — na liquidity wey dem show for di two best prices. Any order wey pass dat size go finish am and fill di rest for di next prices inside di book. Size wey dem show na floor, no be full inventory: plenty interest dey hide wey dem no show for di two prices or between dem, including for dark pools.

Now read di rows as dem dey go down. All 10 records land within 484.95 milliseconds of di first one. No schedule dey — di SIP dey publish anytime winner change, and any of four events fit print one row: better bid, better ask, change for di shares for any best price, or one exchange replace anoda one for di top. If you wan see di full session view, check di microstructure deep-dive.

NBBO dey include odd lots?

Mostly, e no dey. Di national quote dem build am from round-lot interest alone. Any order wey get fewer shares pass round lot na odd lot: e fit siddon for exchange book for better price pass di national best bid, trade for there, and e no go ever show for NBBO.

Round lot no be flat 100 shares again. Under SEC amended Reg NMS quoting rules, dem tier am by share price: 100 shares up to $250, 40 from $250.01 to $1,000, 10 from $1,000.01 to $10,000, one above dat. Di tiers dey visible for tape — di panel dey take di smallest bid size wey ever appear for consolidated quote for six names across di bands.

QueryDi smallest size wey NBBO go show — six names across di price tiers
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 ticker,
       round(quantileDeterministic(0.5)(toFloat64(bid_price), toUInt64(sequence_number)), 2) AS share_price,
       min(bid_size) AS smallest_quoted_size,
       round(quantileDeterministic(0.5)(toFloat64(bid_size), toUInt64(sequence_number)), 0) AS median_bid_size
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('F', 'KO', 'NVDA', 'AAPL', 'SPY', 'AZO')
  AND sip_timestamp >= toDateTime(last_session, 'America/New_York') + INTERVAL 10 HOUR
  AND sip_timestamp < toDateTime(last_session, 'America/New_York') + INTERVAL 11 HOUR
  AND bid_price > 0
  AND bid_size > 0
GROUP BY ticker
ORDER BY share_price

Ford, wey dey quote around $13.9, no ever show bid wey small pass 100 shares for dat hour; Coca-Cola for $84.18 sef no do am. Apple, for $314.36, e drop go 40; AutoZone, for $3030.52 a share, e go down go 10, with median displayed bid of 10. Di floor dey follow di price tier. Better-priced odd-lot interest fit siddon inside di published spread undisplayed, so di true best available price sometimes better pass wetin NBBO dey imply.

Why di quote wey dey your app no be di exact live NBBO

Di quote wey you dey read for phone don travel: exchange matching engine → SIP → data vendor → broker → screen. Every record dey carry two clocks — di exchange own stamp and di SIP own stamp for publication time — and di gap between dem na di consolidation step.

QueryExchange stamp to SIP stamp — di consolidation step, in microseconds
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 ticker,
       round(quantileDeterministic(0.5)((toUnixTimestamp64Nano(sip_timestamp) - toUnixTimestamp64Nano(participant_timestamp)) / 1000.0, toUInt64(sequence_number)), 1) AS median_micros,
       round(quantileDeterministic(0.99)((toUnixTimestamp64Nano(sip_timestamp) - toUnixTimestamp64Nano(participant_timestamp)) / 1000.0, toUInt64(sequence_number)), 1) AS p99_micros
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'NVDA', 'AAPL', 'KO')
  AND sip_timestamp >= toDateTime(last_session, 'America/New_York')
  AND sip_timestamp < toDateTime(last_session + 1, 'America/New_York')
  AND participant_timestamp > toDateTime64('2020-01-01 00:00:00', 9)
GROUP BY ticker
ORDER BY indexOf(['SPY', 'NVDA', 'AAPL', 'KO'], ticker)

Di median gap for SPY measure 229.1 microseconds — millionths of a second — and Apple own na 203.4. Di tail fat pass di middle: Nvidia own 99th percentile come be 536.9 microseconds. Di SIP no slow for any human sense. Two oda things dey slow.

First, your data fit dey delayed on purpose. Free quote feeds for retail apps and charting sites dey usually delayed 15 minutes under exchange licensing terms; real-time streaming na paid entitlement.

Second, professional firms no dey wait for di SIP. Each exchange still dey sell direct feed from im own matching engine. One colocated firm dey read am and compute im own best bid and offer before di SIP own version of dat event reach — one edge of microseconds, wey dey decisive for one market maker wey dey quote both sides all day.

How often di NBBO dey update? Liquid versus tin stocks

Every listed stock get NBBO, and how fast e dey update na gauge of liquidity. Di table na wetin we calculate for full recent sessions from four heavy-traded names and two tin small caps — Nathan’s Famous (NATH) and Seneca Foods (SENEA).

QueryNBBO updates per session — four names wey dem trade well-well vs. two thin small caps
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, di S&P 500 ETF, dey average 3.428 million NBBO updates per session — e be 2031 times wetin di quietest name for di table get. Nvidia average na 1.85 million, Apple 1.336 million. From there e just drop: Seneca Foods print 8097 updates for one average session, Nathan’s Famous 1688. No person dey read screen for di rate wey SPY dey move: di NBBO na feed wey dem build for software.

Wen NBBO dey update fast pass: open vs. midday

Di update rate still get im own daily rhythm. Di chart dey show average of Apple NBBO updates per minute for half-hour clock buckets (Eastern Time); di last column dey read each bucket as percentage of di 9:30 one.

QueryAAPL — average NBBO updates per minute by half-hour bucket (ET, 4 a.m. to 8 p.m.)
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_time

For di half hour afta di opening auction, Apple national quote bin dey update 5657 times a minute on average, and di 10:00 bucket hold dat pace at 89.5% of am. Di tape come thin out as di day dey waka: di 2:30 bucket run 1973 updates a minute, wey be 34.9% of di opening pace. Di 3:30 run-in to di close only recover small part of di way back — 3345 a minute, 59.1% of di open — so di heaviest quoting siddon for di first hour, no be di last. Outside regular hours di tape near-silent, e drop go 17 updates a minute afta di 4:00 p.m. bell.

Wetin dey happen to NBBO wen trading halt dey?

Wen one stock move too far too fast, di limit-up/limit-down rules go pause am for five minutes. Di quote no dey vanish and e no dey stay live: e just stop to dey refresh, and di last record before di pause na di frame wey remain for your screen. GameStop (GME) trigger dat kind pause just after 11:00 a.m. Eastern for May 14, 2024; di panel dey track im quote updates and trades, minute by minute, across di pause.

QueryGME, 2024-05-14 — NBBO updates and trades per minute across one five-minute LULD pause
The exact SQL behind every number
WITH spine AS (
    SELECT toStartOfMinute(toTimeZone(window_start, 'America/New_York')) AS et_min
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'SPY'
      AND window_start >= toDateTime('2024-05-14 10:57:00', 'America/New_York')
      AND window_start < toDateTime('2024-05-14 11:12:00', 'America/New_York')
),
gme_trades AS (
    SELECT toStartOfMinute(toTimeZone(window_start, 'America/New_York')) AS et_min,
           sum(transactions) AS trades
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker = 'GME'
      AND window_start >= toDateTime('2024-05-14 10:57:00', 'America/New_York')
      AND window_start < toDateTime('2024-05-14 11:12:00', 'America/New_York')
    GROUP BY et_min
),
gme_quotes AS (
    SELECT toStartOfMinute(toTimeZone(sip_timestamp, 'America/New_York')) AS et_min,
           count() AS nbbo_updates
    FROM global_markets.cache_stocks_quotes
    WHERE ticker = 'GME'
      AND sip_timestamp >= toDateTime('2024-05-14 10:57:00', 'America/New_York')
      AND sip_timestamp < toDateTime('2024-05-14 11:12:00', 'America/New_York')
    GROUP BY et_min
)
SELECT formatDateTime(spine.et_min, '%H:%i') AS et_time,
       ifNull(gme_quotes.nbbo_updates, 0) AS nbbo_updates,
       toUInt64(ifNull(gme_trades.trades, 0)) AS trades
FROM spine
LEFT JOIN gme_quotes ON gme_quotes.et_min = spine.et_min
LEFT JOIN gme_trades ON gme_trades.et_min = spine.et_min
ORDER BY spine.et_min

For di minute before di pause, 11:00, GameStop im consolidated quote update 4511 times against 12419 trades. Den both columns fall comot like from shelf: 0 quote records at 11:02 and 0 at 11:03, with 0 trades to match am — na quote wey don stop to dey move, for stock wey don stop to dey trade. Quoting dey return at 11:06, di reopening minute, with 4155 updates and 14007 trades, di heaviest trade minute for di table. One halted stock im last NBBO na fossil, no be price wey you fit trade; di January 2021 GameStop session show wetin chain of dat kind pauses dey do to tape.

Why your broker gats to fill you for NBBO or better

NBBO na regulatory benchmark. Regulation NMS — wey be SEC market-structure rulebook, wey dem adopt for 2005 — get order-protection rule, Rule 611: one venue no fit execute for price wey worse pass protected quote wey show for another exchange. Brokers still dey owe customers best execution, wey dem dey measure against NBBO: market buy suppose fill for national best ask or lower, market sell for national best bid or higher.

Plenty retail readers dey miss dis one: your market order normally no dey ever reach exchange. Most retail marketable flow dey route go wholesalers — off-exchange market makers wey pay for the right to fill am — and dem execute am internally, print am go off-exchange reporting facility. NBBO still dey rule dem: the wholesaler gats match or beat the national quote for the moment of execution, and dem dey compete for the flow by beating am — dem dey fill fraction of one cent inside the spread, wey dem dey call price improvement. NBBO na the reference price, no be the venue; the order type wey you choose dey decide whether you cross the spread at all.

FAQ

NBBO dey include odd lots?

E no dey. Di national quote na from round-lot quotes alone, and Reg NMS dey arrange di round lot based on price — 100 shares if e dey below $250, e fit drop go one share if e pass $10,000. Di smallest bid wey di tape show for Ford up dia na 100 shares, against 10 for AutoZone, wey im shares cost well-well. Better-priced odd lots dey siddon inside di published spread, dem no dey show.

Why di quote for my brokerage app different from di live NBBO?

Two reasons, and none of dem na di SIP. Free retail feeds dey usually delay by 15 minutes under exchange licensing rules unless you pay for real-time. And consolidated data na published snapshot: di consolidation step measure 229.1 microseconds for di median on SPY, while firms wey dey on exchange direct feeds dey see di event earlier.

Wetin dey happen to di NBBO when dem halt a stock?

E dey freeze. During GameStop im five-minute limit-up/limit-down pause wey dey up dia, di tape carry 0 quote updates at 11:03 and 0 trades. Di last quote go stay for screen but you no fit trade am; na reopening auction go set di next one.

NBBO dey exist after hours?

E dey. Consolidated quotes dey stream from 4:00 a.m. to 8:00 p.m. ET, so national quote dey through premarket and after-hours trading — but e be small fraction of di daytime pace: 65 Apple updates a minute for di last premarket bucket against 5657 after di open.

Data notes: windows and filters

Rolling windows dey end three days before generation (small ingest lag dey siddon for di feed front edge) and dem dey count only full sessions — days wey SPY print all 390 regular-hours minute bars. Di Coca-Cola panel dey exclude one-sided and crossed records; di counting panels dey take every record as e be (locked and crossed markets cover di ones wey dem exclude). Di GameStop panel dey pinned to one fixed date, with SPY im minute bars as clock spine, so paused minutes go show as zeros.


Every panel dey come with di SQL wey produce am — open one, swap in your own ticker, and count im NBBO updates on di Strasmore terminal.