رفتن به محتوای اصلی
سرفصل مسیر Quant Developer

مسیر Quant Developer · بخش ۲: اقتصاد و ریسک Market Making · درس ۸

Adverse Selection و Markout

چرا سفارش‌های بازارساز اغلب درست پیش از حرکت نامطلوب قیمت پر می‌شوند، و چطور با Markout کیفیت هر پر شدن را در افق‌های زمانی مختلف اندازه بگیریم.

سطح: متوسط۱۳ دقیقه مطالعه

۱. وقتی پر شدن خبر بدی است

در مثال درس هفتم، بازارساز سه بار Spread را درست گرفت و همه‌اش را در موجودی پس داد: دو بار خرید و هر دو بار قیمت بعد از خرید پایین رفت. سؤال این درس این است: این بدشانسی بود یا الگو؟

برای جواب باید ببینیم چه کسی با بازارساز معامله می‌کند. طرف مقابل سفارش‌های Maker تو، Taker‌ها هستند و دو دسته‌اند:

  • جریان ناآگاه (Uninformed Flow): کسی که به دلیلی غیر از پیش‌بینی قیمت معامله می‌کند؛ مثلاً می‌خواهد پرتفوی‌اش را متوازن کند، پول نقد لازم دارد یا ریسک جای دیگری را پوشش می‌دهد. جهت معامله‌اش نسبت به حرکت بعدی قیمت تقریباً تصادفی است.
  • جریان آگاه (Informed Flow): کسی که درباره قیمت آینده چیزی بیشتر از تو می‌داند یا سریع‌تر می‌فهمد؛ مثلاً حرکت قیمت در بازار دیگری را زودتر دیده، یک خبر را سریع‌تر پردازش کرده یا مدل بهتری دارد.

معامله‌گر آگاه فقط وقتی با تو معامله می‌کند که قیمت تو اشتباه باشد. اگر بداند قیمت تا چند ثانیه دیگر بالا می‌رود، از Ask تو می‌خرد؛ یعنی تو درست قبل از بالا رفتن قیمت فروخته‌ای. به این پدیده Adverse Selection (انتخاب نامطلوب) می‌گویند: سفارش‌های تو دقیقاً در بدترین لحظه‌ها انتخاب می‌شوند.

مدل کلاسیک Glosten و Milgrom (۱۹۸۵) نشان داد که حتی بدون کارمزد و ریسک موجودی، Spread باید وجود داشته باشد؛ چون درآمد بازارساز از معامله‌گرهای ناآگاه باید زیانش به معامله‌گرهای آگاه را جبران کند.

یک حساب ساده

فرض کن نیم‌اسپرد تو h = 10 دلار است. معامله با فرد ناآگاه به‌طور متوسط همین ۱۰ دلار (به ازای هر BTC) سود دارد. معامله با فرد آگاه هم ۱۰ دلار Spread می‌دهد، ولی بعدش قیمت M = 30 دلار علیه تو حرکت می‌کند. اگر سهم جریان آگاه π باشد:

Expected Edge = h − π × M

با π = 20٪، سود انتظاری هر پر شدن 10 − 0.2 × 30 = 4 دلار است؛ یعنی ۶۰٪ نیم‌اسپرد از دست رفت. اگر سهم جریان آگاه به یک‌سوم برسد، سود انتظاری صفر می‌شود؛ و این هنوز پیش از کارمزد است. نکته کلیدی: همان h و همان نرخ پر شدن، بسته به اینکه چه کسی سفارش را پر کرده، می‌تواند سودده یا زیان‌ده باشد.

۲. چرا پر شدن‌ها قبل از حرکت نامطلوب جمع می‌شوند

حتی بدون معامله‌گر «باهوش»، سازوکار خود دفتر سفارش پر شدن‌ها را به سمت لحظه‌های بد می‌برد:

  • صف (یادآوری درس ۳): سفارش خرید تو در ته صف 99,990 فقط وقتی پر شد که ۰.۵۵ BTC فروش Market به آن سطح رسید. جریان فروش آن‌قدر سنگین که کل صف جلوی تو را بخورد، خودش نشانه فشار فروش است و قیمت بعد از آن به احتمال بیشتر پایین می‌رود. به بیان دیگر، پر شدن سفارش ته صف با شرط حرکت نامطلوب اتفاق می‌افتد.
  • قیمت کهنه: وقتی Fair Value جهش می‌کند (درس ۵) و سیستم تو چند میلی‌ثانیه دیرتر سفارش‌ها را به‌روز می‌کند، معامله‌گرهای سریع‌تر همان قیمت کهنه را برمی‌دارند. به این Picking Off می‌گویند.
  • عدم تقارن ذاتی: اگر قیمت به سمت سفارش تو بیاید، سفارشت پر می‌شود و حالا موجودی‌ای داری که در جهت اشتباه است. اگر قیمت از سفارشت دور شود، سفارشت پر نمی‌شود و از آن حرکت هیچ سودی نمی‌بری.

۳. Markout: قیمت بعد از پر شدن چه شد؟

Markout می‌سنجد هر پر شدن، اگر آن را با قیمت چند لحظه بعد ارزش‌گذاری کنی، چقدر سود یا زیان داشت. برای پر شدنی در زمان t با قیمت Price و در افق h:

Markout(h) = s × (Mid(t + h) − Price)

که s مثل درس ۷ برای خرید برابر ۱ و برای فروش برابر منفی ۱ است. نتیجه به ازای یک واحد دارایی (اینجا دلار به ازای هر BTC) است؛ برای عدد دلاری در حجم ضرب می‌شود و برای مقایسه بین دارایی‌ها معمولاً به basis point تبدیل می‌شود (۱۰ دلار روی قیمت 100,000 برابر ۱ basis point است).

مثال

بازارساز در 99,990 می‌خرد، وقتی Mid برابر 100,000 است. قیمت میانی در لحظه‌های بعد:

افقMidMarkout به ازای هر BTCبرای 0.1 BTC
صفر (لحظه پر شدن)100,000۱۰ دلار سود۱ دلار سود
۱ ثانیه99,995۵ دلار سود۰.۵ دلار سود
۱۰ ثانیه99,985۵ دلار زیان۰.۵ دلار زیان
۶۰ ثانیه99,980۱۰ دلار زیان۱ دلار زیان

دو چیز را ببین:

  • Markout در افق صفر همان Spread Capture درس ۷ است. یعنی نیم‌اسپردی که لحظه پر شدن گرفتی.
  • افق‌های بعدی می‌گویند از آن نیم‌اسپرد چه چیزی باقی ماند. اینجا بعد از یک دقیقه نه‌تنها چیزی نماند، بلکه ۱۰ دلار به ازای هر BTC زیان داریم.

۴. خواندن منحنی Markout

یک Markout تنها پر از نویز است. ارزش واقعی وقتی پیدا می‌شود که میانگین Markout هزاران پر شدن را در چند افق حساب کنی و به‌صورت یک منحنی ببینی. سه شکل رایج:

شکل منحنیبرداشت
تقریباً صاف و نزدیک نیم‌اسپردجریان عمدتاً ناآگاه است؛ Spread واقعاً به دست می‌آید
نزولی و ثابت‌شده زیر سطح شروعAdverse Selection؛ سطحی که منحنی روی آن ثابت می‌شود، سود واقعی هر پر شدن پیش از کارمزد است
اول نزولی، بعد برگشتاثر موقت (مثلاً فشار نقدشوندگی یا اثر معامله خودت) که بعداً جذب می‌شود؛ انتخاب افق مهم است

چند نکته عملی:

  • انتخاب افق: افق‌ها باید با سرعت بازار و مدت نگه‌داری موجودی تو بخوانند. 1، 10 و 60 ثانیه در این درس مثال‌اند، نه استاندارد.
  • قیمت مرجع: به‌جای Mid می‌توانی از Microprice یا Fair Value خودت (درس ۵) استفاده کنی تا نویز Bid-Ask کمتر شود.
  • Markout همان PnL نیست. ممکن است موجودی را زودتر یا دیرتر از افق Markout ببندی. Markout کیفیت پر شدن را جدا از تصمیم‌های بعدی تو می‌سنجد.
  • تفکیک کن: میانگین کل کافی نیست. Markout را بر اساس سمت معامله، اندازه، جایگاه در صف، Imbalance لحظه پر شدن و ساعت روز جدا کن. Adverse Selection معمولاً در چند دسته خاص متمرکز است.
  • کنار کارمزد بگذار: سود واقعی هر پر شدن تقریباً Markout بلندمدت به‌علاوه ریبیت (یا منهای کارمزد) است. با نرخ‌های فرضی درس ۷، ریبیت ۰.۰۱٪ در قیمت 100,000 یعنی ۱۰ دلار به ازای هر BTC؛ اندازه کل نیم‌اسپرد.

۵. شبیه‌سازی: جریان آگاه و ناآگاه

حالا یک دنیای ساختگی می‌سازیم که در آن می‌دانیم کدام پر شدن آگاه است، و می‌بینیم Markout چطور این را نشان می‌دهد. فرض‌ها:

  • Mid هر ثانیه با نویزی با انحراف معیار ۱ دلار حرکت می‌کند.
  • ۱۵۰ «خبر» در زمان‌های تصادفی رخ می‌دهد؛ بعد از هر خبر، قیمت طی ۲۰ ثانیه ۳۰ دلار در جهت خبر حرکت می‌کند.
  • ۶۰۰ پر شدن ناآگاه در زمان و جهت تصادفی، و ۱۵۰ پر شدن آگاه دقیقاً در لحظه خبر و در جهت آن (پس سمت بازارساز برعکس حرکت است). سهم جریان آگاه ۲۰٪ است.
  • بازارساز همیشه با نیم‌اسپرد ۱۰ دلار از Mid پر می‌شود.
import numpy as np
import pandas as pd

rng = np.random.default_rng(11)
T, half_spread = 20_000, 10.0              # seconds, our half spread in USDT

# Synthetic mid: noise plus "news" events that move the price 30 USDT over 20 s
step = rng.normal(0, 1.0, T)
news_t = rng.choice(np.arange(T - 100), size=150, replace=False)
news_dir = rng.choice([-1, 1], size=150)
for t, d in zip(news_t, news_dir):
    step[t + 1:t + 21] += d * 1.5
mid = 100_000 + np.cumsum(step)

# Uninformed flow: random times, random side. Informed flow: trades right
# before the news, in its direction, so our side is the OPPOSITE of the move.
noise_t = rng.choice(np.arange(T - 100), size=600, replace=False)
fills = pd.DataFrame({
    "t": np.concatenate([noise_t, news_t]),
    "side": np.concatenate([rng.choice([-1, 1], 600), -news_dir]),  # +1 = we bought
    "informed": [False] * 600 + [True] * 150,
})
fills["price"] = mid[fills.t] - fills.side * half_spread   # we buy at bid, sell at ask

for h in (0, 1, 10, 60):
    fills[f"{h}s"] = fills.side * (mid[fills.t + h] - fills.price)

cols = ["0s", "1s", "10s", "60s"]
print(fills.groupby("informed")[cols].mean().round(1))
print("all", fills[cols].mean().round(1).to_dict())

خروجی:

            0s    1s  10s   60s
informed                       
False     10.0  10.0  9.6   9.1
True      10.0   8.5 -4.8 -21.1
all {'0s': 10.0, '1s': 9.7, '10s': 6.7, '60s': 3.0}

همین اعداد به شکل جدول (دلار به ازای هر BTC):

گروهافق صفر۱ ثانیه۱۰ ثانیه۶۰ ثانیه
ناآگاه (۶۰۰ پر شدن)۱۰ سود۱۰ سود۹.۶ سود۹.۱ سود
آگاه (۱۵۰ پر شدن)۱۰ سود۸.۵ سود۴.۸ زیان۲۱.۱ زیان
همه۱۰ سود۹.۷ سود۶.۷ سود۳.۰ سود
Markout افق صفر (نیم‌اسپرد)
10.0
Markout شصت ثانیه، همه پر شدن‌ها
3.0

چطور بخوانیم:

  • ناآگاه: در تئوری باید در همه افق‌ها ۱۰ باشد. افت به ۹.۱ در ۶۰ ثانیه نویز نمونه است؛ حرکت ۶۰ ثانیه‌ای قیمت پراکندگی زیادی دارد و ۶۰۰ نمونه آن را کامل حذف نمی‌کند. این خودش درسی است: Markout به تعداد زیادی پر شدن نیاز دارد.
  • آگاه: منحنی کلاسیک Adverse Selection. بعد از ۱ ثانیه 1.5 دلار، بعد از ۱۰ ثانیه ۱۵ دلار و بعد از ۲۰ ثانیه کل ۳۰ دلار علیه ما حرکت کرده است؛ در تئوری 8.5، منفی ۵ و منفی ۲۰.
  • همه: فرمول بخش ۱ می‌گفت 10 − 0.2 × 30 = 4؛ شبیه‌سازی 3.0 داد (باز هم نویز نمونه). از ۱۰ دلار نیم‌اسپرد، حدود ۷ دلار به جریان آگاه رسید.

بازارساز در برابر Adverse Selection چه می‌کند؟

هیچ‌کدام از این واکنش‌ها مجانی نیست؛ هر کدام نرخ پر شدن یا سهم بازار را کم می‌کند:

  • Spread بازتر در شرایطی که سهم جریان آگاه بالاست (درس ۲: Spread بزرگ‌تر اغلب نشانه ریسک است، نه فرصت).
  • Fair Value بهتر: هرچه تخمین تو به قیمت آینده نزدیک‌تر باشد (درس ۵)، جریان آگاه کمتر می‌تواند از تو سود ببرد.
  • سرعت: لغو و به‌روزرسانی سریع‌تر سفارش‌ها، تا قیمت کهنه کمتر برداشته شود. تأخیر را در درس ۱۹ مدل می‌کنیم.
  • حجم کمتر یا توقف در لحظه‌های پرخطر، مثل پیش از اعلام خبرهای زمان‌بندی‌شده.

۶. تمرین این درس

گزینه مناسب هر سؤال را انتخاب کن و در پایان نتیجه را ببین.

سؤال ۱: بازارساز در 100,010 می‌فروشد. ده ثانیه بعد Mid برابر 100,025 است. Markout ده‌ثانیه‌ای این پر شدن به ازای هر BTC چقدر است؟
سؤال ۲: Markout در افق صفر (با تعریف نسبت به قیمت پر شدن) معادل کدام است؟
سؤال ۳: نیم‌اسپرد 10 دلار است و بعد از هر معامله آگاه قیمت 40 دلار علیه بازارساز حرکت می‌کند. در چه سهمی از جریان آگاه، سود انتظاری پیش از کارمزد صفر می‌شود؟
سؤال ۴: منحنی میانگین Markout در همه افق‌ها تقریباً صاف و نزدیک نیم‌اسپرد است. بهترین برداشت چیست؟

درس بعدی

در این درس دیدیم ۹.۱ به‌جای ۱۰ و 3.0 به‌جای 4 می‌تواند فقط نویز باشد. ولی از کجا بفهمیم یک اختلاف نویز است یا واقعی؟ با درس نهم وارد بخش سوم مسیر، مدل‌های ریاضی و Quantitative Finance، می‌شویم و از پایه شروع می‌کنیم: مبانی آمار؛ بازده، واریانس، انحراف معیار و توزیع بازده. همان ابزارهایی که برای سنجیدن نوسان، ریسک موجودی و معناداری Markout لازم داریم.

این مطلب صرفاً آموزشی است و توصیه خرید، فروش یا سرمایه‌گذاری نیست.