Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

Pourquoi les market makers perdent de l’argent

La sélection adverse explique les pertes des market makers. Découvrez les courbes de markout, le risque d’inventaire et le coût lié à la position dans la file.

Les market makers perdent de l’argent à cause de la sélection adverse : le trader qui lève une offre est souvent celui qui sait déjà que cette offre est devenue obsolète. Chaque exécution commence par un petit crédit, d’environ la moitié du spread. Les secondes suivantes déterminent la part de ce crédit qui subsiste. L’outil de mesure est le markout, soit une variation de prix signée à un horizon fixe après une exécution. Les panneaux ci-dessous construisent de véritables courbes de markout à partir des prints de transactions et de cotations. Notre article complémentaire sur la manière dont les market makers gagnent de l’argent couvre le volet revenus de ce même bilan.

Qu’est-ce que la sélection adverse en trading ?

Un market maker affiche simultanément deux prix : un bid pour acheter et une offre pour vendre, chacun valable pour une quantité donnée. L’écart entre les deux est le bid ask spread, et le modèle économique repose sur une simple arithmétique. Acheter au bid, vendre à l’offre, puis recommencer des dizaines de milliers de fois par jour permet de percevoir en moyenne un montant proche du spread sur chaque aller-retour.

Cette arithmétique suppose que les deux côtés arrivent en équilibre. Ce n’est pas le cas. Une cotation passive est une option permanente que n’importe qui peut exercer au moment de son choix. Les traders les plus attentifs sélectionnent les meilleurs moments. Un fonds qui exécute un ordre parent important continue d’acheter tant que l’offre reste bon marché. Un système qui a déjà observé le mouvement d’un instrument corrélé prend le côté qui n’a pas encore été ajusté.

La sélection adverse désigne ce déséquilibre : les exécutions reçues par un market maker sont davantage le fait des traders qui avaient le plus intérêt à les obtenir. Le symptôme est l’écart entre le spread affiché par le market maker et le spread qu’il conserve réellement.

Qu’est-ce qu’un markout en market making ?

Le markout répond à une question posée après chaque exécution : où se situait le prix un nombre fixe de secondes plus tard, mesuré depuis le côté auquel j’étais exposé ? Supposons qu’un market maker vende 100 actions à 50,02 dollars, tandis que le midpoint se situe à 50,00 dollars. Cette exécution procure initialement un crédit de deux cents par action, soit 20 mils dans les unités du desk, un mil représentant un dixième de cent. Si le midpoint monte à 50,04 dollars soixante secondes plus tard, le markout à 60 secondes est de moins 20 mils. Le crédit initial a disparu, ainsi qu’un montant équivalent supplémentaire.

En calculant la moyenne sur toutes les exécutions d’une période, puis en la représentant selon l’horizon, on obtient une courbe de markout. Le panneau ci-dessous en construit une pour AAPL sur une fenêtre de trois heures en milieu de séance, le jeudi 14 mai 2026. Chaque print est signé par rapport au midpoint de la seconde durant laquelle il a été exécuté. Un print au-dessus du midpoint est considéré comme un achat par le taker, ce qui place le market maker du côté vendeur.

RequêtePart du spread conservée : courbe de markout d’AAPL, de 1 seconde à 5 minutes
Le SQL exact derrière chaque chiffre
WITH
  qs AS (
    SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
           avg((toFloat64(bid_price) + toFloat64(ask_price)) / 2) AS mid
    FROM global_markets.cache_stocks_quotes
    WHERE ticker = 'AAPL'
      AND sip_timestamp >= '2026-05-14 14:00:00'
      AND sip_timestamp <  '2026-05-14 17:06:00'
      AND bid_price > 0 AND ask_price > bid_price
    GROUP BY ts
  ),
  fills AS (
    SELECT t.ts AS ts, t.px AS px, t.shares AS shares, q.mid AS mid_at_fill,
           if(t.px > q.mid, 1, -1) AS taker_side
    FROM (
      SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
             toFloat64(price) AS px, toUInt64(size) AS shares
      FROM global_markets.stocks_trades
      WHERE ticker = 'AAPL'
        AND sip_timestamp >= '2026-05-14 14:00:00'
        AND sip_timestamp <  '2026-05-14 17:00:00'
        AND size > 0
    ) AS t
    INNER JOIN qs AS q ON q.ts = t.ts
    WHERE t.px != q.mid AND abs(t.px / q.mid - 1) < 0.02
  )
SELECT
  concat('+', toString(e.secs), 's')                          AS horizon,
  round(1000 * avg(e.taker_side * (e.px - e.mid_at_fill)), 2) AS edge_at_fill_mils,
  round(1000 * avg(e.taker_side * (e.px - f.mid)), 2)         AS edge_after_mils
FROM (
  SELECT toUInt32(ts + secs) AS future_ts, secs, px, mid_at_fill, taker_side
  FROM (SELECT *, arrayJoin([1, 5, 15, 30, 60, 300]) AS secs FROM fills)
) AS e
INNER JOIN qs AS f ON f.ts = e.future_ts
GROUP BY e.secs
ORDER BY e.secs
Run this yourself

La première série correspond au crédit au moment de l’exécution, c’est-à-dire l’écart entre le print et le midpoint, avec une moyenne de 19.66 mils par action. La deuxième série indique la valeur de ces mêmes exécutions après que le midpoint a eu le temps d’évoluer : 20.5 mils une seconde plus tard, puis 9.81 mils cinq minutes plus tard. L’écart entre les deux séries à chaque horizon constitue le markout. Il est prélevé sur le spread affiché par le market maker.

Une courbe qui baisse rapidement avant de s’aplatir décrit un market maker qui paie la réévaluation immédiate, mais conserve le solde. Une courbe qui continue d’évoluer dans le même sens à tous les horizons décrit des exécutions du mauvais côté d’un prix qui poursuit son mouvement. La première forme représente un coût normal de l’activité. La seconde indique que la cotation doit être modifiée.

Quels sont les flux toxiques ?

Le terme « toxique » a ici un sens technique. Un flux est toxique lorsque sa courbe de markout évolue contre le market maker qui l’a exécuté, à tous les horizons, sur un échantillon suffisamment large. Les desks classent les exécutions selon tous les attributs disponibles : taille du print, plateforme, type d’ordre et identifiant de la contrepartie. La taille est l’attribut visible dans le tape public.

RequêteExécutions AAPL par taille de transaction : crédit à l’exécution et valeur 60 secondes plus tard
Le SQL exact derrière chaque chiffre
WITH
  qs AS (
    SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
           avg((toFloat64(bid_price) + toFloat64(ask_price)) / 2) AS mid
    FROM global_markets.cache_stocks_quotes
    WHERE ticker = 'AAPL'
      AND sip_timestamp >= '2026-05-14 14:00:00'
      AND sip_timestamp <  '2026-05-14 17:06:00'
      AND bid_price > 0 AND ask_price > bid_price
    GROUP BY ts
  ),
  fills AS (
    SELECT t.ts AS ts, t.px AS px, t.shares AS shares, q.mid AS mid_at_fill,
           if(t.px > q.mid, 1, -1) AS taker_side
    FROM (
      SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
             toFloat64(price) AS px, toUInt64(size) AS shares
      FROM global_markets.stocks_trades
      WHERE ticker = 'AAPL'
        AND sip_timestamp >= '2026-05-14 14:00:00'
        AND sip_timestamp <  '2026-05-14 17:00:00'
        AND size > 0
    ) AS t
    INNER JOIN qs AS q ON q.ts = t.ts
    WHERE t.px != q.mid AND abs(t.px / q.mid - 1) < 0.02
  )
SELECT
  multiIf(s.shares < 100, 'under 100 shares',
          s.shares < 500, '100 to 499',
          s.shares < 1000, '500 to 999',
          '1,000 or more')                                    AS size_bucket,
  count()                                                     AS fills_count,
  round(1000 * avg(s.taker_side * (s.px - s.mid_at_fill)), 2) AS edge_at_fill_mils,
  round(1000 * avg(s.taker_side * (s.px - f.mid)), 2)         AS edge_after_60s_mils
FROM (SELECT *, toUInt32(ts + 60) AS future_ts FROM fills) AS s
INNER JOIN qs AS f ON f.ts = s.future_ts
GROUP BY size_bucket
ORDER BY min(s.shares)
Run this yourself

Les exécutions de moins de 100 actions commencent avec un crédit de 19.47 mils par action et valent 15.22 mils une minute plus tard. Les prints de 1 000 actions ou plus commencent avec 36.26 mils et valent 21.34 mils sur le même horizon. Même instrument, mêmes trois heures, mais une économie différente par action. Les ordres les plus importants évitent souvent entièrement la file publique, ce qui est précisément l’objectif d’un block trade.

Risque d’inventaire : la position qui ne peut pas être couverte à temps

Un horizon de markout est aussi une horloge. Un market maker qui achète 5 000 actions au bid détient 5 000 actions. Tant que la position n’est pas couverte ou revendue, elle reste exposée à l’évolution future du prix. La couverture est rarement instantanée. Une position sur une action peut être compensée par un ETF corrélé ou une position sur options, chacun impliquant son propre spread à franchir. Le risque d’inventaire correspond à l’ampleur du mouvement qui peut se produire pendant cette fenêtre. Il se mesure de la même façon pour chaque valeur. Jusqu’où le prix évolue-t-il généralement au cours de la prochaine minute, puis de l’heure suivante ?

RequêteÉvolution du prix pendant l’attente d’une position : SPY et NVDA, mai 2026
Le SQL exact derrière chaque chiffre
WITH
  bars AS (
    SELECT ticker, window_start,
           toDate(toTimeZone(window_start, 'America/New_York')) AS et_date,
           toFloat64(close) AS px
    FROM global_markets.delayed_stocks_minute_aggs
    WHERE ticker IN ('SPY', 'NVDA')
      AND window_start >= '2026-05-01 00:00:00'
      AND window_start <  '2026-06-01 00:00:00'
      AND transactions >= 50
      AND close > 0
  ),
  starts AS (
    SELECT ticker, et_date, px, mins,
           window_start + toIntervalMinute(mins) AS future_start
    FROM (SELECT *, arrayJoin([1, 2, 5, 15, 30, 60]) AS mins FROM bars)
  )
SELECT
  concat(toString(s.mins), ' min')                                AS hold_horizon,
  round(avgIf(abs(f.px / s.px - 1) * 10000, s.ticker = 'SPY'), 1)  AS spy_drift_bps,
  round(avgIf(abs(f.px / s.px - 1) * 10000, s.ticker = 'NVDA'), 1) AS nvda_drift_bps
FROM starts AS s
INNER JOIN bars AS f
  ON f.ticker = s.ticker AND f.et_date = s.et_date AND f.window_start = s.future_start
GROUP BY s.mins
HAVING countIf(s.ticker = 'SPY') > 0 AND countIf(s.ticker = 'NVDA') > 0
ORDER BY s.mins
Run this yourself

Sur l’ensemble du mois de mai 2026, le mouvement absolu moyen de SPY sur une minute a été de 1.9 points de base, un point de base représentant un centième de pour cent. Celui de NVDA a été de 5.5 sur la même durée. En passant à un horizon d’une heure, les deux chiffres deviennent 14.1 et 40.4. Un market maker capable de déboucler sa position en moins d’une minute doit composer avec le premier couple de chiffres. Celui qui conserve sa position pendant une heure doit composer avec le second, alors que le crédit encaissé lors de l’exécution est identique dans les deux cas.

Pourquoi les market makers perdent de l’argent en queue de file

Les exchanges exécutent les ordres passifs à un même prix dans leur ordre d’arrivée : d’abord le prix, puis le temps. Un ordre placé en queue d’une file de 40 000 actions au bid doit attendre l’exécution des 40 000 actions qui le précèdent. L’estimation de la position dans la file constitue une discipline à part entière.

La difficulté tient à la définition de la purge de la file. Une file se vide de deux manières. Les vendeurs continuent de frapper le bid jusqu’à épuisement du niveau, ou le prix descend sous ce niveau et le laisse derrière lui. Un ordre proche de la tête participe aux deux scénarios. Un ordre en queue de file est principalement exécuté selon le second scénario, au moment où le niveau est sur le point de devenir l’ancien prix. Deux market makers peuvent négocier le même instrument au même prix et en conserver une part différente. La position dans la file n’apparaît jamais dans le spread affiché, puisque les deux market makers ont affiché le même prix. Elle apparaît dans la courbe de markout.

Pourquoi élargir la cotation n’est pas une solution gratuite

La réponse évidente à une mauvaise courbe de markout consiste à élargir la cotation. Une cotation plus large rapporte davantage par exécution, mais entraîne moins d’exécutions. Les deux aspects de cet arbitrage apparaissent dans les prints de la même journée, classés selon l’écart de chaque print par rapport au midpoint.

RequêteTransactions AAPL selon la distance au midpoint : part du volume et markout à 60 secondes
Le SQL exact derrière chaque chiffre
WITH
  qs AS (
    SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
           avg((toFloat64(bid_price) + toFloat64(ask_price)) / 2) AS mid
    FROM global_markets.cache_stocks_quotes
    WHERE ticker = 'AAPL'
      AND sip_timestamp >= '2026-05-14 14:00:00'
      AND sip_timestamp <  '2026-05-14 17:06:00'
      AND bid_price > 0 AND ask_price > bid_price
    GROUP BY ts
  ),
  fills AS (
    SELECT t.ts AS ts, t.px AS px, t.shares AS shares, q.mid AS mid_at_fill,
           if(t.px > q.mid, 1, -1) AS taker_side
    FROM (
      SELECT toUnixTimestamp(toDateTime(sip_timestamp)) AS ts,
             toFloat64(price) AS px, toUInt64(size) AS shares
      FROM global_markets.stocks_trades
      WHERE ticker = 'AAPL'
        AND sip_timestamp >= '2026-05-14 14:00:00'
        AND sip_timestamp <  '2026-05-14 17:00:00'
        AND size > 0
    ) AS t
    INNER JOIN qs AS q ON q.ts = t.ts
    WHERE t.px != q.mid AND abs(t.px / q.mid - 1) < 0.02
  )
SELECT
  multiIf(s.cents <= 0.5, '0.5 cents or less',
          s.cents <= 1.0, '0.5 to 1 cent',
          s.cents <= 2.0, '1 to 2 cents',
          'over 2 cents')                                  AS distance_from_mid,
  round(100 * sum(s.shares) / sum(sum(s.shares)) OVER (), 2) AS share_of_volume_pct,
  round(1000 * avg(s.taker_side * (s.px - f.mid)), 2)        AS edge_after_60s_mils
FROM (
  SELECT *, toUInt32(ts + 60) AS future_ts, abs(px - mid_at_fill) * 100 AS cents
  FROM fills
) AS s
INNER JOIN qs AS f ON f.ts = s.future_ts
GROUP BY distance_from_mid
ORDER BY min(s.cents)
Run this yourself

Les prints situés à moins d’un demi-cent du midpoint représentaient 27.58 pour cent des actions de la fenêtre et valaient 0.95 mils par action une minute plus tard. Les prints situés à plus de deux cents du midpoint représentaient 33.19 pour cent des actions, pour une valeur de 46.86 mils. Une cotation plus éloignée du midpoint est atteinte par une part plus faible du volume de la journée.

Le taux d’exécution est le premier coût du retrait. Les rebates versés par les exchanges constituent le deuxième, car de nombreuses plateformes rémunèrent le market maker pour chaque action exécutée. Ce revenu dépend du nombre d’actions plutôt que de la largeur de la cotation. Les paliers de volume qui déterminent le taux de rebate sont calculés chaque mois. Un mois calme modifie donc la rémunération de chaque exécution le mois suivant. Abandonner sa place dans la file est le dernier coût. Il est payé à la sortie, puis à nouveau lorsque le market maker revient en queue de file. Chaque market maker se situe quelque part sur cette courbe. Ceux qui mesurent leurs propres markouts avec le plus de précision peuvent rester au plus près du touch tout en conservant le crédit. Cette mesure constitue l’avantage que défendent les plus grands market makers.

FAQ

Les market makers perdent-ils de l’argent sur certaines transactions ?

Régulièrement. Un book de market making est composé d’une distribution de petits gains et de petites pertes. Les exécutions perdantes se concentrent dans les instants qui précèdent un mouvement de prix. L’activité repose sur la moyenne calculée sur des millions d’exécutions.

Qu’est-ce qu’un markout en trading ?

Un markout est la variation du prix de marché à un horizon fixe après une exécution, signée du point de vue de l’un des côtés. Un nombre positif signifie que ce côté a gagné. Les desks actions expriment les markouts en mils par action, tandis que les desks options les expriment en ticks par contrat.

Que signifie « flux d’ordres toxique » ?

Cette expression désigne un flux d’ordres dont la courbe de markout évolue durablement contre le market maker qui l’exécute. Le prix continue donc de s’éloigner après chaque exécution. Le terme décrit une propriété statistique d’un flux d’ordres. Il ne porte aucun jugement sur un trader donné.

Pourquoi les market makers élargissent-ils les spreads au lieu de retirer leurs cotations ?

Une cotation plus large permet au market maker de rester présent à un prix qui compense une courbe de markout moins favorable. Retirer la cotation ne rapporte rien et fait perdre la position dans la file. Les desks font les deux. Leur choix dépend de la durée pendant laquelle la cotation devrait rester obsolète.

Comment mesure-t-on la sélection adverse ?

Avec des markouts. Chaque exécution est signée selon le côté auquel se trouvait le market maker. On calcule ensuite la variation moyenne du midpoint à des horizons fixes. L’écart entre le crédit au moment de l’exécution et la valeur à chaque horizon correspond au coût de la sélection adverse, exprimé dans les mêmes unités que le spread.

Comment ces chiffres ont été construits

Chaque panneau consacré à AAPL repose sur deux sources publiques : le tape des transactions et le tape des cotations. Chaque print exécuté entre 14:00 et 17:00 UTC le 14 mai 2026 est associé au midpoint moyen du national best bid and offer de la seconde durant laquelle il a été exécuté, puis signé. Un print au-dessus de ce midpoint est considéré comme un achat par le taker, ce qui place le market maker du côté vendeur. Les prints exactement au midpoint ne sont attribués à aucun côté et sont exclus, de même que tout print situé à plus de 2 pour cent du midpoint. Les cotations dont le bid est égal ou supérieur à l’offre sont exclues, car un marché locked ou crossed ne fournit aucun midpoint exploitable.

La mise en correspondance au niveau de la seconde permet d’approcher la cotation en vigueur à la microseconde de l’exécution et lisse les mises à jour les plus rapides. Les prix aux différents horizons proviennent des mêmes midpoints calculés à la seconde. Le panneau consacré à l’inventaire utilise des barres d’une minute et ne conserve que celles qui comptent au moins 50 prints, ce qui concentre l’échantillon sur les heures les plus actives de la journée.


Chaque panneau présente le SQL qui l’a produit. Le calcul du markout peut donc être vérifié ligne par ligne. Pour reconstruire la courbe sur une autre valeur ou une autre journée, formulez votre demande en anglais courant dans le terminal Strasmore.