Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

Trade Markout: Mengukur Kualitas Eksekusi

Pelajari trade markout, konvensi tandanya, serta kurva markout nyata pada horizon dari satu detik hingga lima menit untuk mengukur adverse selection.

Trade markout adalah perubahan mid price selama horizon tetap setelah fill, diukur sejak saat fill tersebut tercatat sebagai print. Nilai positif berarti pasar bergerak menguntungkan Anda setelah transaksi. Nilai negatif berarti pasar bergerak berlawanan dengan posisi Anda. Kondisi ini disebut adverse selection oleh trading desk. Horizon yang dipilih, misalnya satu detik atau lima menit, menentukan pertanyaan yang dijawab oleh angka tersebut.

Apa itu trade markout?

Mulailah dari mid price: titik tengah antara best bid dan best offer, yaitu midpoint dari NBBO. Markout mengambil mid tersebut pada horizon tertentu setelah fill, menguranginya dengan reference price, lalu memberi tanda berdasarkan sisi transaksi.

**markout pada horizon h = side * (mid pada t+h - reference price)**, dengan side bernilai plus satu jika Anda membeli dan minus satu jika Anda menjual.

Konvensi tanda biasanya menjadi sumber kebingungan. Jika mid turun setelah transaksi beli, markout bernilai negatif: Anda membeli, harga turun, dan pihak yang menjual kepada Anda memperoleh hasil yang lebih baik dari transaksi tersebut. Itulah adverse selection yang dinyatakan sebagai angka. Jika mid turun setelah transaksi jual, markout bernilai positif karena tanda berubah sesuai sisi transaksi. Setiap fill memiliki dua sisi. Markout satu sisi adalah markout pihak lain dengan tanda yang berlawanan.

Tiga reference price

Reference price yang dikurangkan menentukan apa yang diukur oleh markout.

  • Fill price. Markout berubah menjadi nilai moneter: nilai posisi pada t+h dibandingkan dengan harga yang Anda bayarkan. Spread yang Anda bayar atau peroleh tercakup di dalamnya.
  • Mid pada saat fill. Metode ini mengeluarkan spread dan mengisolasi pergerakan pasar setelah transaksi. Ini merupakan cara paling bersih untuk membaca adverse selection.
  • Quote pada sisi transaksi. Mengukur terhadap touch yang Anda ambil atau touch yang Anda pasang menunjukkan bagaimana fill dibandingkan dengan harga yang benar-benar tersedia.

Analisis execution quality menggunakan metode kedua untuk mengukur adverse selection dan metode pertama untuk profit and loss. Keduanya ditampilkan pada panel pertama di bawah berdasarkan satu rangkaian fill.

Kurva markout dan makna bentuknya

Jalankan statistik yang sama pada berbagai horizon dan Anda akan memperoleh sebuah kurva. Bentuknya memberikan informasi yang lebih lengkap daripada satu angka.

  • Kurva yang turun tajam dalam detik pertama dan tetap rendah menunjukkan flow yang segera dieksploitasi: harga bergerak berlawanan dengan fill hampir seketika.
  • Kurva yang terus turun selama beberapa menit menunjukkan flow yang membawa informasi nyata tentang arah harga.
  • Kurva yang datar di sekitar nol menunjukkan flow yang tidak merugikan. Setelah lima menit, mid terlihat hampir sama seperti saat fill.
  • Kurva yang awalnya negatif lalu naik kembali mendekati nol merupakan bentuk yang dicari passive maker yang mengumpulkan rebate. Penurunan awal mencerminkan spread dan immediate impact. Pemulihan menunjukkan pasar kembali ke level sebelumnya.

Pemilihan horizon juga merupakan keputusan tentang hal yang ingin Anda ukur. Di bawah satu detik, markout terutama mencerminkan latency dan queue position. Jika diperpanjang menjadi satu menit, markout mencerminkan informasi jangka pendek dalam flow. Setelah lima menit, pergerakan pasar normal mulai menutupi pengaruh fill itu sendiri.

Kurva markout aktual, fill demi fill

Panel di bawah mencakup setiap print INTC selama regular session pada 10 Juni 2026. Setiap print diklasifikasikan sebagai buy initiated atau sell initiated terhadap quote terakhir pada detik sebelum print tersebut tercatat. Panel kemudian menghitung rata-rata signed markout pada 5 horizon. Dua seri menggunakan fill yang sama: satu diukur dari mid pada saat fill, dan satu lagi dari fill price.

QueryKurva markout INTC, 10 Juni 2026, diukur dari dua basis referensi
SQL tepat di balik setiap angka
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

Dari 900593 fill yang telah diklasifikasikan, seri dengan basis mid menunjukkan 3.068 basis point pada 1 sec dan 2.977 basis point pada 5 min. Satu basis point adalah seperseratus persen dari harga. Karena itu, satu fill mungkin hanya menghasilkan selisih pembulatan, sedangkan satu juta saham dapat menghasilkan nilai yang material.

Seri dengan basis fill dibuka pada -0.488 basis point. Jarak antara kedua seri pada horizon terpendek merupakan effective half spread: jarak antara print dan mid. Taker membayar jarak tersebut saat masuk, sedangkan maker memperolehnya. Setelah horizon pertama, pergerakan tersebut sepenuhnya mencerminkan pergerakan pasar.

Ukuran fill dan bentuk kurva

Adverse selection tidak tersebar merata di antara fill. Membagi sesi yang sama berdasarkan ukuran print menempatkan fill kecil dan block berukuran seribu saham atau lebih pada sumbu yang sama.

QueryKurva yang sama, dibagi berdasarkan ukuran transaksi: fill kecil dibandingkan dengan blok
SQL tepat di balik setiap angka
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

Pada horizon 5 min, print di bawah seribu saham rata-rata menghasilkan 2.983 basis point, sedangkan 11588 print berukuran seribu saham atau lebih rata-rata menghasilkan 2.495. Dua quote yang mengisi total volume sama untuk kedua kelompok tersebut tidak selalu berakhir pada posisi yang sama pada akhir hari.

Bagaimana markout menjadi angka spread dalam execution report

Markout adalah komponen yang hilang dalam dekomposisi spread standar. Effective spread adalah biaya aktual yang dibayar taker: dua kali signed distance antara mid dan print. Nilai tersebut dibagi menjadi dua. Komponen pertama adalah realized spread, yaitu bagian yang dipertahankan maker setelah pasar bergerak. Komponen kedua adalah adverse selection, yaitu mid basis markout dikalikan dua. Identitasnya bersifat eksak: effective spread = realized spread + adverse selection.

QueryEffective spread diuraikan menjadi realized spread dan adverse selection, berdasarkan interval setengah jam
SQL tepat di balik setiap angka
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

Pada setengah jam yang dimulai pada 09:30 Eastern, effective spread rata-rata sebesar 10.651 basis point. Dari angka tersebut, 8.313 merupakan komponen adverse selection pada horizon enam puluh detik, sedangkan 2.338 merupakan bagian yang dipertahankan maker. Panel ini mencakup 13 bucket setengah jam.

Komponen tersebut merupakan angka yang dirangkum venue demi venue dalam execution report Rule 605 dan 606. Angka-angka itu juga menjadi dasar aritmetika klaim price improvement yang terkait dengan sub penny rule dan price improvement. Rebate adalah kredit tetap per saham. Adverse selection adalah biaya variabel per saham atas fill yang benar-benar diterima oleh quote. Membandingkan keduanya berdasarkan kurva yang diukur, bukan berdasarkan rate card utama, merupakan pemeriksaan di balik maker taker fees dan rebates, sekaligus melengkapi mekanisme dalam mengapa market maker mengalami kerugian.

Cara angka-angka ini dihitung

Setiap panel menggunakan quote dan print INTC dari regular session pada 10 Juni 2026, pukul 09:30 hingga 16:00 Eastern. Quote diringkas menjadi satu mid per detik, yaitu quote terakhir yang tercatat di dalam detik tersebut. Print diklasifikasikan sebagai buy initiated jika tercatat di atas mid pada detik sebelumnya dan sebagai sell initiated jika tercatat di bawahnya. Ini merupakan quote rule standar. Print yang tepat berada pada mid tersebut dikeluarkan, bukan ditebak, sehingga eksekusi pada midpoint berada di luar sampel. Penggunaan mid pada detik sebelumnya sebagai reference mencegah data masa depan ikut digunakan. Horizon dihitung dalam satuan detik penuh sejak detik saat print tercatat. Fill hanya masuk ke suatu horizon jika tersedia quote pada detik target.

FAQ

Apa itu markout dalam trading?

Markout adalah perubahan signed pada mid price selama horizon tetap setelah fill. Nilai positif berarti pasar bergerak searah dengan transaksi Anda setelah fill. Nilai negatif berarti pasar bergerak berlawanan. Inilah definisi adverse selection.

Apakah markout negatif selalu berarti fill yang buruk?

Tidak. Markout negatif pada satu detik untuk marketable order sebagian besar mencerminkan spread yang dibayar order tersebut sebagai biaya untuk segera mendapatkan eksekusi. Hal yang lebih penting adalah apakah kurva terus turun pada horizon yang lebih panjang atau menjadi datar.

Apa perbedaan markout dan slippage?

Slippage membandingkan fill dengan decision price atau arrival price. Karena itu, slippage menilai seluruh jalur order. Markout membandingkan fill dengan mid pada suatu horizon setelah fill. Jadi, markout menilai apa yang terjadi setelah transaksi. Slippage menilai parent order, sedangkan markout menilai fill individual.

Horizon apa yang sebaiknya digunakan untuk markout?

Horizon bergantung pada tujuan fill. Horizon di bawah satu detik menilai eksekusi yang sensitif terhadap latency. Sementara itu, satu menit merupakan default umum untuk mengukur adverse selection pada saham yang likuid. Mencantumkan horizon di samping angka membuat dua markout dapat dibandingkan.

Bagaimana hubungan markout dengan effective spread?

Effective spread terbagi menjadi realized spread dan komponen adverse selection. Komponen tersebut adalah mid basis markout dikalikan dua. Jika horizon diubah, pembagian antara kedua komponen juga berubah. Karena itu, statistik spread yang dipublikasikan tidak lengkap tanpa mencantumkan horizonnya.


Setiap panel di sini disertai SQL yang menghasilkan data tersebut. Buka salah satunya, ganti ticker atau tanggalnya, dan kurva markout yang sama akan dibangun ulang dari awal di terminal Strasmore.