Trade Markout: entenda a qualidade da execução
Entenda o que é trade markout, como funciona o sinal e veja uma curva real de 1 segundo a 5 minutos para avaliar adverse selection na execução.
Uma trade markout é a variação do preço médio ao longo de um horizonte fixo após uma execução, medida a partir do momento em que essa execução foi registrada. Um resultado positivo significa que o mercado se moveu a seu favor depois da operação. Um resultado negativo significa que se moveu contra você, o que os desks chamam de adverse selection. O horizonte escolhido, de um segundo ou cinco minutos, determina qual pergunta o número está respondendo.
O que é uma trade markout?
Comece pelo preço médio: o ponto intermediário entre a melhor oferta de compra e a melhor oferta de venda, o midpoint de o NBBO. A markout usa esse preço médio em um horizonte escolhido após a execução, subtrai um preço de referência e atribui sinal ao resultado conforme o lado da operação.
**markout no horizonte h = lado * (preço médio em t+h - preço de referência)**, em que lado é mais um se você comprou e menos um se você vendeu.
A convenção de sinal é a principal fonte de confusão. Uma compra seguida de queda do preço médio tem markout negativo: você comprou, o preço caiu e quem vendeu para você obteve o melhor resultado nessa operação. Isso é adverse selection expresso em um número. Uma venda seguida de queda do preço médio tem markout positivo, pois o sinal muda conforme o lado. Toda execução tem dois lados, e a markout de um lado é a do outro com o sinal invertido.
Os três preços de referência
O preço de referência subtraído determina o que a markout mede.
- O preço de execução. A markout passa a representar dinheiro: quanto a posição vale em t+h em comparação com o que você pagou. O spread pago ou recebido fica incluído nesse cálculo.
- O preço médio no momento da execução. Isso retira o spread do cálculo e isola o movimento do mercado depois da operação. É a leitura mais limpa de adverse selection.
- A cotação do lado em que você negociou. Medir em relação à melhor oferta que você tomou ou à melhor oferta que disponibilizou mostra como a execução se compara ao preço efetivamente disponível.
A análise da qualidade de execução usa principalmente o segundo preço para adverse selection e o primeiro para lucro e perda. Ambos aparecem no primeiro painel abaixo, sobre o mesmo conjunto de execuções.
A curva de markout e o significado do seu formato
Calcule a mesma estatística em vários horizontes e você terá uma curva. O formato dela revela mais do que qualquer número isolado.
- Uma curva que cai rapidamente no primeiro segundo e permanece baixa descreve fluxo sendo antecipado: o preço se move contra a execução quase imediatamente.
- Uma curva que continua caindo por minutos descreve fluxo que carregava informação efetiva sobre a direção do preço.
- Uma curva estável perto de zero descreve fluxo benigno. Cinco minutos depois, o preço médio está próximo do nível observado na execução.
- Uma curva que começa negativa e volta em direção a zero é o formato procurado por um market maker passivo que recebe rebates. A queda inicial é o spread mais o impacto imediato, e a recuperação representa o retorno do mercado.
A escolha do horizonte é uma decisão sobre o que está sendo medido. Abaixo de um segundo, a markout reflete principalmente latência e posição na fila. Ao estendê-la para um minuto, ela passa a captar a informação de curto prazo contida no fluxo. Depois de cinco minutos, o movimento normal do mercado começa a dominar o efeito da própria execução.
Uma curva de markout real, execução por execução
O painel abaixo considera todos os prints de INTC durante a sessão regular de 10 de junho de 2026, classifica cada um como iniciado por compra ou por venda em relação à última cotação do segundo anterior ao print e calcula a média da markout com sinal em 5 horizontes. Duas séries usam as mesmas execuções: uma medida a partir do preço médio na execução e outra a partir do preço de execução.
O SQL exato por trás de cada número
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_sEntre 900593 execuções classificadas, a série baseada no preço médio registra 3.068 pontos-base em 1 sec e 2.977 pontos-base em 5 min. Um ponto-base corresponde a um centésimo de 1% do preço. Assim, uma execução isolada gera pouco efeito, mas um milhão de ações movimenta dinheiro relevante.
A série baseada no preço de execução começa em -0.488 pontos-base. A distância entre as duas séries no horizonte mais curto é o half spread efetivo: a distância entre o print e o preço médio. Um taker paga esse valor na entrada, e um maker o recebe. Tudo depois do primeiro horizonte representa o movimento do mercado.
O tamanho da execução e o formato da curva
A adverse selection não se distribui igualmente entre as execuções. Dividir a mesma sessão pelo tamanho dos prints coloca pequenas execuções e blocos de mil ações ou mais nos mesmos eixos.
O SQL exato por trás de cada número
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_sNo horizonte de 5 min, prints com menos de mil ações registram, em média, 2.983 pontos-base, enquanto os 11588 prints de mil ações ou mais registram, em média, 2.495. Duas cotações que executem o mesmo volume total contra esses dois grupos não terminam o dia no mesmo nível.
Como as markouts se transformam nos números de spread dos relatórios de execução
A markout é o termo que falta na decomposição padrão do spread. O spread efetivo é o que um taker realmente pagou: duas vezes a distância com sinal entre o preço médio e o print. Divida esse valor em duas partes. Uma é o spread realizado, o que o maker conserva depois que o mercado se move. A outra é a adverse selection, que corresponde à markout baseada no preço médio multiplicada por dois. A identidade é exata: spread efetivo = spread realizado + adverse selection.
O SQL exato por trás de cada número
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_timeNa meia hora iniciada em 09:30, horário do leste dos Estados Unidos, o spread efetivo registra, em média, 10.651 pontos-base. Desse total, 8.313 corresponde ao componente de adverse selection no horizonte de sessenta segundos, e 2.338 é o que o maker retém. O painel cobre 13 intervalos de meia hora.
Esses componentes são os valores resumidos por venue nos relatórios de execução Rule 605 e 606, e formam a base matemática das alegações de price improvement associadas à regra de sub-penny e ao price improvement. Um rebate é um crédito fixo por ação. A adverse selection é um custo variável por ação nas execuções que uma cotação efetivamente recebe. Comparar um com o outro ao longo de uma curva medida, em vez de usar apenas uma tabela de taxas, é a verificação por trás de taxas e rebates maker-taker, em conjunto com a mecânica explicada em por que market makers perdem dinheiro.
Como esses números foram calculados
Todos os painéis usam cotações e prints de INTC da sessão regular de 10 de junho de 2026, das 09:30 às 16:00, horário do leste dos Estados Unidos. As cotações são consolidadas em um preço médio por segundo: o último registrado dentro daquele segundo. Um print é classificado como iniciado por compra quando ocorre acima do preço médio do segundo anterior e como iniciado por venda quando ocorre abaixo dele. Essa é a regra padrão baseada na cotação. Prints exatamente no preço médio são excluídos, em vez de classificados por estimativa; por isso, execuções no midpoint ficam fora da amostra. Usar o preço médio do segundo anterior como referência impede o uso de informação futura. Os horizontes são contados em segundos inteiros a partir do segundo do print, e uma execução entra em um horizonte somente quando existe uma cotação no segundo-alvo.
Perguntas frequentes
O que é uma markout em trading?
Uma markout é a variação, com sinal, do preço médio ao longo de um horizonte fixo após uma execução. Um resultado positivo significa que o mercado se moveu na direção da sua operação depois que ela foi executada. Um resultado negativo significa que se moveu na direção contrária, que é a definição de adverse selection.
Uma markout negativa sempre indica uma execução ruim?
Não. Uma markout negativa em um segundo, em uma ordem que cruza o spread, reflete principalmente o spread pago para executar imediatamente. O mais importante é saber se a curva continua caindo em horizontes mais longos ou se estabiliza.
Qual é a diferença entre markout e slippage?
Slippage compara uma execução com um preço de decisão ou de chegada. Por isso, avalia o percurso completo de uma ordem. A markout compara a execução com o preço médio em um horizonte posterior. Assim, avalia o que aconteceu depois. Uma mede a ordem principal; a outra mede a execução individual.
Qual horizonte uma markout deve usar?
Depende da finalidade da execução. Horizontes inferiores a um segundo avaliam execução sensível à latência, enquanto um minuto é o padrão mais comum para medir adverse selection em ativos líquidos. Informar o horizonte ao lado do número é o que permite comparar duas markouts.
Qual é a relação entre markout e spread efetivo?
O spread efetivo se divide em spread realizado mais um componente de adverse selection. Esse componente corresponde à markout baseada no preço médio multiplicada por dois. Quando o horizonte muda, a divisão entre os dois componentes também muda. Por isso, uma estatística de spread publicada não é completa sem o horizonte correspondente.
Todos os painéis vêm acompanhados do SQL que os produziu. Abra um deles, substitua o ticker ou a data, e a mesma curva de markout será reconstruída do zero no terminal Strasmore.