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

مسیر Quant Developer · بخش ۵: Backtesting و شبیه‌سازی · درس ۱۹

Latency، Fees و Slippage

تأخیر از کجا می‌آید و چرا قیمت کهنه یعنی شکار شدن، کارمزد چطور مرز سود و زیان را جابه‌جا می‌کند، و اسلیپیج سفارش‌های Taker هج را در Backtest چطور مدل کنیم.

سطح: متوسط تا پیشرفته۱۴ دقیقه مطالعه

۱. سه هزینه‌ای که Backtest ساده صفر می‌گیرد

در درس ۱۸ دیدیم فرض پر شدن چطور PnL را چند برابر جابه‌جا می‌کند. ولی آنجا سه چیز را صفر فرض کردیم:

  • Latency (تأخیر): فاصله زمانی بین رخ دادن یک رویداد در صرافی و رسیدن واکنش تو به صرافی.
  • Fees (کارمزد): که در درس ۷ با جزئیات حساب کردیم، ولی اینجا اثرش را روی تصمیم «این استراتژی ارزش اجرا دارد یا نه» می‌بینیم.
  • Slippage (اسلیپیج): فاصله قیمت اجرای واقعی یک سفارش Taker با قیمتی که هنگام تصمیم دیده بودی؛ در درس ۴ اندازه‌گیری‌اش را دیدیم، اینجا مدل کردنش در Backtest را.

هر سه یک ویژگی مشترک دارند: در Backtest خوش‌بینانه حذفشان آسان است و در اجرای واقعی هیچ‌وقت صفر نیستند.

۲. Latency از کجا می‌آید؟

وقتی در صرافی اتفاقی می‌افتد، مثلاً یک معامله بزرگ قیمت را جابه‌جا می‌کند، واکنش تو از چند مرحله عبور می‌کند. اعداد زیر فرضی‌اند و فقط مرتبه بزرگی را نشان می‌دهند؛ مقدار واقعی به فاصله فیزیکی تا صرافی، شبکه و زیرساخت بستگی دارد و می‌تواند از چند صد میکروثانیه تا ده‌ها میلی‌ثانیه باشد:

مرحلهاز کجا تا کجامقدار فرضی
Market Data Latencyرویداد در Matching Engine تا رسیدن پیامش به برنامه تو3 ms
Decision Latencyپردازش پیام، به‌روزرسانی مدل و تصمیم0.5 ms
Order Latencyفرستادن سفارش یا لغو تا رسیدن به Matching Engine3 ms
Ack Latencyتأیید صرافی تا رسیدن به تو3 ms

برای بازارساز مهم‌ترین عدد، زمان واکنش است: از لحظه‌ای که چیزی در صرافی عوض شد تا لحظه‌ای که لغو یا سفارش جدید تو به صرافی رسید.

Reaction = Market Data + Decision + Order = 3 + 0.5 + 3 = 6.5 ms

چند نکته که در یک عدد میانگین دیده نمی‌شود:

  • میانگین کافی نیست؛ دنباله مهم است. اگر میانگین تأخیر ۶.۵ میلی‌ثانیه باشد ولی ۱٪ پیام‌ها ۵۰ میلی‌ثانیه طول بکشند، همان ۱٪ می‌تواند بیشترین زیان را بسازد. تأخیر را با صدک‌ها (p50، p99) گزارش کن، نه فقط میانگین.
  • تأخیر وقتی بیشتر می‌شود که بیشتر مهم است. در لحظه‌های پرنوسان، حجم پیام‌ها چند برابر می‌شود و صف پیام‌ها هم در صرافی و هم در سیستم تو بلندتر می‌شود.
  • برای اندازه‌گیری، ساعت‌ها باید هم‌زمان باشند. اختلاف زمان صرافی با زمان دریافت فقط وقتی معنا دارد که ساعت سیستم تو دقیق تنظیم شده باشد. این را در درس ۲۸ (Observability) دنبال می‌کنیم.
  • تأخیر جایگاه صف را هم بد می‌کند. در درس ۱۸ گفتیم جایگاه در صف از لحظه رسیدن سفارش حساب می‌شود. هر میلی‌ثانیه دیرتر یعنی سفارش‌های بیشتری جلوی تو.

۳. قیمت کهنه و شکار شدن

خطرناک‌ترین اثر تأخیر این است که سفارش‌هایت بعد از تغییر قیمت هنوز در دفتر بمانند. به چنین سفارشی Stale Quote (قیمت کهنه) می‌گویند.

فرض کن سفارش‌های تو 99,990 و 100,010 هستند، هر کدام 0.1 BTC، حول Fair Value برابر 100,000 (درس ۵). ناگهان در بازار دیگری، مثلاً قرارداد Perpetual همین دارایی (درس ۲۲)، قیمت بالا می‌رود و Fair Value به 100,050 می‌رسد:

زمانچه اتفاقی می‌افتد
0 msFair Value از 100,000 به 100,050 می‌رسد
1 msیک معامله‌گر سریع تغییر را می‌بیند
3 msسفارش خرید او به صرافی می‌رسد و Ask تو در 100,010 را می‌خرد
6.5 msلغو تو به صرافی می‌رسد؛ دیگر چیزی برای لغو نمانده

تو 0.1 BTC را به 100,010 فروختی که حالا 100,050 می‌ارزد:

Loss = (100,050 − 100,010) × 0.1 = 4 USDT

به این Picked Off شدن (شکار شدن) می‌گویند. این شکل خالص Adverse Selection درس ۸ است: طرف مقابل چیزی نمی‌داند که تو ندانی؛ فقط زودتر از تو می‌داند. نکته مهم این است که این زیان به پهنای Spread تو ربطی ندارد. با هر پرشی بزرگ‌تر از نیم‌اسپرد، قیمت کهنه یعنی زیان؛ تنها سؤال این است که در مسابقه سرعت چند بار می‌بازی.

۴. تأخیر در Backtest

اسکلت درس ۱۷ تأخیر را از اول در ساختارش داشت: md_latency و order_latency زمان رسیدن هر پیام را جابه‌جا می‌کنند. چند قدم برای واقع‌گرایانه‌تر کردنش:

  1. تأخیر را ثابت نگیر. از توزیعی بکش که از اندازه‌گیری خودت آمده، با دنباله سنگین، و در لحظه‌های پرحجم بزرگ‌ترش کن.
  2. رقابت را مدل کن. داده تاریخی می‌گوید معامله‌ای رخ داد، ولی نمی‌گوید اگر لغو تو زودتر می‌رسید، آن معامله‌گر چه می‌کرد. ساده‌ترین مدل این است که زمان واکنش سریع‌ترین رقیب را یک متغیر تصادفی بگیری و هر بار که پرش قیمت رخ می‌دهد، ببینی او زودتر رسیده یا لغو تو.
  3. زمان دیدن و زمان رسیدن را جدا نگه دار. تصمیم با داده‌ای که t + تأخیر داده دیده شده گرفته می‌شود و در t + تأخیر داده + تأخیر تصمیم + تأخیر سفارش اجرا می‌شود.

در شبیه‌سازی بخش ۶ از مدل ساده بند ۲ استفاده می‌کنیم. اگر زمان واکنش سریع‌ترین رقیب توزیع نمایی با میانگین τ داشته باشد و زمان واکنش تو L باشد، احتمال اینکه او زودتر برسد:

P(picked off) = 1 − e^(−L / τ)

با τ برابر ۱۰ میلی‌ثانیه (فرضی): برای L برابر ۱ میلی‌ثانیه حدود ۱۰٪، برای ۱۰ میلی‌ثانیه حدود ۶۳٪ و برای ۵۰ میلی‌ثانیه بیش از ۹۹٪.

۵. کارمزد: یک سطح، کل استراتژی

در درس ۷ دیدیم برای 0.1 BTC با نیم‌اسپرد ۱۰ دلاری، سهم Spread هر معامله فقط ۱ دلار است و کارمزد هم‌اندازه یا بزرگ‌تر از آن است. بیشتر صرافی‌ها کارمزد را پلکانی (Tiered) تعیین می‌کنند: هر چه حجم معاملات ماهانه بیشتر، نرخ کمتر. یک جدول فرضی، که سطح آخرش همان نرخ‌های درس ۱ و ۷ است:

سطححجم ۳۰ روزه (فرضی)MakerTakerکارمزد Maker هر پر شدن 0.1 BTC
۱کمتر از ۱ میلیون USDT۰.۰۲٪۰.۰۸٪۲ دلار پرداختی
۲۱ تا ۵۰ میلیون۰.۰۱٪۰.۰۷٪۱ دلار پرداختی
۳۵۰ تا ۵۰۰ میلیونصفر۰.۰۶٪صفر
۴بیش از ۵۰۰ میلیونریبیت ۰.۰۱٪۰.۰۵٪۱ دلار دریافتی

حالا یک واحد مشترک لازم داریم. Basis Point (bp) یعنی یک‌صدم درصد، یعنی ۰.۰۱٪. نیم‌اسپرد ۱۰ دلار روی قیمت 100,000 دقیقاً 1 bp است. پس:

Edge per fill = half-spread − maker fee = 1 bp − fee

در سطح ۲، کارمزد Maker برابر کل سهم Spread است و استراتژی پیش از هر حرکت قیمتی سربه‌سر است. در سطح ۱ هر پر شدن زیان‌ده است. در سطح ۴ ریبیت درآمد هر پر شدن را دو برابر می‌کند. یعنی سطح کارمزد خودش یک پارامتر استراتژی است، و استراتژی‌ای که فقط در سطح ۴ سودده است، تا وقتی به حجم آن سطح نرسی، اصلاً قابل اجرا نیست.

۶. شبیه‌سازی: حساسیت PnL به تأخیر و کارمزد

حالا دو اثر را کنار هم می‌گذاریم. مدل عمداً ساده است تا هر عدد قابل ردیابی باشد. فرض‌ها (همه فرضی):

  • سفارش‌ها 0.1 BTC در فاصله ۱۰ دلار از Fair Value برابر 100,000 هستند؛ ارزش هر پر شدن حدود 10,000 USDT.
  • معامله‌گرهای بی‌اطلاع به‌طور تصادفی، به‌طور میانگین هر ۲۰ ثانیه یک بار در هر طرف، با تو معامله می‌کنند. هر پر شدن نیم‌اسپرد را می‌دهد: ۱ دلار.
  • Fair Value به‌طور میانگین هر ۲۰ ثانیه یک بار ۵۰ دلار می‌پرد. اگر سریع‌ترین رقیب زودتر از لغو تو برسد، شکار می‌شوی: (50 − 10) × 0.1 = 4 دلار زیان.
  • زمان واکنش سریع‌ترین رقیب توزیع نمایی با میانگین ۱۰ میلی‌ثانیه دارد.
  • ریسک موجودی را کنار می‌گذاریم؛ هر پر شدن با Fair Value همان لحظه ارزش‌گذاری می‌شود.
import numpy as np

rng = np.random.default_rng(19)
HOURS = 200
Q, HALF, JUMP, NOTIONAL = 0.1, 10, 50, 10_000   # BTC, USDT, USDT, USDT per fill

# Uninformed takers hit our bid or ask at random: each such fill earns the half-spread
n_noise = rng.poisson(2 * 0.05 * 3600 * HOURS)      # 0.05 fills/s on each side
# Fair value jumps by 50 USDT now and then, and one of our quotes becomes stale
n_jump = rng.poisson(0.05 * 3600 * HOURS)           # one jump every 20 s on average
arb_time = rng.exponential(0.010, n_jump)           # fastest taker's reaction time (s)

def pnl_per_hour(latency, maker_fee):
    picked = np.sum(arb_time < latency)              # taker arrives before our cancel
    gross = n_noise * HALF * Q - picked * (JUMP - HALF) * Q
    fees = (n_noise + picked) * NOTIONAL * maker_fee
    return (gross - fees) / HOURS

fees = [-0.0001, 0.0, 0.0001, 0.0002]               # hypothetical tiers 4..1 (negative = rebate)
print("latency  " + "".join(f"{f * 1e4:+7.0f}bp" for f in fees))
for ms in (1, 5, 10, 20, 50):
    print(f"{ms:4d} ms " + "".join(f"{pnl_per_hour(ms / 1000, f):9.0f}" for f in fees))
latency       -1bp     +0bp     +1bp     +2bp
   1 ms       668      291      -86     -463
   5 ms       506       75     -355     -786
  10 ms       378      -96     -569    -1043
  20 ms       254     -261     -776    -1291
  50 ms       185     -353     -891    -1429

همین جدول به زبان سطح‌های کارمزد (USDT در ساعت):

زمان واکنشسطح ۴: ریبیت 1 bpسطح ۳: صفرسطح ۲: 1 bpسطح ۱: 2 bp
1 ms۶۶۸ سود۲۹۱ سود۸۶ زیان۴۶۳ زیان
5 ms۵۰۶ سود۷۵ سود۳۵۵ زیان۷۸۶ زیان
10 ms۳۷۸ سود۹۶ زیان۵۶۹ زیان۱,۰۴۳ زیان
20 ms۲۵۴ سود۲۶۱ زیان۷۷۶ زیان۱,۲۹۱ زیان
50 ms۱۸۵ سود۳۵۳ زیان۸۹۱ زیان۱,۴۲۹ زیان

این مدل آن‌قدر ساده است که جواب دقیقش را با دست هم می‌شود نوشت. در هر ساعت به‌طور میانگین ۳۶۰ پر شدن بی‌اطلاع و ۱۸۰ پرش داریم. با f نرخ کارمزد Maker و N ارزش هر پر شدن:

E[PnL per hour] = 360 × (1 − f × N) − 180 × P(picked off) × (4 + f × N)

برای کارمزد صفر و تأخیر ۱ میلی‌ثانیه: 360 − 180 × 0.095 × 4 ≈ 291؛ همان عدد شبیه‌سازی. سه برداشت:

۱. تأخیر می‌تواند علامت نتیجه را عوض کند. با کارمزد صفر، رفتن از ۱ به ۱۰ میلی‌ثانیه سود ۲۹۱ دلاری را به ۹۶ دلار زیان تبدیل می‌کند. نقطه سربه‌سر جایی است که 360 = 180 × P × 4، یعنی P برابر ۰.۵ و L برابر τ × ln 2، حدود ۶.۹ میلی‌ثانیه. در این مدل، استراتژی با زمان واکنش ۶.۵ میلی‌ثانیه بخش ۲ درست روی مرز است.

۲. یک سطح کارمزد هم‌وزن کل محور تأخیر است. فاصله دو ستون کنار هم بین ۳۷۷ و ۵۳۸ دلار در ساعت است، چون ۱ bp یعنی ۱ دلار برای هر پر شدن. این هم‌مرتبه با کل فاصله ۱ تا ۵۰ میلی‌ثانیه در یک ستون است (بین ۴۸۳ و ۹۶۶ دلار).

۳. ریبیت مشکل را پنهان می‌کند. در ستون سطح ۴، استراتژی حتی با ۵۰ میلی‌ثانیه تأخیر سودده است. ولی تقریباً همه سودش از ریبیت می‌آید و با هر بار شکار شدن، بخشی از آن را پس می‌دهد. اگر حجم ماهانه کم شود و به سطح ۳ برگردی، همین استراتژی در هر تأخیری بالای حدود ۷ میلی‌ثانیه زیان‌ده است، و در سطح ۲ در هر تأخیری.

محدودیت‌های مدل: پرش‌ها همه هم‌اندازه‌اند، معامله‌گرهای بی‌اطلاع به تأخیر حساس نیستند، ریسک موجودی و جایگاه صف کنار گذاشته شده، و τ عددی است که در واقعیت باید از داده تخمین زده شود؛ مثلاً از Markout پر شدن‌هایی که درست بعد از حرکت‌های تند قیمت رخ داده‌اند (درس ۸ و ۳۱).

۷. اسلیپیج سفارش‌های Taker هج

بازارساز معمولاً Maker است، ولی وقتی موجودی از حد مجاز بیرون می‌زند، ممکن است با سفارش Taker آن را کم کند یا در بازار دیگری هج کند (درس ۲۱). اینجا اسلیپیج وارد می‌شود. چهار مدل رایج در Backtest، از ساده به دقیق:

  1. صفر: اجرا با Mid یا با Best Bid و Ask. تقریباً همیشه غلط و خوش‌بینانه.
  2. ثابت: هزینه‌ای ثابت بر حسب bp، مثلاً «نیم‌اسپرد به‌اضافه ۲ bp». ساده و برای حجم کوچک قابل قبول.
  3. پیمایش دفتر ثبت‌شده: سفارش را روی دفتر سفارشی که در داده داری اجرا کن، همان کاری که در درس ۴ کردیم. نکته‌اش این است که دفتر را در لحظه رسیدن سفارش بخوانی، نه لحظه تصمیم. در لحظه‌های پرنوسان، همین چند میلی‌ثانیه بیشترین اسلیپیج را می‌سازد.
  4. مدل اثر قیمتی: برای حجم‌های بزرگ که چند دقیقه یا چند ساعت اجرا می‌شوند، دفتر لحظه‌ای کافی نیست، چون بازار به سفارش تو واکنش نشان می‌دهد. یک رابطه تجربی رایج در پژوهش‌های اجرای سفارش، قانون ریشه دوم (Square-Root Law) است:
Impact / Price ≈ Y × σ × √(Q / V)

σ نوسان روزانه، V حجم معاملات روزانه بازار، Q حجم سفارش تو و Y ضریبی از مرتبه یک است که باید برای هر بازار تخمین زده شود. با اعداد فرضی σ برابر ۲٪، V برابر 10,000 BTC، Q برابر 10 BTC و Y برابر ۱، اثر حدود 0.02 × √0.001 ≈ 6.3 bp می‌شود؛ یعنی حدود ۶۳ دلار برای هر BTC.

برای حجم‌های کوچک، مدل ۳ کافی است. دفتر سفارش درس ۱ را در نظر بگیر و فرض کن بعد از پر شدن چند سفارش فروش، موجودی منفی داری و می‌خواهی با خرید Market آن را ببندی؛ کارمزد Taker همان ۰.۰۵٪ فرضی درس ۷ است:

حجم هجمیانگین قیمتاسلیپیج نسبت به Midکارمزد Takerهزینه کل
0.1 BTC100,010۱ دلار۵.۰ دلار۶.۰ دلار
0.5 BTC100,014۷ دلار۲۵.۰ دلار۳۲.۰ دلار
1.0 BTC100,019۱۹ دلار۵۰.۰ دلار۶۹.۰ دلار
سهم Spread هر پر شدن Maker، 0.1 BTC
1 USDT
هزینه هج Taker همان 0.1 BTC
6 USDT

اگر هر پر شدن را فوراً با Taker هج کنی، هزینه هج شش برابر درآمد Spread آن است. حتی اگر ده پر شدن را جمع کنی و یکجا 1 BTC هج کنی، ۶۹ دلار هزینه در برابر ۱۰ دلار درآمد می‌ماند. با این نرخ‌های فرضی، کارمزد Taker بخش بزرگ‌تر هزینه است، نه اسلیپیج. به همین دلیل در درس ۶ موجودی را با Skew کم کردیم و در درس ۲۱ می‌بینیم هج کِی و با چه ابزاری ارزشش را دارد.

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

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

سؤال ۱: تأخیر داده بازار 4 میلی‌ثانیه، تأخیر تصمیم 1 میلی‌ثانیه و تأخیر سفارش 4 میلی‌ثانیه است. از لحظه رخ دادن یک رویداد در صرافی تا رسیدن لغو تو به صرافی چقدر طول می‌کشد؟
سؤال ۲: سفارش 0.1 BTC با نیم‌اسپرد 10 دلار حول 100,000 پر می‌شود و کارمزد Maker فرضی ۰.۰۲٪ است. نتیجه این پر شدن پیش از هر حرکت قیمت چیست؟
سؤال ۳: با مدل بخش ۴ و τ برابر 10 میلی‌ثانیه، اگر زمان واکنش تو 10 میلی‌ثانیه باشد، احتمال شکار شدن بعد از هر پرش چقدر است؟
سؤال ۴: با دفتر سفارش درس ۱ و کارمزد Taker فرضی ۰.۰۵٪، هزینه کل خرید Market به حجم 0.5 BTC نسبت به Mid چقدر است؟

درس بعدی

در درس بیستم، آخرین درس بخش Backtesting، می‌پرسیم خروجی Backtest را با چه معیارهایی بخوانیم: Net PnL، Drawdown، Sharpe Ratio و دام‌های سالانه‌سازی آن برای PnL پرتکرار، نرخ پر شدن و PnL به ازای حجم معامله، و اینکه چطور بفهمیم نتیجه پایدار است یا فقط حاصل شانس و تنظیم بیش از حد پارامترها.

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