Strasmore Research
Deep Dives · Matt ConnorBy Matt Connor ·

מהו trade markout? הסבר על איכות ביצוע ומדידת עסקאות

מדריך מקיף על חישוב trade markout ומוסכמת הסימנים במסחר. גלו כיצד מודדים adverse selection באמצעות עקומות markout בטווחי זמן שבין שנייה אחת לחמש דקות.

מהו trade markout?

נתחיל במחיר ה-mid: נקודת האמצע בין ה-best bid ל-best offer, כלומר נקודת האמצע של ה-NBBO. חישוב markout לוקח את ה-mid בנקודת זמן נבחרת לאחר הביצוע (fill), מחסיר ממנו מחיר ייחוס, ומכפיל בסימן התואם לצד שבו נסחרת:

**markout בטווח זמן h = צד * (mid ב-t+h - מחיר ייחוס)**, כאשר הצד הוא פלוס אחד אם קנית ומינוס אחד אם מכרת.

הבלבול נובע בדרך כלל ממוסכמת הסימנים. קנייה שלאחריה ה-mid יורד מניבה markout שלילי: קנית, המחיר ירד, ומי שמכר לך יצא נשכר מהעסקה. זוהי adverse selection הכתובה כמספר. מכירה שלאחריה ה-mid יורד מניבה markout חיובי, שכן הסימן מתהפך בהתאם לצד. לכל ביצוע יש שני צדדים, וה-markout של צד אחד הוא ה-markout של הצד השני בסימן הפוך.

שלושת מחירי הייחוס

מחיר הייחוס שתבחר להחסיר קובע מה ה-markout מודד.

  • מחיר הביצוע (fill price). ה-markout הופך לערך כספי: שווי הפוזיציה ב-t+h לעומת מה ששילמת. ה-spread ששילמת או הרווחת כלול בתוכו.
  • ה-mid ברגע הביצוע. זה מנטרל את ה-spread ומבודד את תנועת השוק לאחר המסחר, מה שמהווה את המדד המדויק ביותר ל-adverse selection.
  • הציטוט (quote) בצד שבו נסחרת. מדידה מול ה-touch שלקחת או ה-touch שהצבת עונה על השאלה כיצד הביצוע משתווה למחיר שהיה זמין בפועל.

עבודת איכות ביצוע (execution quality) נשענת על השני עבור adverse selection ועל הראשון עבור רווח והפסד. שניהם מופיעים בלוח הראשון להלן, עבור קבוצת ביצועים אחת.

עקומת ה-markout ומשמעות צורתה

הרצת אותו נתון בטווחי זמן רבים יוצרת עקומה. צורתה נושאת מידע רב יותר מכל מספר בודד.

  • עקומה שיורדת בחדות בשנייה הראשונה ונשארת נמוכה מתארת זרימת פקודות (flow) ש"נאכלת": המחיר נע נגד הביצוע כמעט מיד.
  • עקומה שממשיכה לרדת במשך דקות מתארת זרימה שנשאה מידע אמיתי על כיוון המחיר.
  • עקומה שטוחה ליד האפס מתארת זרימה שפירה. חמש דקות לאחר מכן, ה-mid נראה כפי שנראה ברגע הביצוע.
  • עקומה שמתחילה שלילית ומטפסת חזרה לכיוון האפס היא הצורה שמחפש עושה שוק פסיבי שאוסף החזרים (rebates). הירידה המוקדמת היא ה-spread בתוספת אימפקט מיידי, וההתאוששות היא חזרת השוק למצבו הקודם.

בחירת טווח הזמן היא כשלעצמה החלטה על מה שאתה מודד. מתחת לשנייה, ה-markout קורא בעיקר לטנסי (latency) ו-מיקום בתור. מתיחה לדקה קוראת למידע קצר הטווח בזרימה. מעבר לחמש דקות, תנודות שוק רגילות מתחילות להאפיל על הביצוע עצמו.

עקומת markout אמיתית, ביצוע אחר ביצוע

הלוח להלן לוקח כל print של INTC מיום המסחר הרגיל ב-10 ביוני 2026, מסווג כל אחד כיוזמת קנייה או יוזמת מכירה מול הציטוט האחרון של השנייה שלפני ה-print, ומחשב ממוצע של ה-markout החתום בטווחי זמן של 5. שתי סדרות רצות על אותם ביצועים: אחת נמדדת מה-mid ברגע הביצוע, והשנייה ממחיר הביצוע.

שאילתהעקומת markout עבור INTC, 10 ביוני 2026, נמדדת משני בסיסי ייחוס
ה-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
Run this yourself

בקרב 900593 ביצועים מסווגים, סדרת ה-mid basis קוראת 3.068 נקודות בסיס ב-1 sec ו-2.977 נקודות בסיס ב-5 min. נקודת בסיס היא מאית האחוז מהמחיר, כך שביצוע אחד מזיז טעות עיגול ומיליון מניות מזיזות כסף אמיתי.

סדרת ה-fill basis נפתחת ב--0.488 נקודות בסיס. המרחק בין שתי הסדרות בטווח הזמן הקצר ביותר הוא ה-effective half spread: המרחק שבו ה-print נחת מה-mid. לוקח (taker) משלם זאת בכניסה ועושה שוק (maker) מרוויח זאת. כל מה שמעבר לטווח הזמן הראשון הוא תנועת השוק.

גודל הביצוע וצורת העקומה

ה-adverse selection אינה מתפלגת באופן שווה בין הביצועים. פיצול אותו יום מסחר לפי גודל ה-print מציב ביצועים קטנים ובלוקים של אלף מניות ומעלה על אותם צירים.

שאילתהאותה עקומה, בחלוקה לפי גודל פקודה: ביצועים קטנים מול בלוקים
ה-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
Run this yourself

בטווח הזמן של 5 min, prints של פחות מאלף מניות מציגים ממוצע של 2.983 נקודות בסיס, בעוד ה-11588 prints של אלף מניות ומעלה מציגים ממוצע של 2.495. שני ציטוטים הממלאים את אותו נפח כולל מול שתי הקבוצות הללו לא יסיימו את היום באותו מקום.

כיצד הופכים markouts למספרי ה-spread בדוחות ביצוע

ה-markout הוא המשתנה החסר בפירוק ה-spread הסטנדרטי. ה-effective spread הוא מה שלוקח (taker) שילם בפועל: פעמיים המרחק החתום מה-mid ל-print. חלק זאת לשניים. חלק אחד הוא ה-realized spread, מה שעושה שוק שומר לעצמו לאחר שהשוק זז. החלק השני הוא ה-adverse selection, שהוא ה-mid basis markout כפול שתיים. הזהות מדויקת: effective spread = realized spread + adverse selection.

שאילתהפירוק ה-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
Run this yourself

בחצי השעה שמתחילה ב-09:30 שעון מזרח, ה-effective spread עומד בממוצע על 10.651 נקודות בסיס, מתוכן 8.313 הוא רכיב ה-adverse selection בטווח זמן של שישים שניות ו-2.338 הוא מה שעושה השוק שומר. הלוח מכסה 13 דליים של חצי שעה.

רכיבים אלו הם הכמויות המסוכמות זירה אחר זירה ב-דוחות ביצוע לפי Rule 605 ו-606, והם החשבון שמאחורי טענות לשיפור מחיר (price improvement) הנשענות על חוק תת-הסנט ושיפור מחיר. החזר (rebate) הוא זיכוי קבוע למניה. adverse selection הוא עלות משתנה למניה על הביצועים שהציטוט מקבל בפועל. שקלול האחד מול השני על פני עקומה מדודה, ולא על פני מחירון כותרות, הוא הבדיקה שמאחורי עמלות והחזרים של maker-taker, והוא ניצב לצד המכניקה ב-מדוע עושי שוק מפסידים כסף.

כיצד חושבו מספרים אלו

כל לוח קורא ציטוטים ו-prints של INTC מיום המסחר הרגיל ב-10 ביוני 2026, בין 09:30 ל-16:00 שעון מזרח. הציטוטים מתכנסים ל-mid אחד לשנייה, האחרון שנדפס בתוך אותה שנייה. print מסווג כיוזמת קנייה כאשר נחת מעל ה-mid של השנייה הקודמת וכיוזמת מכירה כאשר נחת מתחתיו, לפי כלל הציטוט הסטנדרטי. prints שנחתו בדיוק על ה-mid מושמטים במקום לנחש את כיוונם, כך שביצועים ב-mid נשארים מחוץ למדגם. השימוש ב-mid של השנייה הקודמת כייחוס מונע מהייחוס "להציץ" קדימה. טווחי הזמן הם שניות שלמות הנספרות משניית ה-print, וביצוע נכנס לטווח זמן רק כאשר קיים ציטוט בשניית היעד.

שאלות נפוצות

מהו markout במסחר?

markout הוא השינוי החתום במחיר ה-mid לאורך טווח זמן קבוע לאחר ביצוע. חיובי אומר שהשוק נע בכיוון העסקה שלך לאחר שקיבלת ביצוע. שלילי אומר שהוא נע לכיוון ההפוך, וזו ההגדרה של adverse selection.

האם markout שלילי הוא תמיד ביצוע גרוע?

לא. markout שלילי בשנייה אחת על פקודה סחירה הוא ברובו ה-spread ששילמה אותה פקודה, וזהו המחיר של ביצוע מיידי. מה שחשוב יותר הוא האם העקומה ממשיכה לרדת בטווחי זמן ארוכים יותר או מתייצבת.

מה ההבדל בין markout ל-slippage?

slippage משווה ביצוע מול מחיר החלטה או מחיר הגעה, ולכן הוא מדרג את כל מסלול הפקודה. markout משווה ביצוע מול ה-mid בטווח זמן לאחר הביצוע, ולכן הוא מדרג את מה שקרה לאחר מכן. האחד מדרג את פקודת האם, השני מדרג את הביצוע הבודד.

באיזה טווח זמן צריך להשתמש ב-markout?

זה תלוי במטרה של הביצוע. טווחי זמן של תת-שנייה מדרגים ביצוע רגיש לטנסי, בעוד דקה אחת היא ברירת המחדל המקובלת ל-adverse selection במניות נזילות. פרסום טווח הזמן לצד המספר הוא מה שהופך שני markouts לניתנים להשוואה.

כיצד markout קשור ל-effective spread?

ה-effective spread מתפרק ל-realized spread בתוספת רכיב adverse selection, ורכיב זה הוא ה-mid basis markout כפול שתיים. שנה את טווח הזמן והפיצול בין השניים ישתנה בהתאם, וזו הסיבה שנתון spread מפורסם אינו שלם ללא טווח הזמן הצמוד אליו.


כל לוח כאן מגיע עם ה-SQL שיצר אותו. פתח אחד, החלף את ה-ticker או את התאריך, ועקומת ה-markout תבנה מחדש מאפס במסוף Strasmore.