Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

Trade markout : mesurer la qualité d’exécution

Définition du trade markout, convention de signe et courbe réelle mesurée d’une seconde à cinq minutes pour évaluer l’adverse selection.

Un trade markout est l’évolution du mid sur un horizon fixe après une exécution, mesurée à partir du moment où cette exécution a été enregistrée. Un résultat positif signifie que le marché a évolué en votre faveur après votre trade. Un résultat négatif signifie qu’il a évolué contre vous, ce que les desks appellent l’adverse selection. L’horizon retenu, une seconde ou cinq minutes par exemple, détermine la question à laquelle répond le chiffre.

Qu’est-ce qu’un trade markout ?

Commencez par le mid : le point situé à mi-chemin entre le meilleur bid et la meilleure offre, le midpoint de la NBBO. Un markout prend ce mid à un horizon donné après votre exécution, lui soustrait un prix de référence, puis affecte le résultat du signe correspondant au sens du trade.

**markout à l’horizon h = side * (mid à t+h - prix de référence)**, où side vaut plus un si vous avez acheté et moins un si vous avez vendu.

La convention de signe est généralement à l’origine de la confusion. Si le mid baisse après un achat, le markout est négatif : vous avez acheté, le prix a baissé et la contrepartie qui vous a vendu le titre a réalisé la meilleure opération. C’est l’adverse selection exprimée sous forme chiffrée. Si le mid baisse après une vente, le markout est positif, car le signe s’inverse selon le sens du trade. Chaque exécution comporte deux contreparties, et le markout de l’une est l’opposé, en signe, de celui de l’autre.

Les trois prix de référence

Le prix de référence que vous soustrayez détermine ce que mesure le markout.

  • Le prix d’exécution. Le markout devient une mesure monétaire : il indique la valeur de la position à t+h par rapport au prix payé. Le spread payé ou perçu est inclus.
  • Le mid au moment de l’exécution. Cette méthode neutralise le spread et isole l’évolution du marché après le trade. C’est la mesure la plus directe de l’adverse selection.
  • La quote du côté traité. Une mesure par rapport au touch pris, ou au touch affiché, indique comment l’exécution se compare au prix effectivement disponible.

Les analyses de qualité d’exécution utilisent principalement la deuxième méthode pour l’adverse selection et la première pour le profit et la perte. Les deux apparaissent dans le premier panneau ci-dessous, sur un même ensemble d’exécutions.

La courbe de markout et la signification de sa forme

Calculez la même statistique sur de nombreux horizons et vous obtenez une courbe. Sa forme apporte davantage d’informations qu’un chiffre isolé.

  • Une courbe qui chute fortement pendant la première seconde et reste basse traduit un flux qui se fait prendre de vitesse : le prix évolue presque immédiatement contre l’exécution.
  • Une courbe qui continue de baisser pendant plusieurs minutes indique que le flux contenait une information réelle sur la direction du prix.
  • Une courbe stable autour de zéro décrit un flux sans effet marqué. Cinq minutes plus tard, le mid est proche de son niveau au moment de l’exécution.
  • Une courbe qui commence en territoire négatif puis remonte vers zéro correspond au profil recherché par un market maker passif qui perçoit des rebates. Le creux initial reflète le spread et l’impact immédiat ; la remontée traduit le retour du marché.

Le choix de l’horizon détermine lui-même ce que vous mesurez. En dessous d’une seconde, le markout reflète surtout la latence et la queue position. Sur une minute, il mesure l’information à court terme contenue dans le flux. Au-delà de cinq minutes, l’évolution normale du marché commence à dominer l’effet de l’exécution.

Une véritable courbe de markout, exécution par exécution

Le panneau ci-dessous prend tous les prints sur INTC pendant la séance régulière du 10 juin 2026, classe chacun comme initié à l’achat ou à la vente par rapport à la dernière quote de la seconde précédant son enregistrement, puis calcule la moyenne du markout signé sur des horizons 5. Deux séries portent sur les mêmes exécutions : l’une est mesurée à partir du mid au moment de l’exécution, l’autre à partir du prix d’exécution.

RequêteCourbe de markout d’INTC, 10 juin 2026, mesurée à partir de deux bases de référence
Le SQL exact derrière chaque chiffre
WITH
    mid_by_second AS
    (
        SELECT
            dateDiff('second', toDateTime('2026-06-10 13:30:00', 'UTC'), sip_timestamp) AS sec,
            argMax((toFloat64(bid_price) + toFloat64(ask_price)) / 2, sip_timestamp)    AS mid
        FROM global_markets.cache_stocks_quotes
        WHERE ticker = 'INTC'
          AND sip_timestamp >= toDateTime('2026-06-10 13:30:00', 'UTC')
          AND sip_timestamp <  toDateTime('2026-06-10 20:00:00', 'UTC')
          AND bid_price > 0
          AND ask_price > bid_price
        GROUP BY sec
    ),
    signed_fills AS
    (
        SELECT
            t.sec        AS sec,
            t.fill_price AS fill_price,
            q.mid        AS ref_mid,
            if(t.fill_price > q.mid, 1, -1) AS side
        FROM
        (
            SELECT
                dateDiff('second', toDateTime('2026-06-10 13:30:00', 'UTC'), sip_timestamp) AS sec,
                sec - 1          AS ref_sec,
                toFloat64(price) AS fill_price
            FROM global_markets.stocks_trades
            WHERE ticker = 'INTC'
              AND sip_timestamp >= toDateTime('2026-06-10 13:30:01', 'UTC')
              AND sip_timestamp <  toDateTime('2026-06-10 19:55:00', 'UTC')
              AND price > 0
              AND size > 0
        ) AS t
        INNER JOIN mid_by_second AS q ON q.sec = t.ref_sec
        WHERE t.fill_price != q.mid
    )
SELECT
    multiIf(f.horizon_s < 60,
            concat(toString(f.horizon_s), ' sec'),
            concat(toString(intDiv(f.horizon_s, 60)), ' min'))              AS horizon,
    round(avg(f.side * (fut.mid - f.ref_mid) / f.ref_mid) * 10000, 3)       AS mid_basis_bps,
    round(avg(f.side * (fut.mid - f.fill_price) / f.fill_price) * 10000, 3) AS fill_basis_bps,
    count()                                                                 AS fill_count
FROM
(
    SELECT
        sec,
        fill_price,
        ref_mid,
        side,
        horizon_s,
        sec + horizon_s AS future_sec
    FROM signed_fills
    ARRAY JOIN [1, 5, 15, 60, 300] AS horizon_s
) AS f
INNER JOIN mid_by_second AS fut ON fut.sec = f.future_sec
GROUP BY f.horizon_s
ORDER BY f.horizon_s
Run this yourself

Sur 900593 exécutions classées, la série calculée sur le mid affiche 3.068 points de base à 1 sec et 2.977 points de base à 5 min. Un point de base représente un centième de pour cent du prix. Ainsi, une seule exécution peut produire un écart négligeable, tandis qu’un million d’actions représente un montant significatif.

La série calculée sur le prix d’exécution commence à -0.488 points de base. L’écart entre les deux séries sur l’horizon le plus court correspond au demi-spread effectif : la distance entre le print et le mid. Un taker le paie à l’entrée et un maker le perçoit. Tout ce qui intervient au-delà du premier horizon correspond à l’évolution du marché.

La taille des exécutions et la forme de la courbe

L’adverse selection ne se répartit pas uniformément entre les exécutions. En ventilant la même séance selon la taille des prints, on place les petites exécutions et les blocs de mille actions ou plus sur les mêmes axes.

RequêteMême courbe, ventilée par taille d’exécution : petites exécutions vs blocs
Le SQL exact derrière chaque chiffre
WITH
    mid_by_second AS
    (
        SELECT
            dateDiff('second', toDateTime('2026-06-10 13:30:00', 'UTC'), sip_timestamp) AS sec,
            argMax((toFloat64(bid_price) + toFloat64(ask_price)) / 2, sip_timestamp)    AS mid
        FROM global_markets.cache_stocks_quotes
        WHERE ticker = 'INTC'
          AND sip_timestamp >= toDateTime('2026-06-10 13:30:00', 'UTC')
          AND sip_timestamp <  toDateTime('2026-06-10 20:00:00', 'UTC')
          AND bid_price > 0
          AND ask_price > bid_price
        GROUP BY sec
    ),
    signed_fills AS
    (
        SELECT
            t.sec        AS sec,
            t.fill_size  AS fill_size,
            q.mid        AS ref_mid,
            if(t.fill_price > q.mid, 1, -1) AS side
        FROM
        (
            SELECT
                dateDiff('second', toDateTime('2026-06-10 13:30:00', 'UTC'), sip_timestamp) AS sec,
                sec - 1          AS ref_sec,
                toFloat64(price) AS fill_price,
                size             AS fill_size
            FROM global_markets.stocks_trades
            WHERE ticker = 'INTC'
              AND sip_timestamp >= toDateTime('2026-06-10 13:30:01', 'UTC')
              AND sip_timestamp <  toDateTime('2026-06-10 19:55:00', 'UTC')
              AND price > 0
              AND size > 0
        ) AS t
        INNER JOIN mid_by_second AS q ON q.sec = t.ref_sec
        WHERE t.fill_price != q.mid
    )
SELECT
    multiIf(f.horizon_s < 60,
            concat(toString(f.horizon_s), ' sec'),
            concat(toString(intDiv(f.horizon_s, 60)), ' min'))                                   AS horizon,
    round(avgIf(f.side * (fut.mid - f.ref_mid) / f.ref_mid, f.fill_size < 1000) * 10000, 3)       AS small_fill_bps,
    round(avgIf(f.side * (fut.mid - f.ref_mid) / f.ref_mid, f.fill_size >= 1000) * 10000, 3)      AS block_fill_bps,
    countIf(f.fill_size >= 1000)                                                                 AS block_fill_count
FROM
(
    SELECT
        sec,
        fill_size,
        ref_mid,
        side,
        horizon_s,
        sec + horizon_s AS future_sec
    FROM signed_fills
    ARRAY JOIN [1, 5, 15, 60, 300] AS horizon_s
) AS f
INNER JOIN mid_by_second AS fut ON fut.sec = f.future_sec
GROUP BY f.horizon_s
HAVING countIf(f.fill_size < 1000) > 0
   AND countIf(f.fill_size >= 1000) > 0
ORDER BY f.horizon_s
Run this yourself

À l’horizon 5 min, les prints de moins de mille actions affichent en moyenne 2.983 points de base, contre 2.495 pour les 11588 prints d’au moins mille actions. Deux quotes exécutant le même volume total face à ces deux groupes ne terminent pas la journée au même niveau.

Comment les markouts deviennent les chiffres de spread des rapports d’exécution

Le markout est le terme manquant de la décomposition standard du spread. L’effective spread correspond à ce qu’un taker a effectivement payé : deux fois la distance signée entre le mid et le print. Cette valeur se divise en deux. La première composante est le realized spread, c’est-à-dire ce que conserve un maker après l’évolution du marché. La seconde est l’adverse selection, soit le markout calculé sur le mid multiplié par deux. L’identité est exacte : effective spread = realized spread + adverse selection.

RequêteDécomposition du spread effectif en spread réalisé et sélection adverse, par demi-heure
Le SQL exact derrière chaque chiffre
WITH
    mid_by_second AS
    (
        SELECT
            dateDiff('second', toDateTime('2026-06-10 13:30:00', 'UTC'), sip_timestamp) AS sec,
            argMax((toFloat64(bid_price) + toFloat64(ask_price)) / 2, sip_timestamp)    AS mid
        FROM global_markets.cache_stocks_quotes
        WHERE ticker = 'INTC'
          AND sip_timestamp >= toDateTime('2026-06-10 13:30:00', 'UTC')
          AND sip_timestamp <  toDateTime('2026-06-10 20:00:00', 'UTC')
          AND bid_price > 0
          AND ask_price > bid_price
        GROUP BY sec
    ),
    signed_fills AS
    (
        SELECT
            t.sec + 60   AS future_sec,
            t.et_time    AS et_time,
            t.fill_price AS fill_price,
            q.mid        AS ref_mid,
            if(t.fill_price > q.mid, 1, -1) AS side
        FROM
        (
            SELECT
                dateDiff('second', toDateTime('2026-06-10 13:30:00', 'UTC'), sip_timestamp) AS sec,
                sec - 1          AS ref_sec,
                toFloat64(price) AS fill_price,
                formatDateTime(toStartOfInterval(toTimeZone(sip_timestamp, 'America/New_York'), toIntervalMinute(30)), '%H:%i') AS et_time
            FROM global_markets.stocks_trades
            WHERE ticker = 'INTC'
              AND sip_timestamp >= toDateTime('2026-06-10 13:30:01', 'UTC')
              AND sip_timestamp <  toDateTime('2026-06-10 19:55:00', 'UTC')
              AND price > 0
              AND size > 0
        ) AS t
        INNER JOIN mid_by_second AS q ON q.sec = t.ref_sec
        WHERE t.fill_price != q.mid
    )
SELECT
    f.et_time                                                                  AS et_time,
    round(avg(2 * f.side * (f.fill_price - f.ref_mid) / f.ref_mid) * 10000, 3) AS effective_spread_bps,
    round(avg(2 * f.side * (f.fill_price - fut.mid) / f.ref_mid) * 10000, 3)   AS realized_spread_bps,
    round(avg(2 * f.side * (fut.mid - f.ref_mid) / f.ref_mid) * 10000, 3)      AS adverse_selection_bps,
    count()                                                                    AS fill_count
FROM signed_fills AS f
INNER JOIN mid_by_second AS fut ON fut.sec = f.future_sec
GROUP BY f.et_time
ORDER BY f.et_time
Run this yourself

Pendant la demi-heure commençant à 09:30, heure de la côte Est, l’effective spread s’établit en moyenne à 10.651 points de base. Sur ce montant, 8.313 correspondent à l’adverse selection mesurée sur un horizon de soixante secondes et 2.338 à ce que conserve un maker. Le panneau couvre 13 intervalles d’une demi-heure.

Ces composantes sont les chiffres synthétisés venue par venue dans les rapports d’exécution Rule 605 et 606. Elles constituent aussi la base arithmétique des affirmations relatives à l’amélioration de prix associées à la règle du sub penny et à l’amélioration de prix. Un rebate est un crédit fixe par action. L’adverse selection est un coût variable par action sur les exécutions effectivement reçues par une quote. Comparer les deux sur une courbe mesurée, plutôt que sur une grille tarifaire affichée, permet de contrôler les maker taker fees et rebates. Cette analyse complète les mécanismes présentés dans pourquoi les market makers perdent de l’argent.

Comment ces chiffres ont été calculés

Chaque panneau utilise les quotes et les prints sur INTC pendant la séance régulière du 10 juin 2026, de 09:30 à 16:00, heure de la côte Est. Les quotes sont ramenées à un mid par seconde : le dernier mid enregistré pendant cette seconde. Un print est classé comme initié à l’achat lorsqu’il est exécuté au-dessus du mid de la seconde précédente, et comme initié à la vente lorsqu’il est exécuté en dessous. Il s’agit de la règle standard fondée sur les quotes. Les prints exécutés exactement sur ce mid sont exclus plutôt que classés arbitrairement ; les exécutions au midpoint ne font donc pas partie de l’échantillon. Utiliser le mid de la seconde précédente comme référence évite toute anticipation. Les horizons sont exprimés en secondes entières à compter de la seconde du print. Une exécution n’entre dans un horizon que si une quote existe pendant la seconde cible.

FAQ

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

Un markout est la variation signée du mid sur un horizon fixe après une exécution. Un résultat positif signifie que le marché a évolué dans le sens de votre trade après l’exécution. Un résultat négatif signifie qu’il a évolué dans l’autre sens, ce qui constitue la définition de l’adverse selection.

Un markout négatif signifie-t-il toujours que l’exécution est mauvaise ?

Non. Un markout négatif à une seconde sur un ordre marketable reflète principalement le spread payé par l’ordre, c’est-à-dire le prix de l’exécution immédiate. L’élément le plus important est de savoir si la courbe continue de baisser sur les horizons plus longs ou si elle se stabilise.

Quelle est la différence entre un markout et le slippage ?

Le slippage compare une exécution à un prix de décision ou à un prix d’arrivée. Il évalue donc l’ensemble du parcours d’un ordre. Le markout compare une exécution au mid observé à un horizon donné après cette exécution. Il évalue donc ce qui s’est passé ensuite. Le premier mesure l’ordre parent ; le second mesure l’exécution individuelle.

Quel horizon faut-il utiliser pour un markout ?

Cela dépend de l’objectif de l’exécution. Les horizons inférieurs à une seconde évaluent les exécutions sensibles à la latence. Une minute constitue l’horizon de référence courant pour mesurer l’adverse selection sur les valeurs liquides. Indiquer l’horizon à côté du chiffre est indispensable pour comparer deux markouts.

Quel est le lien entre un markout et l’effective spread ?

L’effective spread se décompose entre realized spread et adverse selection. Cette dernière correspond au markout calculé sur le mid, multiplié par deux. Modifier l’horizon modifie la répartition entre les deux composantes. C’est pourquoi une statistique de spread publiée est incomplète si son horizon n’est pas précisé.


Chaque panneau est accompagné du SQL qui l’a produit. Ouvrez-en un, remplacez le ticker ou la date, et la même courbe de markout sera recalculée à partir de zéro sur le terminal Strasmore.