Trade markout: qualità dell’esecuzione spiegata
Che cos’è un trade markout? La convenzione del segno spiegata in modo chiaro, con una curva reale misurata da un secondo a cinque minuti.
Un trade markout è la variazione del mid price su un orizzonte temporale fisso dopo un fill, misurata dal momento in cui quel fill è stato eseguito. Un valore positivo indica che il mercato si è mosso a tuo favore dopo l’esecuzione. Un valore negativo indica che si è mosso contro di te: è ciò che i desk chiamano adverse selection. L’orizzonte scelto, un secondo o cinque minuti, determina quale domanda sta rispondendo quel valore.
Che cos’è un trade markout?
Si parte dal mid price: il punto intermedio tra il best bid e il best offer, il midpoint di NBBO. Il markout prende il mid a un orizzonte scelto dopo il fill, sottrae un prezzo di riferimento e assegna un segno al risultato in base al lato dell’operazione.
**markout all’orizzonte h = lato * (mid a t+h - prezzo di riferimento)**, dove lato è più uno se hai acquistato e meno uno se hai venduto.
La convenzione sui segni è la principale fonte di confusione. Un acquisto seguito da una discesa del mid ha un markout negativo: hai comprato, il prezzo è sceso e chi ti ha venduto il titolo ha realizzato il risultato migliore su quell’operazione. È l’adverse selection espressa da un numero. Una vendita seguita da una discesa del mid ha un markout positivo, perché il segno cambia in base al lato. Ogni fill ha due lati e il markout di un lato è quello dell’altro con segno opposto.
I tre prezzi di riferimento
Il prezzo che sottrai determina che cosa misura il markout.
- Il prezzo del fill. Il markout diventa un valore monetario: quanto vale la posizione a t+h rispetto a quanto hai pagato. Lo spread pagato o incassato è incluso nel calcolo.
- Il mid al momento del fill. Questo esclude lo spread e isola il movimento del mercato dopo l’operazione. È la lettura più chiara dell’adverse selection.
- La quotazione sul lato in cui hai operato. Misurare rispetto al touch che hai colpito, o al touch al quale hai inserito l’ordine, mostra come il fill si confronta con il prezzo effettivamente disponibile.
Le analisi della qualità dell’esecuzione usano soprattutto il secondo riferimento per l’adverse selection e il primo per il profit and loss. Entrambi sono riportati nel primo pannello qui sotto, sulla stessa serie di fill.
La curva del markout e il significato della sua forma
Calcolando la stessa statistica su molti orizzonti si ottiene una curva. La sua forma contiene più informazioni di qualunque singolo valore.
- Una curva che scende rapidamente nel primo secondo e poi resta bassa descrive un flusso di ordini intercettato: il prezzo si muove quasi subito contro il fill.
- Una curva che continua a scendere per diversi minuti descrive un flusso che conteneva informazioni effettive sulla direzione del prezzo.
- Una curva piatta vicino allo zero descrive un flusso benigno. Dopo cinque minuti, il mid è simile a quello osservato al momento del fill.
- Una curva che parte negativa e risale verso zero è la forma che cerca un market maker passivo che incassa rebate. La discesa iniziale riflette lo spread e l’impatto immediato; il recupero indica il ritorno del mercato.
La scelta dell’orizzonte è una decisione su ciò che si vuole misurare. Sotto il secondo, il markout riflette soprattutto la latenza e la posizione nella coda. Estendendolo a un minuto, misura le informazioni di breve periodo contenute nel flusso. Oltre cinque minuti, il normale drift del mercato inizia a prevalere sull’effetto del fill.
Una curva reale del markout, fill per fill
Il pannello seguente include ogni print su INTC della sessione regolare del 10 giugno 2026, classifica ciascuno come buy initiated o sell initiated rispetto all’ultima quotazione del secondo precedente all’esecuzione e calcola la media del markout con segno su 5 orizzonti. Le due serie usano gli stessi fill: una è misurata dal mid al momento del fill, l’altra dal prezzo del fill.
L'esatto SQL dietro ogni numero
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_sSui 900593 fill classificati, la serie basata sul mid registra 3.068 punti base a 1 sec e 2.977 punti base a 5 min. Un punto base è un centesimo di punto percentuale del prezzo: il movimento di un singolo fill può essere trascurabile, mentre su un milione di azioni può rappresentare denaro reale.
La serie basata sul prezzo del fill parte da -0.488 punti base. La distanza tra le due serie sull’orizzonte più breve è il mezzo spread effettivo: la distanza tra il print e il mid. Un taker lo paga in entrata, mentre un maker lo incassa. Tutto ciò che si osserva oltre il primo orizzonte è il movimento del mercato.
La dimensione del fill e la forma della curva
L’adverse selection non è distribuita in modo uniforme tra i fill. Dividendo la stessa sessione per dimensione dei print, si possono confrontare sugli stessi assi i piccoli fill e i blocchi da almeno mille azioni.
L'esatto SQL dietro ogni numero
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_sAll’orizzonte 5 min, i print inferiori a mille azioni registrano in media 2.983 punti base, mentre i 11588 print da almeno mille azioni registrano in media 2.495. Due quotazioni che eseguono lo stesso volume totale contro questi due gruppi non arrivano allo stesso risultato a fine giornata.
Come i markout diventano i valori dello spread nei report di esecuzione
Il markout è il termine mancante nella scomposizione standard dello spread. L’effective spread è ciò che un taker ha effettivamente pagato: il doppio della distanza con segno tra il mid e il print. Lo si divide in due componenti. Una è il realized spread, cioè ciò che un maker conserva dopo il movimento del mercato. L’altra è l’adverse selection, pari al doppio del markout basato sul mid. L’identità è esatta: effective spread = realized spread + adverse selection.
L'esatto SQL dietro ogni numero
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_timeNella mezz’ora iniziata alle 09:30 Eastern, l’effective spread è in media pari a 10.651 punti base. Di questi, 8.313 rappresentano la componente di adverse selection su un orizzonte di sessanta secondi e 2.338 ciò che il maker conserva. Il pannello copre 13 intervalli di mezz’ora.
Queste componenti sono i valori riepilogati venue per venue nei report di esecuzione Rule 605 e 606 e costituiscono la base aritmetica delle dichiarazioni sul price improvement collegate a sub penny rule e price improvement. Un rebate è un credito fisso per azione. L’adverse selection è un costo variabile per azione sui fill effettivamente ricevuti da una quotazione. Confrontare l’uno con l’altra lungo una curva misurata, anziché sulla base di un rate card pubblicizzato, è il controllo alla base dell’analisi di maker taker fees e rebate e si affianca ai meccanismi descritti in perché i market maker perdono denaro.
Come sono stati calcolati questi valori
Ogni pannello utilizza quotazioni e print su INTC della sessione regolare del 10 giugno 2026, dalle 09:30 alle 16:00 Eastern. Le quotazioni vengono ridotte a un mid per secondo, utilizzando l’ultima quotazione registrata all’interno di quel secondo. Un print è classificato come buy initiated quando viene eseguito sopra il mid del secondo precedente e come sell initiated quando viene eseguito sotto, secondo la regola standard basata sulle quotazioni. I print eseguiti esattamente su quel mid vengono esclusi, invece di essere classificati arbitrariamente; le esecuzioni al midpoint restano quindi fuori dal campione. L’uso del mid del secondo precedente come riferimento evita di utilizzare informazioni future. Gli orizzonti sono espressi in secondi interi, conteggiati dal secondo del print, e un fill entra nel calcolo di un orizzonte solo quando esiste una quotazione nel secondo obiettivo.
Domande frequenti
Che cos’è un markout nel trading?
Un markout è la variazione con segno del mid price su un orizzonte temporale fisso dopo un fill. Un valore positivo indica che il mercato si è mosso nella direzione della tua operazione dopo l’esecuzione. Un valore negativo indica che si è mosso nella direzione opposta: questa è la definizione di adverse selection.
Un markout negativo indica sempre un’esecuzione negativa?
No. Un markout negativo a un secondo su un ordine marketable riflette soprattutto lo spread pagato dall’ordine, cioè il costo dell’esecuzione immediata. È più importante osservare se la curva continua a scendere sugli orizzonti più lunghi o se si stabilizza.
Qual è la differenza tra markout e slippage?
Lo slippage confronta un fill con un prezzo decisionale o con un arrival price, quindi valuta l’intero percorso di un ordine. Il markout confronta un fill con il mid a un determinato orizzonte dopo l’esecuzione, quindi valuta ciò che è accaduto successivamente. Il primo misura l’ordine principale, il secondo il singolo fill.
Quale orizzonte dovrebbe usare un markout?
Dipende dallo scopo del fill. Gli orizzonti inferiori al secondo valutano le esecuzioni sensibili alla latenza, mentre un minuto è il riferimento più comune per l’adverse selection sui titoli liquidi. Indicare l’orizzonte accanto al valore è ciò che rende almeno comparabili due markout.
Qual è il rapporto tra markout ed effective spread?
L’effective spread si scompone in realized spread e componente di adverse selection. Quest’ultima è pari al doppio del markout basato sul mid. Cambiando l’orizzonte cambia anche la ripartizione tra le due componenti. Per questo una statistica sullo spread è incompleta se non indica il relativo orizzonte.
Ogni pannello include il codice SQL che lo ha prodotto. Aprilo, sostituisci il ticker o la data e ricostruisci da zero la stessa curva del markout sul terminale Strasmore.