مسیر 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 دلار علیه تو حرکت میکند. اگر سهم جریان آگاه π باشد:
با π = 20٪، سود انتظاری هر پر شدن 10 − 0.2 × 30 = 4 دلار است؛ یعنی ۶۰٪ نیماسپرد از دست رفت. اگر سهم جریان آگاه به یکسوم برسد، سود انتظاری صفر میشود؛ و این هنوز پیش از کارمزد است. نکته کلیدی: همان h و همان نرخ پر شدن، بسته به اینکه چه کسی سفارش را پر کرده، میتواند سودده یا زیانده باشد.
۲. چرا پر شدنها قبل از حرکت نامطلوب جمع میشوند
حتی بدون معاملهگر «باهوش»، سازوکار خود دفتر سفارش پر شدنها را به سمت لحظههای بد میبرد:
- صف (یادآوری درس ۳): سفارش خرید تو در ته صف 99,990 فقط وقتی پر شد که ۰.۵۵ BTC فروش Market به آن سطح رسید. جریان فروش آنقدر سنگین که کل صف جلوی تو را بخورد، خودش نشانه فشار فروش است و قیمت بعد از آن به احتمال بیشتر پایین میرود. به بیان دیگر، پر شدن سفارش ته صف با شرط حرکت نامطلوب اتفاق میافتد.
- قیمت کهنه: وقتی Fair Value جهش میکند (درس ۵) و سیستم تو چند میلیثانیه دیرتر سفارشها را بهروز میکند، معاملهگرهای سریعتر همان قیمت کهنه را برمیدارند. به این Picking Off میگویند.
- عدم تقارن ذاتی: اگر قیمت به سمت سفارش تو بیاید، سفارشت پر میشود و حالا موجودیای داری که در جهت اشتباه است. اگر قیمت از سفارشت دور شود، سفارشت پر نمیشود و از آن حرکت هیچ سودی نمیبری.
۳. Markout: قیمت بعد از پر شدن چه شد؟
Markout میسنجد هر پر شدن، اگر آن را با قیمت چند لحظه بعد ارزشگذاری کنی، چقدر سود یا زیان داشت. برای پر شدنی در زمان t با قیمت Price و در افق h:
که s مثل درس ۷ برای خرید برابر ۱ و برای فروش برابر منفی ۱ است. نتیجه به ازای یک واحد دارایی (اینجا دلار به ازای هر BTC) است؛ برای عدد دلاری در حجم ضرب میشود و برای مقایسه بین داراییها معمولاً به basis point تبدیل میشود (۱۰ دلار روی قیمت 100,000 برابر ۱ basis point است).
مثال
بازارساز در 99,990 میخرد، وقتی Mid برابر 100,000 است. قیمت میانی در لحظههای بعد:
| افق | Mid | Markout به ازای هر 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 بهتر: هرچه تخمین تو به قیمت آینده نزدیکتر باشد (درس ۵)، جریان آگاه کمتر میتواند از تو سود ببرد.
- سرعت: لغو و بهروزرسانی سریعتر سفارشها، تا قیمت کهنه کمتر برداشته شود. تأخیر را در درس ۱۹ مدل میکنیم.
- حجم کمتر یا توقف در لحظههای پرخطر، مثل پیش از اعلام خبرهای زمانبندیشده.
۶. تمرین این درس
گزینه مناسب هر سؤال را انتخاب کن و در پایان نتیجه را ببین.
درس بعدی
در این درس دیدیم ۹.۱ بهجای ۱۰ و 3.0 بهجای 4 میتواند فقط نویز باشد. ولی از کجا بفهمیم یک اختلاف نویز است یا واقعی؟ با درس نهم وارد بخش سوم مسیر، مدلهای ریاضی و Quantitative Finance، میشویم و از پایه شروع میکنیم: مبانی آمار؛ بازده، واریانس، انحراف معیار و توزیع بازده. همان ابزارهایی که برای سنجیدن نوسان، ریسک موجودی و معناداری Markout لازم داریم.
این مطلب صرفاً آموزشی است و توصیه خرید، فروش یا سرمایهگذاری نیست.