Locked and Crossed Markets, Explained With Data
Locked market na wen bid equal ask; crossed market na wen bid higher pass ask. See why Reg NMS ban both and how often dem dey show for di tape.
Wen market lock, na di moment wey one stock im best bid equal im best ask — bid-ask spread of exactly zero. Crossed market even pass dat one: di best bid dey stand above di best ask. US market rules no let exchanges show any of di two, but dem dey show for di consolidated quote record all di time. Dis page go define di two, explain di rule, and measure how often each one dey show.
Wetin be locked market?
Every US stock get two price at once: the bid, na di highest price any buyer go pay, and the ask, na di lowest price any seller go accept. Di ask normally dey above di bid; di gap between dem na di bid-ask spread, di built-in cost of trading sharp sharp.
Locked market na di moment wey dat gap drop reach zero: suppose dem quote one stock $10.00 bid / $10.05 ask, di spread na five cent, and if di best ask fall to $10.00 while di bid still hold, di quote don lock at $10.00 / $10.00.
For one single exchange, dat kain state no fit stand — buy at $10.00 meet sell at $10.00, e go execute sharp sharp. Locked quote only survive between venues. US stocks dey trade for more than one dozen exchange at once, and NBBO — di national best bid and offer, na di quote your brokerage app dey show — dey stitch di best bid and ask across all of dem. $10.00 bid for one venue and $10.00 ask for another go lock di national quote while no single venue dey show locked book.
Wetin be crossed market?
Crossed market dey turn normal arrangement upside down: the best bid dey stand above the best ask — like say $10.02 bid dey against $10.00 ask. For paper, anybody fit buy at $10.00, sell at $10.02, and chop two cents per share risk-free. That free money na exactly why crossed quote no fit last: professional firms — and market makers dey among dem, na dem dey quote both sides of most stocks — dem go take the arbitrage the moment wey e become real, and to take am, dem go chop both quotes. Wetin remain inside the data na the flicker: crossed record wey catch between one venue update and another one update.
Why Reg NMS dey ban locked and crossed quotes
The ban dey inside Regulation NMS, the SEC rulebook (dem adopt am for 2005) for trading across US stock exchanges. Rule 610(d) dey require each exchange to stop its members from displaying quotes wey lock or cross protected quotes — the automated best bids and offers for other exchanges — during normal trading hours. The intention: a bid wey equal somebody else ask fit trade right now, and the rulebook want make dem route and execute am, not to display am like one standing contradiction.
One boundary inside the rule dey important for the data wey dey below: e dey regulate displaying, not existing. Each venue dey control wetin its own book dey show; the consolidated record dey assembled across venues in real time, from feeds wey dey race each other. One locked NBBO fit appear there without any single participant breaking the rule.
Why locked and crossed quotes still dey show for tape
Speed. Exchanges dey update quotes for microseconds, and the consolidated feed dey rebuild on every update. Two ordinary events dey put locked and crossed records inside am:
- Races. One exchange don raise im bid to $10.00 while another one still dey show $10.00 ask. When you stitch them together, the NBBO go read locked until the slower side update; the same race wey overshoot by one cent go read crossed.
- Stale and one-sided records. Some records carry only one side — bid without ask, or the reverse. Thin names dey spend far more of the day there, as the census below dey show.
The counting rules for this page: locked = bid equal ask, both sides positive; crossed = bid higher than positive ask; one-sided = either side zero or missing. Nothing dey drop silently — one-sided records get their own column.
How often do locked and crossed markets happen?
Start with the whole tape: every NBBO update, for every listed symbol, on 2026-07-14 — the most recent completed session inside our census window.
The exact SQL behind every number
WITH (
SELECT max(toDate(toTimeZone(window_start, 'America/New_York')))
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker = 'SPY' AND window_start < toDateTime(today() - 3)
) AS census_day
SELECT
formatDateTime(census_day, '%Y-%m-%d') AS session_date,
round(count() / 1e6, 0) AS updates_m,
round(countIf(bid_price = ask_price AND bid_price > 0) / 1e6, 2) AS locked_m,
round(countIf(bid_price > ask_price AND ask_price > 0) / 1e3, 1) AS crossed_k,
round(countIf(bid_price = ask_price AND bid_price > 0) / toFloat64(greatest(countIf(bid_price > ask_price AND ask_price > 0), 1)), 0) AS locked_per_crossed,
round(countIf(bid_price >= ask_price AND ask_price > 0 AND bid_price > 0) / toFloat64(count()) * 1e4, 1) AS locked_or_crossed_per_10k,
round(countIf(bid_price <= 0 OR ask_price <= 0) / toFloat64(count()) * 1e4, 1) AS one_sided_per_10k
FROM global_markets.cache_stocks_quotes
WHERE sip_timestamp >= toDateTime(census_day)
AND sip_timestamp < toDateTime(census_day + 1)That session carry 477 million quote updates: 9.7 million locked and 67 thousand crossed — together 204.9 of every 10,000 updates, and locked pass crossed by 145-to-one. Records wey one side dey miss run 2.8 per 10,000. The July 7 market recap dey show the same counts next to every spread e dey measure.
The market-wide rate dey mix thousands of names wey no be the same. The table below rerun the census on one set of ten wey dem don check — eight household tickers plus two small caps wey thin well-well, Nathan's Famous (NATH) and Seneca Foods (SENEA) — across recent completed sessions, extended hours inside, and each name get im own normal quoted spread dey show there too.
The exact SQL behind every number
SELECT ticker,
round(count() / 1e3, 1) AS updates_k,
round(quantileExactIf(0.5)(toFloat64(ask_price - bid_price), bid_price > 0 AND ask_price >= bid_price) * 100, 1) AS median_spread_cents,
countIf(bid_price = ask_price AND bid_price > 0) AS locked_records,
countIf(bid_price > ask_price AND ask_price > 0) AS crossed_records,
round(countIf(bid_price >= ask_price AND ask_price > 0 AND bid_price > 0) / toFloat64(count()) * 1e4, 1) AS locked_or_crossed_per_10k,
round(countIf(bid_price <= 0 OR ask_price <= 0) / toFloat64(count()) * 1e4, 1) AS one_sided_per_10k
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'QQQ', 'AAPL', 'NVDA', 'MSFT', 'TSLA', 'KO', 'AMD', 'NATH', 'SENEA')
AND sip_timestamp >= toDateTime(today() - 10)
AND sip_timestamp < toDateTime(today() - 3)
GROUP BY ticker
ORDER BY tickerRead the spread column against the rate. Coca-Cola, wey dem dey quote am 1¢ wide, show one locked or crossed quote for 215.9 of every 10,000 updates; Nvidia (2¢) run 91 per 10,000 and SPY (2¢) 52.2. AMD, wey im normal extended-day quote dey sit around 44¢ wide, land for just 5.9 per 10,000. One lock need two venues wey reach the same penny at the same time — the wider the normal quote, the longer that trip go take.
The thin names barely show face: Nathan's Famous print 0 locked and 0 crossed records across 8.4 thousand updates, Seneca Foods 0 and 0 across 40.5 thousand. Their column na the other one: one-sided records run 41.5 per 10,000 for Nathan's Famous and 17 for Seneca Foods, against 0 for SPY. Locked and crossed records dey where quoting fast and tight; one-sided records dey where quoting scarce.
When locked and crossed quotes dey cluster?
The name census talk say where; the clock talk say when. Here na the checked set locked-or-crossed rate by 30-minute Eastern Time bucket, 4:00 a.m. to 8:00 p.m., with each bucket update traffic dey side am.
The exact SQL behind every number
SELECT formatDateTime(toStartOfInterval(toTimeZone(sip_timestamp, 'America/New_York'), INTERVAL 30 MINUTE), '%H:%i') AS et_time,
round(countIf(bid_price >= ask_price AND ask_price > 0 AND bid_price > 0) / toFloat64(count()) * 1e4, 1) AS locked_or_crossed_per_10k,
round(count() / 1e6, 2) AS updates_m
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'QQQ', 'AAPL', 'NVDA', 'MSFT', 'TSLA', 'KO', 'AMD', 'NATH', 'SENEA')
AND sip_timestamp >= toDateTime(today() - 10)
AND sip_timestamp < toDateTime(today() - 3)
GROUP BY et_time
HAVING et_time >= '04:00' AND et_time < '20:00'
ORDER BY et_timeThe rate dey climb across the session. The 05:00 premarket bucket measure 3 per 10,000 on 0.59 million updates; the 09:30 bucket — regular trading first half hour, wey the opening auction open am — run 24.9 per 10,000 on 9.98 million updates. From there the rate dey build into the close, reach 109.9 per 10,000 for the 15:30 bucket, the run-up to the closing auction. One receipt row dey pin the shape:
The exact SQL behind every number
SELECT
round(countIf(is_locked) / 1e3, 1) AS locked_k,
round(countIf(is_crossed) / 1e3, 1) AS crossed_k,
round(countIf(is_locked) / toFloat64(greatest(countIf(is_crossed), 1)), 1) AS locked_per_crossed,
round(countIf((is_locked OR is_crossed) AND et_minute BETWEEN 240 AND 569) / toFloat64(countIf(et_minute BETWEEN 240 AND 569)) * 1e4, 1) AS premarket_per_10k,
round(countIf((is_locked OR is_crossed) AND et_minute BETWEEN 570 AND 599) / toFloat64(countIf(et_minute BETWEEN 570 AND 599)) * 1e4, 1) AS opening_half_hour_per_10k,
round(countIf((is_locked OR is_crossed) AND et_minute BETWEEN 720 AND 779) / toFloat64(countIf(et_minute BETWEEN 720 AND 779)) * 1e4, 1) AS midday_hour_per_10k,
round(countIf((is_locked OR is_crossed) AND et_minute BETWEEN 930 AND 959) / toFloat64(countIf(et_minute BETWEEN 930 AND 959)) * 1e4, 1) AS closing_half_hour_per_10k,
round((countIf((is_locked OR is_crossed) AND et_minute BETWEEN 930 AND 959) / toFloat64(countIf(et_minute BETWEEN 930 AND 959)))
/ (countIf((is_locked OR is_crossed) AND et_minute BETWEEN 570 AND 599) / toFloat64(countIf(et_minute BETWEEN 570 AND 599))), 1) AS close_to_open_ratio,
round((countIf((is_locked OR is_crossed) AND et_minute BETWEEN 930 AND 959) / toFloat64(countIf(et_minute BETWEEN 930 AND 959)))
/ (countIf((is_locked OR is_crossed) AND et_minute BETWEEN 720 AND 779) / toFloat64(countIf(et_minute BETWEEN 720 AND 779))), 1) AS close_to_midday_ratio,
round((countIf((is_locked OR is_crossed) AND et_minute BETWEEN 930 AND 959) / toFloat64(countIf(et_minute BETWEEN 930 AND 959)))
/ (countIf((is_locked OR is_crossed) AND et_minute BETWEEN 240 AND 569) / toFloat64(countIf(et_minute BETWEEN 240 AND 569))), 1) AS close_to_premarket_ratio
FROM (
SELECT
bid_price = ask_price AND bid_price > 0 AS is_locked,
bid_price > ask_price AND ask_price > 0 AS is_crossed,
toHour(toTimeZone(sip_timestamp, 'America/New_York')) * 60 + toMinute(toTimeZone(sip_timestamp, 'America/New_York')) AS et_minute
FROM global_markets.cache_stocks_quotes
WHERE ticker IN ('SPY', 'QQQ', 'AAPL', 'NVDA', 'MSFT', 'TSLA', 'KO', 'AMD', 'NATH', 'SENEA')
AND sip_timestamp >= toDateTime(today() - 10)
AND sip_timestamp < toDateTime(today() - 3)
)Across the whole window the checked set print 257.2 thousand locked records against 25.6 thousand crossed — 10.1 locked for every crossed. The closing half hour rate, 109.9 per 10,000, run 4.4 times the opening half hour 24.9 and 2.3 times the noon hour 48.5.
The display ban no even apply before 9:30 a.m., yet the whole 4:00–9:30 stretch — premarket trading, wey dem dey quote on small fraction of regular-hours traffic — show just 10.9 per 10,000, and the closing half hour run 10.1 times that rate. These records dey collect where quoting dey run fast and tight, not where the rulebook loose pass.
Data notes: window and scope
- The whole-tape census cover one full UTC calendar day, every listed symbol inside; the checked-set panels cover rolling window of recent completed sessions, extended hours (4:00 a.m.–8:00 p.m. ET) inside. Every window end three days behind the refresh date — the quote warehouse carry one-to-two-day ingest lag for front edge.
- The ten-name table na checked set, not market-wide ranking; clock buckets after 4:00 p.m. dey run on small fraction of regular-hours traffic (na why dem chart the update-count column).
- These na counts of records, not durations. Per-update forensics — nanosecond gaps, plus crossed and zero-bid receipts on one session SPY tape — dey inside the June 29 microstructure deep-dive.
FAQ
Wetin be locked market for stocks?
Locked market na quote wey the best bid equal the best ask — spread of zero. E dey happen between exchanges — one venue bid match another one ask — and Regulation NMS no allow exchanges to display quotes wey dey create am during regular hours.
Wetin e mean when the bid pass the ask?
Bid wey pass ask na crossed market. One exchange book no fit stand like that — orders wey overlap dey execute sharp sharp — and crossed NBBO na almost always two venues quotes wey dem catch for middle of update.
Locked and crossed markets dey illegal?
No be for normal investor. Rule 610(d) of Regulation NMS dey make exchanges to stop their members from displaying locking or crossing quotes during regular hours. The transient records for the consolidated feed na artifacts of venues wey dey update for small different times.
How often locked and crossed markets dey happen?
Routine: 9.7 million locked and 67 thousand crossed records hit the consolidated tape for 2026-07-14 alone — 204.9 out of every 10,000 updates. The rate dey higher pass for tightly quoted names pass thin ones, and higher as market dey close pass when e dey open.
Every number for this page dey render from stored query — expand the SQL under any panel to see exactly how dem dey count lock or cross. To run the same census for the names wey you dey trade, ask for am for plain English for Strasmore terminal.