Comprendre le NBBO et son fonctionnement
Découvrez le fonctionnement du NBBO, la cotation consolidée que votre courtier doit respecter pour l'exécution de vos ordres sur les marchés américains.
Le NBBO (National Best Bid and Offer) est la cotation consolidée d'une action américaine : il représente le prix d'achat le plus élevé et le prix de vente le plus bas, tous échanges confondus. C'est la cotation affichée par votre application et la référence que votre courtier doit respecter ou améliorer lors de l'exécution de votre ordre. Tous les chiffres présentés ci-dessous proviennent de relevés de cotations réels, voir la requête jointe.
Qu'est-ce que le NBBO ? Une définition simple
Une action américaine ne se négocie pas sur un lieu unique. Le NYSE, le Nasdaq et plus d'une douzaine d'autres bourses gèrent chacune un carnet d'ordres pour le même ticker, avec leurs propres meilleures offres d'achat et de vente. Le NBBO agrège ces données : il affiche la meilleure offre (bid) disponible partout et le meilleur prix de vente (ask) disponible partout, côte à côte avec les volumes disponibles pour chacun. Cette agrégation est réalisée par les processeurs d'informations sur les titres, ou SIPs — des infrastructures de marché exploitées conjointement par les bourses.
Deux détails sont importants. Le bid et l'ask peuvent se trouver simultanément sur deux bourses différentes. De plus, une mise à jour ne nécessite pas forcément un changement de prix : une modification de la taille d'un ordre au même meilleur prix génère également un nouvel enregistrement. Les traders appellent ces deux meilleurs prix « the touch » ; l'écart entre eux est le bid-ask spread.
Comment lire une cotation NBBO : prix, tailles et rythme
Voici dix enregistrements NBBO consécutifs pour Coca-Cola (KO) à 13h30 (heure de l'Est) lors d'une session complète récente — la cotation nationale telle qu'elle arrive réellement.
Le SQL exact derrière chaque chiffre
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 10Lisez la première ligne comme deux ordres en attente, horodatés à 13:30:02.886 ET. Meilleur acheteur : $83.3 pour 200 actions. Meilleur vendeur : $83.31 pour 200 actions. L'écart entre les deux est de 1¢.
Le nombre d'actions correspond à la taille au touch — la liquidité affichée aux deux meilleurs prix. Un ordre supérieur à cette taille épuise cette liquidité et exécute le reste aux prix suivants du carnet. La taille affichée est un minimum, pas un inventaire complet : un intérêt supplémentaire reste souvent non affiché au niveau ou entre les deux prix, notamment dans les dark pools.
Lisez maintenant les lignes suivantes. Tous les enregistrements 10 sont arrivés dans un intervalle de 484.95 millisecondes par rapport au premier. Il n'y a pas d'horaire fixe — le SIP publie dès qu'un prix change, et l'un des quatre événements suivants génère une ligne : une meilleure offre (bid), une meilleure demande (ask), un changement de volume au niveau de l'un des deux meilleurs prix, ou une bourse qui remplace une autre en tête de liste. Pour une analyse détaillée de la microstructure, consultez le guide sur la microstructure.
Le NBBO inclut-il les odd lots ?
Généralement non. La cotation nationale est constituée uniquement des intérêts en round-lot. Un ordre portant sur un nombre d'actions inférieur à un round lot est un odd lot : il peut être inscrit dans le carnet d'ordres d'une plateforme à un prix meilleur que le national best bid, y être exécuté, et n'apparaître jamais dans le NBBO.
Le round lot n'est plus systématiquement de 100 actions. Selon les règles de cotation modifiées de la Reg NMS par la SEC, il est segmenté selon le cours de l'action : 100 actions jusqu'à 250 $, 40 actions de 250,01 $ à 1 000 $, 10 actions de 1 000,01 $ à 10 000 $, et une seule action au-delà. Ces paliers sont visibles dans le tape — le panel retient la plus petite taille de bid qui apparaît dans la cotation consolidée pour six titres répartis sur ces bandes.
Le SQL exact derrière chaque chiffre
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_priceFord, cotant autour de 13.9, n'affiche jamais de bid inférieur à 100 actions durant cette heure ; il en va de même pour Coca-Cola à 84.18. Apple, à 314.36, descend à 40 ; AutoZone, à 3030.52 la part, descend à 10, avec un bid médian affiché de 10. Le plancher suit le palier de prix. Un intérêt en odd-lot à un meilleur prix peut se situer à l'intérieur du spread publié sans être affiché ; le véritable meilleur prix disponible est donc parfois meilleur que ce que le NBBO suggère.
Pourquoi le cours de votre application n'est pas exactement le NBBO en temps réel
Le cours affiché sur votre téléphone suit un parcours précis : moteur de matching de la bourse → SIP → fournisseur de données → courtier → écran. Chaque enregistrement comporte deux horodatages — celui de la bourse et celui du SIP lors de la publication — et l'écart entre les deux correspond à l'étape de consolidation.
Le SQL exact derrière chaque chiffre
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)L'écart médian sur le SPY était de 229.1 microsecondes — des millionièmes de seconde — et de 203.4 pour Apple. La queue de distribution est plus épaisse que la médiane : le 99e percentile de Nvidia s'élevait à 536.9 microsecondes. Le SIP n'est pas lent au sens humain du terme. Deux autres facteurs le sont.
Premièrement, vos données peuvent être volontairement retardées. Les flux de cours gratuits dans les applications de détail et les sites de graphiques sont couramment retardés de 15 minutes selon les conditions de licence des bourses ; le streaming en temps réel est un service payant.
Deuxièmement, les firmes professionnelles n'attendent pas le SIP. Chaque bourse vend également un flux direct provenant de son propre moteur de matching. Une firme en colocalisation lit ce flux et calcule son propre best bid et offer avant que la version du SIP de cet événement n'arrive — un avantage de quelques microsecondes, décisif pour un market maker qui cote les deux côtés toute la journée.
Fréquence de mise à jour du NBBO : titres liquides vs titres peu liquides
Chaque action cotée possède un NBBO, et sa fréquence de mise à jour sert d'indicateur de liquidité. Ce tableau présente la moyenne des dernières sessions complètes pour quatre titres très échangés et deux small caps peu liquides — Nathan's Famous (NATH) et Seneca Foods (SENEA).
Le SQL exact derrière chaque chiffre
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)Le SPY, l'ETF S&P 500, a enregistré en moyenne 3.428 millions de mises à jour du NBBO par session, soit 2031 fois le volume du titre le moins actif du tableau. Nvidia affiche une moyenne de 1.85 millions, Apple 1.336 millions. La chute est brutale : Seneca Foods a enregistré 8097 mises à jour par session moyenne, contre 1688 pour Nathan's Famous. Aucun opérateur ne peut lire un écran au rythme du SPY : le NBBO est un flux conçu pour les logiciels.
Quand le NBBO est le plus réactif : l'ouverture vs le milieu de journée
Le taux de mise à jour suit également un rythme quotidien. Le graphique présente la moyenne des mises à jour du NBBO d'Apple par minute, segmentée par tranches de trente minutes (heure de l'Est) ; la dernière colonne exprime chaque tranche en pourcentage de celle de 9h30.
Le SQL exact derrière chaque chiffre
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_timePendant la demi-heure suivant l'enchère d'ouverture, le NBBO d'Apple a enregistré en moyenne 5657 mises à jour par minute, et la tranche de 10h00 a maintenu ce rythme à 89.5% de ce niveau. Le flux de données diminue ensuite durant la mi-journée : la tranche de 14h30 affichait 1973 mises à jour par minute, soit 34.9% du rythme d'ouverture. La montée en puissance vers la clôture à 15h30 ne compense qu'une partie de la baisse — 3345 mises à jour par minute, soit 59.1% de l'ouverture — l'activité de cotation la plus intense se situait donc durant la première heure et non la dernière. En dehors des horaires réguliers, le flux est quasi inexistant, tombant à 17 mises à jour par minute après la cloche de 16h00.
What happens to the NBBO during a trading halt?
When a stock moves too far too fast, the limit-up/limit-down rules pause it for five minutes. The quote neither vanishes nor stays live: it stops being refreshed, and the last record before the pause is the frame left on your screen. GameStop (GME) tripped such a pause just after 11:00 a.m. Eastern on May 14, 2024; the panel tracks its quote updates and trades, minute by minute, across it.
Le SQL exact derrière chaque chiffre
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_minIn the minute before the pause, 11:00, GameStop's consolidated quote updated 4511 times against 12419 trades. Then both columns fall off a shelf: 0 quote records at 11:02 and 0 at 11:03, with 0 trades to match — a quote that has stopped moving, in a stock that has stopped trading. Quoting returns at 11:06, the reopening minute, with 4155 updates and 14007 trades, the heaviest trade minute in the table. A halted stock's last NBBO is a fossil, not a tradable price; the January 2021 GameStop session shows what a chain of such pauses does to a tape.
Pourquoi votre courtier doit vous exécuter au NBBO ou mieux
Le NBBO est une référence réglementaire. La Regulation NMS — le corpus de règles sur la structure du marché adopté par la SEC en 2005 — inclut la Rule 611 (order-protection rule) : une plateforme ne peut pas exécuter une transaction à un prix moins favorable qu'une cotation protégée affichée sur une autre plateforme. Les courtiers ont également une obligation de best execution envers leurs clients, mesurée par rapport au NBBO : un ordre d'achat au marché doit être exécuté au national best ask ou moins cher ; un ordre de vente au marché doit être exécuté au national best bid ou plus cher.
La plupart des investisseurs particuliers ignorent ce point : votre ordre au marché n'atteint généralement jamais une plateforme d'échange. La majeure partie des flux exploitables des particuliers est dirigée vers des wholesalers — des teneurs de marché hors bourse qui paient pour obtenir ce flux — et exécutée en interne, puis reportée via une plateforme de reporting hors bourse. Le NBBO reste la référence pour eux : le wholesaler doit égaler ou battre la cotation nationale au moment de l'exécution. Il cherche à capter le flux en proposant un prix plus avantageux, soit une exécution à une fraction de centime à l'intérieur du spread, ce que l'on appelle le price improvement. Le NBBO est le prix de référence, pas la plateforme ; le type d'ordre que vous choisissez détermine si vous traversez le spread ou non.
FAQ
Le NBBO inclut-il les odd lots ?
Non. La cotation nationale est composée uniquement de round-lots. Selon la Reg NMS, la taille du round-lot varie selon le prix : 100 actions en dessous de 250 $, jusqu'à une seule action au-dessus de 10 000 $. Le plus petit bid affiché pour Ford était de 100 actions, contre 10 pour AutoZone, dont le cours est nettement plus élevé. Les odd lots avec un meilleur prix sont inclus dans le spread publié mais ne sont pas affichés.
Pourquoi la cotation de mon application de courtage diffère-t-elle du NBBO en direct ?
Il y a deux raisons, et aucune n'est liée au SIP. Les flux gratuits pour les particuliers subissent généralement un délai de 15 minutes selon les règles de licence des bourses, sauf en cas d'abonnement au temps réel. De plus, les données consolidées sont des instantanés publiés : l'étape de consolidation a mesuré une médiane de 229.1 microsecondes sur le SPY, alors que les entreprises utilisant les flux directs des bourses voient l'événement plus tôt.
Que devient le NBBO lorsqu'une action est suspendue ?
Il se fige. Lors de la pause de cinq minutes (limit-up/limit-down) de GameStop mentionnée plus haut, le tape a enregistré 0 mises à jour de cotation pour 11:03 et 0 transactions. La dernière cotation reste affichée mais n'est plus tradable ; une enchère de réouverture détermine la suivante.
Le NBBO existe-t-il en after-hours ?
Oui. Les cotations consolidées sont diffusées de 4h00 à 20h00 ET. Une cotation nationale existe donc durant le premarket et l'after-hours trading — à une cadence bien moindre que durant la journée : Apple enregistre 65 mises à jour par minute dans la dernière tranche du premarket contre 5657 après l'ouverture.
Notes sur les données : fenêtres et filtres
Les fenêtres glissantes se terminent trois jours avant la génération (un léger délai d'ingestion est présent en début de flux) et ne comptabilisent que les sessions complètes — les jours où le SPY affiche les 390 bougies de minute de la séance régulière. Le panel Coca-Cola exclut les enregistrements unilatéraux ou croisés ; les panels de comptage prennent chaque enregistrement tel quel (marchés verrouillés et croisés couvre les cas exclus). Le panel GameStop est fixé à une date précise, utilisant les bougies de minute du SPY comme référence temporelle ; les minutes de suspension s'affichent donc comme des zéros.
Chaque panel est livré avec le SQL ayant servi à sa production — ouvrez-en un, remplacez le ticker par le vôtre, et comptez ses mises à jour NBBO sur le terminal Strasmore.