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

مسیر Quant Developer · بخش ۳: مدل‌های ریاضی و Quantitative Finance · درس ۱۱

مدل Avellaneda–Stoikov

اولین مدل کلاسیک بازارسازی: فرض‌ها، Reservation Price و Spread بهینه، شهود هر جمله، و یک شبیه‌سازی که آن را با قیمت‌گذاری متقارن مقایسه می‌کند.

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

۱. از شهود Skew تا فرمول

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

مارکو آولانِدا و ساشا استویکوف در مقاله‌ای در سال ۲۰۰۸ با عنوان High-frequency trading in a limit order book به این دو سؤال جواب ریاضی دادند. این مقاله نقطه شروع تقریباً همه مدل‌های کمی بازارسازی است که بعد از آن آمدند، از جمله مدل درس بعد.

۲. فرض‌های مدل

مدل چهار جزء دارد. هر کدام ساده‌سازی است و بعداً سراغ هزینه‌شان می‌رویم.

۱. قیمت میانی بدون روند حرکت می‌کند. Mid Price که با s نشان می‌دهیم، یک حرکت براونی (Brownian Motion) با نوسان σ است:

dS = σ × dW

یعنی تغییر قیمت در هر بازه کوچک تصادفی و نرمال است، میانگینش صفر است و واریانسش با زمان خطی رشد می‌کند؛ همان قاعده جذر زمان درس ۹. σ اینجا بر حسب واحد قیمت است (مثلاً USDT به ازای جذر ثانیه)، نه درصد.

۲. بازارساز ریسک‌گریز است. او تا افق زمانی T معامله می‌کند و در پایان، موجودی‌اش با Mid ارزش‌گذاری می‌شود. هدفش بیشینه کردن این مطلوبیت نمایی (Exponential Utility) است:

max E[ −exp(−γ × (X(T) + q(T) × S(T))) ]

X پول نقد، q موجودی و γ ضریب ریسک‌گریزی (Risk Aversion) است. γ بزرگ یعنی بازارساز حاضر است سود میانگین کمتری بگیرد تا نوسان نتیجه‌اش کمتر شود. γ نزدیک صفر یعنی تقریباً فقط میانگین برایش مهم است.

۳. احتمال پر شدن با فاصله از Mid کم می‌شود. اگر سفارشت به فاصله δ از Mid باشد، سفارش‌های Market که به آن می‌خورند با این نرخ می‌رسند:

λ(δ) = A × e^(−k × δ)

A سطح کلی فعالیت بازار است (نرخ پر شدن وقتی دقیقاً روی Mid باشی) و k نشان می‌دهد این نرخ با دور شدن از Mid چقدر سریع افت می‌کند. مقاله این شکل نمایی را از فرض‌هایی درباره توزیع اندازه سفارش‌های Market و اثر قیمتی‌شان بیرون می‌کشد؛ ما آن را یک فرض تجربی در نظر می‌گیریم که باید با داده سنجیده شود (درس ۱۸).

۴. هر Fill یک واحد است و کارمزد، تأخیر و Tick Size در مدل نیستند.

۳. Reservation Price: قیمت از نگاه خودت

اولین نتیجه مدل، Reservation Price است: ارزشی که بازارساز، با توجه به موجودی فعلی‌اش، واقعاً برای دارایی قائل است:

r = s − q × γ × σ² × (T − t)

هر جمله یک معنی روشن دارد:

  • q: اگر موجودی مثبت داری (Long)، r پایین‌تر از Mid است؛ یعنی برای تو یک واحد بیشتر BTC کمتر از قیمت بازار ارزش دارد، چون ریسکت را بیشتر می‌کند. با موجودی منفی، برعکس.
  • σ² × (T − t): واریانس حرکت قیمت در زمان باقی‌مانده. هر چه بازار پرنوسان‌تر یا افق طولانی‌تر باشد، نگه داشتن موجودی پرریسک‌تر است.
  • γ: همین ریسک را با ترجیح شخصی تو به پول تبدیل می‌کند.

مثال با BTC

فرض کن Mid برابر 100,000 است، 0.5 BTC موجودی داری، σ برابر 10 USDT به ازای جذر ثانیه است (حدود 2.9% روزانه، کمی پرنوسان‌تر از مثال درس ۹)، γ برابر 0.001 به ازای هر USDT و افق باقی‌مانده 60 ثانیه است. همه این اعداد فرضی‌اند:

r = 100,000 − 0.5 × 0.001 × 100 × 60 = 99,997

پس از نگاه تو، BTC سه دلار کمتر از Mid می‌ارزد و قیمت‌هایت را حول 99,997 می‌گذاری، نه 100,000.

۴. Spread بهینه

نتیجه دوم، مجموع فاصله قیمت خرید و فروش است:

δa + δb = γ × σ² × (T − t) + (2/γ) × ln(1 + γ/k)

و قیمت‌ها حول r قرار می‌گیرند، نه حول Mid:

bid = r − (δa + δb) / 2
ask = r + (δa + δb) / 2

دو جمله Spread دو منبع متفاوت دارند:

  • جمله ریسک (γσ²(T − t)): جبران ریسک موجودی در زمان باقی‌مانده. نزدیک پایان افق به صفر می‌رسد.
  • جمله نقدشوندگی ((2/γ)·ln(1 + γ/k)): از شکل λ(δ) می‌آید. اگر γ خیلی کوچک باشد، این جمله تقریباً 2/k می‌شود. k بزرگ یعنی سفارش‌ها با کمی فاصله دیگر پر نمی‌شوند، پس Spread باید تنگ باشد؛ k کوچک یعنی معامله‌گرها حتی با فاصله زیاد هم می‌آیند و بازارساز می‌تواند Spread بازتری بگیرد.

در مثال BTC، با k برابر 0.1 به ازای هر USDT (یعنی با هر 10 دلار دورتر شدن، نرخ پر شدن e برابر کم می‌شود):

Spread = 0.001 × 100 × 60 + (2 / 0.001) × ln(1.01) = 6 + 19.90 = 25.90 USDT
bid = 99,997 − 12.95 = 99,984.05
ask = 99,997 + 12.95 = 100,009.95

Ask فقط 9.95 دلار بالای Mid است و Bid 15.95 دلار پایین آن. قیمت‌ها نامتقارن شده‌اند تا فروش محتمل‌تر از خرید باشد و موجودی به سمت صفر برگردد. دقت کن که اندازه Spread به q بستگی ندارد؛ موجودی فقط مرکز قیمت‌ها را جابه‌جا می‌کند.

اثر پارامترها

وقتی این بزرگ‌تر می‌شودSkew (فاصله r از Mid)Spread
موجودی (قدرمطلق q)بیشتربدون تغییر
نوسان σبیشتربیشتر
زمان باقی‌مانده T − tبیشتربیشتر
ریسک‌گریزی γبیشترجمله ریسک بیشتر، جمله نقدشوندگی کمی کمتر
kبدون تغییرکمتر

یک نکته جالب: A در هیچ‌کدام از دو فرمول نیست. در این مدل، اینکه بازار در کل چقدر فعال است روی قیمت‌گذاری اثر نمی‌گذارد؛ فقط شیب افت احتمال پر شدن (k) مهم است. در درس بعد می‌بینیم این نتیجه در مدل دقیق‌تر عوض می‌شود.

۵. شبیه‌سازی: Avellaneda–Stoikov در برابر قیمت‌گذاری متقارن

حالا مدل را با یک رقیب ساده مقایسه می‌کنیم: بازارسازی که همان Spread را می‌گذارد ولی حول Mid، بدون توجه به موجودی. پارامترها همان مثال عددی خود مقاله‌اند و واحدها انتزاعی‌اند (قیمت اولیه 100): σ برابر 2، T برابر 1، گام زمانی 0.005، γ برابر 0.1، k برابر 1.5 و A برابر 140. در هر گام، احتمال پر شدن هر طرف λ(δ) × dt است و قیمت به اندازه σ√dt بالا یا پایین می‌رود:

import numpy as np

# Parameters of the numerical example in Avellaneda & Stoikov (2008)
s0, T, sigma, dt = 100.0, 1.0, 2.0, 0.005
gamma, k, A = 0.1, 1.5, 140.0
n_steps, n_paths = int(T / dt), 1000

def simulate(strategy, seed=1):
    rng = np.random.default_rng(seed)
    pnl, q_end = np.zeros(n_paths), np.zeros(n_paths)
    for p in range(n_paths):
        s, q, cash = s0, 0, 0.0
        for i in range(n_steps):
            tau = T - i * dt                                   # time left: T - t
            spread = gamma * sigma**2 * tau + (2 / gamma) * np.log(1 + gamma / k)
            r = s - q * gamma * sigma**2 * tau                 # reservation price
            center = r if strategy == "AS" else s              # symmetric: around mid
            bid, ask = center - spread / 2, center + spread / 2
            # Fill probabilities depend on distance from the MID price s
            if rng.random() < A * np.exp(-k * (s - bid)) * dt:
                q += 1; cash -= bid
            if rng.random() < A * np.exp(-k * (ask - s)) * dt:
                q -= 1; cash += ask
            s += sigma * np.sqrt(dt) * (1 if rng.random() < 0.5 else -1)
        pnl[p], q_end[p] = cash + q * s, q                     # mark to market at T
    return pnl, q_end

for name in ["AS", "symmetric"]:
    pnl, q = simulate(name)
    print(f"{name:9s} mean PnL={pnl.mean():6.2f}  std PnL={pnl.std():5.2f}  "
          f"5% worst={np.percentile(pnl, 5):6.2f}  std final q={q.std():4.2f}")

خروجی:

AS        mean PnL= 64.94  std PnL= 6.49  5% worst= 53.74  std final q=2.89
symmetric mean PnL= 68.40  std PnL=12.59  5% worst= 45.99  std final q=8.03

چون هر دو استراتژی با یک Seed اجرا می‌شوند و در هر گام به همان ترتیب عدد تصادفی می‌کشند، مسیر قیمت هر دو دقیقاً یکسان است؛ تفاوت نتیجه فقط از قیمت‌گذاری می‌آید.

  • انحراف معیار موجودی پایانی از 8.03 به 2.89 رسیده است. Skew موجودی را کنترل می‌کند.
  • انحراف معیار PnL تقریباً نصف شده (12.59 در برابر 6.49) و بدترین ۵٪ نتیجه‌ها بهتر شده است (53.74 در برابر 45.99).
  • میانگین PnL کمی کمتر است (64.94 در برابر 68.40). این بهای کنترل ریسک است: Skew گاهی باعث می‌شود معامله‌ای را که قیمت خوبی داشت از دست بدهی.

این همان معامله‌ای است که γ تعریف می‌کند: کمی میانگین کمتر در ازای ریسک خیلی کمتر. مقاله اصلی هم در جدول نتایجش همین الگو را گزارش می‌کند.

۶. محدودیت‌ها: مدل کجا می‌شکند؟

  • σ، A و k ثابت‌اند. در درس ۹ دیدیم نوسان خوشه‌ای است. اگر σ را از یک دوره آرام تخمین بزنی، در دوره پرتلاطم هم Skew و هم Spread کم‌اند.
  • هیچ رابطه‌ای بین جریان سفارش و قیمت نیست. عدم‌توازن دفتر سفارش (درس ۱۰) و Adverse Selection (درس ۸) در مدل جایی ندارند.
  • افق T مصنوعی است. بازار رمزارز تعطیل نمی‌شود. با نزدیک شدن به T، جمله (T − t) به صفر می‌رسد و بازارساز ناگهان نسبت به موجودی بی‌تفاوت می‌شود؛ رفتاری که در عمل منطقی نیست. پیاده‌سازی‌های عملی معمولاً T − t را یک عدد ثابت (افق غلتان) می‌گذارند، که عملاً یعنی یک پارامتر دیگر که باید تنظیم شود.
  • سقفی برای موجودی نیست. q می‌تواند هر قدر بزرگ شود و Skew خطی با آن رشد می‌کند. در شبیه‌سازی بالا با q برابر 5 در لحظه شروع، فاصله r از Mid برابر 5 × 0.1 × 4 = 2 است، در حالی که نیم‌Spread فقط حدود 0.85 است. یعنی Ask حدود 1.15 پایین‌تر از Mid قرار می‌گیرد و در بازار واقعی یا فوراً به‌عنوان Taker معامله می‌شود یا با Post-Only (درس ۳) رد می‌شود.
  • Fill یک‌واحدی، بدون کارمزد، بدون تأخیر و بدون صف. این‌ها را در بخش ۵ (درس‌های ۱۷ تا ۲۰) به شبیه‌سازی اضافه می‌کنیم.

با همه این‌ها، ارزش مدل در ساختار آن است: Skew متناسب با موجودی، ریسک‌گریزی و واریانس باقی‌مانده؛ و Spreadی که از ریسک و از شیب نقدشوندگی می‌آید. تقریباً هر مدل بازارسازی جدی‌تر، همین اسکلت را حفظ می‌کند و یکی از فرض‌ها را واقعی‌تر می‌کند.

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

سؤال ۱: بازارساز 0.5 BTC موجودی مثبت دارد. Reservation Price نسبت به Mid کجاست؟
سؤال ۲: Mid برابر 100,000، q برابر 1 BTC، γ برابر 0.001، σ² برابر 100 و T − t برابر 30 ثانیه است. Reservation Price چقدر است؟
سؤال ۳: اگر γ به صفر نزدیک شود، Spread بهینه به چه عددی نزدیک می‌شود؟
سؤال ۴: کدام پارامتر در فرمول‌های Reservation Price و Spread مدل Avellaneda–Stoikov ظاهر نمی‌شود؟

درس بعدی

در درس دوازدهم سراغ مدل Guéant–Lehalle–Fernandez-Tapia می‌رویم که دو ضعف مهم این مدل را برطرف می‌کند: موجودی را بین دو سقف مشخص نگه می‌دارد و مسئله را دقیق حل می‌کند. از آن فرمول‌های تقریبی ساده‌ای بیرون می‌آید که به افق T وابسته نیستند و برخلاف این درس، A هم در آن‌ها نقش دارد.

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