Trade markout คืออะไร อธิบายการวัดคุณภาพการเทรด
ทำความเข้าใจ Trade markout และการคำนวณทิศทางราคาหลังการจับคู่คำสั่ง พร้อมวิเคราะห์เส้นกราฟ markout ในช่วงเวลาตั้งแต่หนึ่งวินาทีจนถึงห้านาที เพื่อประเมินประสิทธิภาพการซื้อขาย
Trade markout คือการเปลี่ยนแปลงของราคา Mid price ในช่วงเวลาที่กำหนดหลังจากได้รับการจับคู่คำสั่ง (fill) โดยวัดจากวินาทีที่การซื้อขายนั้นเกิดขึ้น หากค่าเป็นบวกหมายความว่าตลาดเคลื่อนไหวไปในทิศทางที่เป็นประโยชน์ต่อคุณหลังจากที่คุณเทรด หากค่าเป็นลบหมายความว่าตลาดเคลื่อนไหวสวนทางกับคุณ ซึ่งเป็นสิ่งที่โต๊ะเทรด (trading desk) เรียกว่า adverse selection ระยะเวลาที่คุณเลือก ไม่ว่าจะเป็นหนึ่งวินาทีหรือห้านาที จะเป็นตัวกำหนดว่าตัวเลขนั้นกำลังตอบคำถามเรื่องอะไร
Trade markout คืออะไร?
เริ่มต้นจาก Mid price ซึ่งเป็นจุดกึ่งกลางระหว่างราคาเสนอซื้อที่ดีที่สุด (best bid) และราคาเสนอขายที่ดีที่สุด (best offer) หรือจุดกึ่งกลางของ NBBO การทำ markout คือการนำราคา Mid ณ ช่วงเวลาที่เลือกหลังจาก fill ของคุณ มาลบด้วยราคาอ้างอิง แล้วใส่เครื่องหมายตามฝั่งที่คุณเทรด
**markout ณ ช่วงเวลา h = ฝั่ง * (mid ณ เวลา t+h - ราคาอ้างอิง)** โดยที่ฝั่งจะมีค่าเป็นบวกหนึ่งหากคุณซื้อ และเป็นลบหนึ่งหากคุณขาย
หลักการกำหนดเครื่องหมายมักเป็นจุดที่ทำให้เกิดความสับสน การซื้อที่ตามมาด้วยราคา Mid ที่ลดลงจะมีค่า markout เป็นลบ: คุณซื้อไปแล้วราคาลดลง ผู้ที่ขายให้คุณจึงเป็นฝ่ายได้เปรียบในการเทรดนั้น นี่คือ adverse selection ที่ถูกเขียนออกมาเป็นตัวเลข ส่วนการขายที่ตามมาด้วยราคา Mid ที่ลดลงจะมีค่า markout เป็นบวก เนื่องจากเครื่องหมายจะกลับด้านตามฝั่งที่เทรด ทุกการจับคู่คำสั่ง (fill) มีสองฝั่ง และ markout ของฝั่งหนึ่งก็คือค่าของอีกฝั่งที่กลับเครื่องหมายนั่นเอง
ราคาอ้างอิงทั้งสามประเภท
ราคาอ้างอิงที่คุณนำมาลบจะเป็นตัวกำหนดว่า markout นั้นกำลังวัดค่าอะไร
- ราคาที่จับคู่ได้ (fill price): markout จะกลายเป็นมูลค่าเงิน: สถานะของคุณมีมูลค่าเท่าใด ณ เวลา t+h เมื่อเทียบกับราคาที่คุณจ่ายไป ซึ่งรวมถึง spread ที่คุณจ่ายหรือได้รับไว้ด้วย
- ราคา Mid ณ วินาทีที่จับคู่ได้: วิธีนี้จะตัดส่วนของ spread ออกไปและแยกให้เห็นว่าตลาดเคลื่อนไหวอย่างไรหลังจากที่คุณเทรด ซึ่งเป็นการวัด adverse selection ที่ชัดเจนที่สุด
- ราคาเสนอซื้อขาย (quote) ในฝั่งที่คุณเทรด: การวัดเทียบกับราคา touch ที่คุณได้รับหรือราคาที่คุณวางไว้ จะช่วยตอบคำถามว่าการจับคู่คำสั่งนั้นเปรียบเทียบกับราคาที่มีอยู่จริงในขณะนั้นอย่างไร
งานด้านคุณภาพการส่งคำสั่งซื้อขาย (execution quality) มักอิงตามวิธีที่สองสำหรับ adverse selection และวิธีแรกสำหรับกำไรขาดทุน ทั้งสองวิธีปรากฏอยู่ในแผงข้อมูลแรกด้านล่าง โดยอ้างอิงจากชุดการจับคู่คำสั่งชุดหนึ่ง
เส้นกราฟ markout และความหมายของรูปแบบ
เมื่อคำนวณสถิติเดียวกันในหลายช่วงเวลา คุณจะได้เส้นกราฟออกมา ซึ่งรูปแบบของมันให้ข้อมูลมากกว่าตัวเลขเพียงตัวเดียว
- เส้นกราฟที่ดิ่งลงอย่างรวดเร็วภายในวินาทีแรกและยังคงอยู่ในระดับต่ำ อธิบายถึง flow ที่ถูกดักกิน (picked off): ราคาเคลื่อนไหวสวนทางกับการจับคู่คำสั่งแทบจะทันที
- เส้นกราฟที่ยังคงลดลงต่อเนื่องเป็นเวลาหลายนาที อธิบายถึง flow ที่มีข้อมูลจริงเกี่ยวกับทิศทางที่ราคาจะไป
- เส้นกราฟที่ราบเรียบใกล้ศูนย์ อธิบายถึง flow ที่ไม่มีนัยสำคัญ ห้านาทีผ่านไปราคา Mid ก็ยังดูเหมือนตอนที่จับคู่คำสั่ง
- เส้นกราฟที่เริ่มต้นด้วยค่าลบแล้วค่อย ๆ ไต่กลับขึ้นมาใกล้ศูนย์ คือรูปแบบที่ market maker แบบ passive ซึ่งเก็บค่า rebate ต้องการเห็น การดิ่งลงในช่วงแรกคือ spread บวกกับผลกระทบต่อราคาในทันที (immediate impact) และการฟื้นตัวคือการที่ตลาดปรับตัวกลับเข้าสู่ภาวะปกติ
การเลือกช่วงเวลา (horizon) คือการตัดสินใจว่าคุณกำลังวัดค่าอะไร หากต่ำกว่าหนึ่งวินาที markout จะอ่านค่าเรื่อง latency และ queue position เป็นหลัก หากขยายไปถึงหนึ่งนาที มันจะอ่านค่าข้อมูลระยะสั้นใน flow นั้น และหากเกินห้านาทีไปแล้ว การแกว่งตัวปกติของตลาดจะเริ่มกลบผลของการจับคู่คำสั่งนั้นไป
เส้นกราฟ markout จริง รายการต่อรายการ
แผงข้อมูลด้านล่างนำทุกรายการซื้อขาย (print) ของ INTC จากการซื้อขายปกติในวันที่ 10 มิถุนายน 2026 มาจำแนกแต่ละรายการว่าเป็นการซื้อหรือการขาย โดยเทียบกับ quote ล่าสุดของวินาทีก่อนที่จะเกิดการซื้อขายนั้น และหาค่าเฉลี่ยของ markout ที่มีเครื่องหมาย ณ ช่วงเวลา 5 โดยมีสองชุดข้อมูลที่ใช้การจับคู่คำสั่งชุดเดียวกัน: ชุดหนึ่งวัดจากราคา Mid ณ เวลาที่จับคู่ได้ และอีกชุดวัดจากราคาที่จับคู่ได้จริง
SQL เบื้องหลังตัวเลขแต่ละตัว
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จากจำนวนการจับคู่คำสั่ง 900593 รายการ ชุดข้อมูล mid basis อ่านค่าได้ 3.068 basis points ณ เวลา 1 sec และ 2.977 basis points ณ เวลา 5 min โดยหนึ่ง basis point คือหนึ่งในร้อยของหนึ่งเปอร์เซ็นต์ของราคา ดังนั้นการจับคู่คำสั่งหนึ่งรายการอาจเป็นเพียงความคลาดเคลื่อนจากการปัดเศษ แต่การซื้อขายหนึ่งล้านหุ้นคือเงินจำนวนจริง
ชุดข้อมูล fill basis เริ่มต้นที่ -0.488 basis points ระยะห่างระหว่างสองชุดข้อมูล ณ ช่วงเวลาที่สั้นที่สุดคือ effective half spread: ระยะห่างจากราคาที่ซื้อขายจริงไปถึงราคา Mid ผู้ที่เข้าซื้อ (taker) จะเป็นผู้จ่ายส่วนนี้และผู้สร้างสภาพคล่อง (maker) จะเป็นผู้ได้รับ ทุกสิ่งที่เกิดขึ้นหลังจากช่วงเวลาแรกคือการเคลื่อนไหวของตลาด
ขนาดของการจับคู่คำสั่งและรูปร่างของเส้นกราฟ
Adverse selection ไม่ได้เกิดขึ้นเท่ากันในทุกการจับคู่คำสั่ง การแยกข้อมูลในวันเดียวกันตามขนาดของรายการซื้อขาย ทำให้เห็นรายการขนาดเล็กและรายการขนาดใหญ่ (block) ตั้งแต่หนึ่งพันหุ้นขึ้นไปบนแกนเดียวกัน
SQL เบื้องหลังตัวเลขแต่ละตัว
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ณ ช่วงเวลา 5 min รายการซื้อขายที่ต่ำกว่าหนึ่งพันหุ้นมีค่าเฉลี่ยอยู่ที่ 2.983 basis points ในขณะที่รายการ 11588 ที่มีขนาดหนึ่งพันหุ้นขึ้นไปมีค่าเฉลี่ยอยู่ที่ 2.495 สอง quote ที่จับคู่กับปริมาณรวมเท่ากันในสองกลุ่มนี้ จะไม่จบวันด้วยผลลัพธ์ที่เหมือนกัน
วิธีที่ markout กลายเป็นตัวเลข spread ในรายงานการส่งคำสั่งซื้อขาย
Markout คือตัวแปรที่ขาดหายไปในการแยกองค์ประกอบของ spread มาตรฐาน Effective spread คือสิ่งที่ taker จ่ายจริง: สองเท่าของระยะห่างที่มีเครื่องหมายจากราคา Mid ไปยังราคาที่ซื้อขายจริง เมื่อแบ่งส่วนนี้ออกเป็นสองส่วน ส่วนหนึ่งคือ realized spread ซึ่งเป็นสิ่งที่ maker เก็บไว้หลังจากตลาดเคลื่อนไหวไปแล้ว อีกส่วนหนึ่งคือ adverse selection ซึ่งก็คือ mid basis markout คูณด้วยสอง ความสัมพันธ์นี้เป็นค่าที่แม่นยำ: effective spread = realized spread + adverse selection
SQL เบื้องหลังตัวเลขแต่ละตัว
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ในช่วงครึ่งชั่วโมงที่เริ่มตั้งแต่ 09:30 ตามเวลา Eastern, effective spread มีค่าเฉลี่ยอยู่ที่ 10.651 basis points โดย 8.313 เป็นส่วนของ adverse selection ณ ช่วงเวลาหกสิบวินาที และ 2.338 คือส่วนที่ maker เก็บไว้ แผงข้อมูลนี้ครอบคลุมช่วงเวลา 13 ครึ่งชั่วโมง
องค์ประกอบเหล่านี้คือปริมาณที่สรุปไว้ในแต่ละสถานที่ซื้อขายใน รายงานการซื้อขายตามกฎ 605 และ 606 และเป็นคณิตศาสตร์เบื้องหลังการอ้างสิทธิ์เรื่องการปรับปรุงราคา (price improvement) ที่อ้างอิงตาม กฎ sub penny และการปรับปรุงราคา Rebate คือเครดิตคงที่ต่อหุ้น ส่วน adverse selection คือต้นทุนผันแปรต่อหุ้นในการจับคู่คำสั่งที่ quote ได้รับจริง การชั่งน้ำหนักระหว่างสองสิ่งนี้ผ่านเส้นกราฟที่วัดค่าได้ แทนที่จะดูเพียงอัตราค่าธรรมเนียมตามประกาศ คือการตรวจสอบเบื้องหลัง ค่าธรรมเนียมและ rebate ของ maker taker และเป็นสิ่งที่ควบคู่ไปกับกลไกในเรื่อง ทำไม market maker ถึงขาดทุน
วิธีการคำนวณตัวเลขเหล่านี้
ทุกแผงข้อมูลอ่านค่า quote และ print ของ INTC จากการซื้อขายปกติในวันที่ 10 มิถุนายน 2026 ตั้งแต่เวลา 09:30 ถึง 16:00 น. ตามเวลา Eastern โดย quote จะถูกยุบรวมเหลือหนึ่งค่า Mid ต่อวินาที คือค่าสุดท้ายที่บันทึกได้ภายในวินาทีนั้น รายการซื้อขายจะถูกจำแนกว่าเป็นการซื้อหากราคาที่ซื้อขายสูงกว่า Mid ของวินาทีก่อนหน้า และเป็นการขายหากราคาต่ำกว่า ซึ่งเป็นกฎมาตรฐานของ quote รายการที่ซื้อขายตรงกับ Mid พอดีจะถูกตัดออกแทนที่จะคาดเดา ดังนั้นการจับคู่คำสั่งที่ราคา Mid จึงไม่อยู่ในกลุ่มตัวอย่าง การใช้ Mid ของวินาทีก่อนหน้าเป็นราคาอ้างอิงช่วยป้องกันไม่ให้ราคาอ้างอิงมองเห็นข้อมูลล่วงหน้า ช่วงเวลาคือจำนวนวินาทีเต็มที่นับจากวินาทีที่เกิดการซื้อขาย และการจับคู่คำสั่งจะเข้าสู่ช่วงเวลานั้นก็ต่อเมื่อมี quote ปรากฏอยู่ในวินาทีเป้าหมายนั้น
คำถามที่พบบ่อย
Markout ในการเทรดคืออะไร?
Markout คือการเปลี่ยนแปลงที่มีเครื่องหมายของราคา Mid ในช่วงเวลาที่กำหนดหลังจากได้รับการจับคู่คำสั่ง ค่าที่เป็นบวกหมายความว่าตลาดเคลื่อนไหวไปในทิศทางเดียวกับการเทรดของคุณหลังจากที่คุณได้รับ fill ค่าที่เป็นลบหมายความว่าตลาดเคลื่อนไหวสวนทาง ซึ่งเป็นนิยามของ adverse selection
Markout ที่เป็นลบหมายถึงการได้ fill ที่แย่เสมอไปหรือไม่?
ไม่เสมอไป Markout ที่เป็นลบ ณ เวลาหนึ่งวินาทีสำหรับคำสั่งซื้อขายที่จับคู่ได้ทันที (marketable order) ส่วนใหญ่คือ spread ที่คำสั่งนั้นจ่ายไป ซึ่งเป็นราคาของการได้เทรดทันที สิ่งที่สำคัญกว่าคือเส้นกราฟยังคงลดลงต่อไปในระยะเวลาที่นานขึ้นหรือเริ่มราบเรียบ
Markout กับ Slippage ต่างกันอย่างไร?
Slippage เปรียบเทียบการจับคู่คำสั่งกับราคาตัดสินใจหรือราคาที่คำสั่งมาถึง ดังนั้นจึงเป็นการประเมินเส้นทางทั้งหมดของคำสั่ง ส่วน markout เปรียบเทียบการจับคู่คำสั่งกับราคา Mid ณ ช่วงเวลาหนึ่งหลังจากนั้น จึงเป็นการประเมินสิ่งที่เกิดขึ้นหลังจากนั้น หนึ่งอย่างให้คะแนนคำสั่งหลัก (parent order) อีกอย่างให้คะแนนการจับคู่คำสั่งแต่ละรายการ
ควรใช้ช่วงเวลา (horizon) ใดในการทำ markout?
ขึ้นอยู่กับว่าการจับคู่คำสั่งนั้นมีไว้เพื่ออะไร ช่วงเวลาที่ต่ำกว่าหนึ่งวินาทีจะประเมินการส่งคำสั่งที่ไวต่อ latency ในขณะที่หนึ่งนาทีเป็นค่าเริ่มต้นทั่วไปสำหรับ adverse selection ในหุ้นที่มีสภาพคล่อง การระบุช่วงเวลาไว้ข้างตัวเลขคือสิ่งที่ทำให้ markout สองค่าสามารถนำมาเปรียบเทียบกันได้
Markout เกี่ยวข้องกับ effective spread อย่างไร?
Effective spread แบ่งออกเป็น realized spread บวกกับองค์ประกอบของ adverse selection และองค์ประกอบนั้นก็คือ mid basis markout คูณด้วยสอง หากเปลี่ยนช่วงเวลา การแบ่งส่วนระหว่างสองค่านี้ก็จะเปลี่ยนตามไปด้วย นี่คือเหตุผลว่าทำไมสถิติ spread ที่ประกาศออกมาจึงไม่สมบูรณ์หากไม่มีการระบุช่วงเวลาที่ใช้กำกับไว้
ทุกแผงข้อมูลที่นี่มาพร้อมกับ SQL ที่ใช้สร้างมันขึ้นมา คุณสามารถเปิดแผงข้อมูล เปลี่ยน ticker หรือวันที่ แล้วเส้นกราฟ markout เดิมจะถูกสร้างขึ้นใหม่ตั้งแต่ต้นบนเทอร์มินัล Strasmore