← العودة إلى قائمة المقالات
May 17, 2025
5 دقائق للقراءة

بناء خوارزمية صناعة السوق لأزواج العملات المشفرة باستخدام نموذج Avellaneda-Stoikov

بناء خوارزمية صناعة السوق لأزواج العملات المشفرة باستخدام نموذج Avellaneda-Stoikov
#market making
#cryptocurrency
#Avellaneda-Stoikov
#algorithmic trading
#reinforcement learning
#PPO
#DeFi

مرحباً أصدقاء! سأوضح لكم اليوم كيفية بناء خوارزمية صناعة السوق لأزواج العملات المشفرة USD+/wETH و USD+/cbbtc. سنستخدم نموذج Avellaneda-Stoikov (A-S) ونعززه بخوارزمية التعلم المعزز (PPO) لتحسين السبريد الديناميكي. يبدو معقداً؟ لا تقلقوا، سأقسم كل شيء إلى خطوات واضحة حتى يتمكن المطور المبتدئ من المتابعة.

تصور صناعة السوق تصور جوهر صناعة السوق: موازنة مستمرة لأوامر الشراء والبيع حول السعر العادل لتوليد سيولة سوقية مثلى.

ما هي صناعة السوق ولماذا نحتاجها؟

صناعة السوق هي استراتيجية يقوم فيها المتداول بوضع أوامر شراء وبيع لأصل ما في وقت واحد، ويكسب من السبريد (الفرق بين الأسعار). في فضاء DeFi، يلعب صناع السوق دوراً رئيسياً بتوفير السيولة وتقليل الانزلاق لمشاركي السوق الآخرين.

تخيل أنك بائع في سوق، مستعد دائماً لشراء منتج بسعر أقل قليلاً من سعر السوق وبيعه بسعر أعلى قليلاً. ربحك هو الفرق بين سعري الشراء والبيع. لكن هناك مأزق: إذا تحرك السعر فجأة في اتجاه واحد، فقد تتراكم لديك مخزون كبير أو على العكس تُترك بدون ما تبيعه.

نموذج Avellaneda-Stoikov: الرياضيات في خدمة التداول

نموذج A-S هو نهج رياضي لتحديد الأسعار المثلى لصناعة السوق. ميزته الرئيسية أنه يأخذ في الاعتبار ليس فقط السعر السوقي الحالي، بل أيضاً حجم المركز (المخزون)، وتقلب السوق، والرغبة في المخاطرة.

المعادلات الرئيسية للنموذج:

δ_a = S_t + (1/γ) * ln(1 + γ/k) + q_t * σ² * T
δ_b = S_t - (1/γ) * ln(1 + γ/k) - q_t * σ² * T

حيث:

  • δ_a و δ_b هما سعرا العرض والطلب
  • S_t هو السعر السوقي الحالي
  • γ هو معامل المخاطرة (كلما ارتفع، اتسع السبريد)
  • k هو معدل وصول الأوامر
  • q_t هو المخزون الحالي
  • σ هو التقلب
  • T هو الأفق الزمني

ميزات التداول على السلسلة

عند نقل الخوارزمية إلى السلسلة، تظهر تحديات إضافية:

  1. الكمون – المعاملات على البلوكتشين ليست فورية، وقد يتغير السعر قبل تنفيذ الأمر
  2. تكاليف الغاز – كل معاملة تتطلب رسوم شبكة
  3. خصائص AMM/PMM – آليات مجمعات السيولة تختلف عن البورصات التقليدية

لنرَ كيف نأخذ هذه العوامل في الاعتبار في خوارزميتنا.

الخطوة 1: إعداد البيئة وجمع البيانات

أولاً، نحتاج لإعداد بيئة للحصول على بيانات السوق. سنستخدم Binance API للحصول على الأسعار الحالية وعمق دفتر الأوامر.

std::tuple MarketMaker::get_binance_data(const std::string& pair) {
    // In real code, this would be a request to the Binance API
    // Returns: mid_price, bid, ask, bid_volume, ask_volume
    double mid_price = 2000.0;
    double bid = mid_price - 1.0;
    double ask = mid_price + 1.0;
    double bid_volume = 10.0;
    double ask_volume = 8.0;
    return {mid_price, bid, ask, bid_volume, ask_volume};
}

سنحتاج أيضاً لمقاييس على السلسلة مثل تكلفة الغاز وكمون الشبكة:

std::pair MarketMaker::get_onchain_metrics() {
    // In real code, this would be a request to an Ethereum node
    // Returns: gas_price (wei), latency (seconds)
    return {50e9, 12.0};
}

الخطوة 2: تنفيذ نموذج A-S الأساسي

الآن لننفذ حساب السبريد باستخدام نموذج A-S:

std::pair MarketMaker::calculate_spreads(double S_t, double sigma, double k, double q_t) {
    // Avellaneda-Stoikov formula
    double spread_term = (1.0 / gamma_) * log(1.0 + gamma_ / k);
    double inventory_term = q_t * sigma * sigma * T_;

    double delta_a = S_t + spread_term + inventory_term;  // Ask price
    double delta_b = S_t - spread_term - inventory_term;  // Bid price

    return {delta_a, delta_b};
}

لاحظ inventory_term. إذا كان لديك مخزون إيجابي (كثير من الأصل)، ينخفض سعر العرض، وينخفض سعر الطلب أكثر لتشجيع البيع وتقييد الشراء. والعكس للمخزون السلبي.

الخطوة 3: تكييف النموذج للتداول على السلسلة

نحتاج الآن لمراعاة خصائص البلوكتشين. لنبدأ بالكمون:

double MarketMaker::adjust_price_with_latency(double S_t, double sigma, double latency) {
    // Simulate random price change due to latency
    double latency_adjustment = utils::normal_dist(0.0, sigma * std::sqrt(latency));
    return S_t + latency_adjustment;
}

هنا نستخدم نموذج المشي العشوائي: كلما ارتفع التقلب وطال الكمون، زاد تغير السعر المحتمل قبل تنفيذ الأمر.

الآن لنراعي تكلفة الغاز:

double MarketMaker::calculate_gas_cost(double gas_price, double trade_size) {
    const double GAS_LIMIT_PER_ORDER = 100000;  // Approximate value per order
    return (gas_price * GAS_LIMIT_PER_ORDER * trade_size) / 1e18;  // Convert wei to ETH
}

أخيراً، لنكيّف السبريدات لخصائص مجمع PMM:

std::pair MarketMaker::adjust_spreads_for_pmm(double S_t, double delta_a, double delta_b, double pool_depth) {
    // Simplified PMM model: adjust spreads based on pool depth
    const double MIN_POOL_DEPTH = 10.0;
    double depth_factor = std::max(pool_depth, MIN_POOL_DEPTH) / MIN_POOL_DEPTH;

    // Reduce spreads with greater pool depth
    double spread_reduction = 1.0 / std::sqrt(depth_factor);
    double mid_price = (delta_a + delta_b) / 2;
    double new_delta_a = mid_price + (delta_a - mid_price) * spread_reduction;
    double new_delta_b = mid_price - (mid_price - delta_b) * spread_reduction;

    return {new_delta_a, new_delta_b};
}

الخطوة 4: إدارة المخزون

لتتبع المخزون وإدارته، لننشئ فئة بسيطة:

class InventoryManager {
public:
    InventoryManager() : inventory_(0.0) {}

    void update_inventory(double size, bool is_buy) {
        inventory_ += is_buy ? size : -size;
    }

    double get_inventory() const {
        return inventory_;
    }

private:
    double inventory_;
};

تصور إدارة المخزون والمخاطر تصور مخاطر المخزون: مراقبة أحجام المراكز لتجنب التعرض المفرط لتحركات السوق أحادية الاتجاه.

الخطوة 5: دمج كل شيء في خوارزمية واحدة

الآن لندمج جميع المكونات في خوارزمية صناعة سوق واحدة:

void MarketMaker::step(double S_t, double sigma, double k, double latency, double gas_cost, double trade_size) {
    // Get current inventory
    double current_inventory = inventory_.get_inventory();

    // Calculate spreads based on current market conditions and inventory
    auto [delta_a, delta_b] = calculate_spreads(S_t, sigma, k, current_inventory);
    auto [adjusted_delta_a, adjusted_delta_b] = adjust_spreads_for_onchain(S_t, delta_a, delta_b, latency, sigma, gas_cost, trade_size);

    // Generate independent market price
    double market_price = S_t + utils::normal_dist(0.0, sigma);

    // Determine if trades should occur based on market price and spreads
    bool is_buy = (market_price = adjusted_delta_a);

    // Execute trades and update inventory
    if (is_buy) {
        inventory_.update_inventory(trade_size, true);
        std::cout  reset();

    // Take action and get new state, reward, and done flag
    std::tuple, double, bool> step(const std::array& action);

private:
    // Get current environment state
    std::vector get_state() const;

    MarketMaker& mm_;
    double current_inventory_;
    double current_profit_;
    int current_step_;
    int max_steps_;

    // Current market parameters
    double mid_price_;
    double sigma_;
    double latency_;
    double pool_depth_;

    std::mt19937 rng_;
};

حالة بيئتنا هي متجه من السعر الحالي، والمخزون، والتقلب، وكمون الشبكة، وعمق المجمع. الإجراء هو متجه من السبريدات وأحجام الشراء/البيع.

الآن لننفذ دالة المكافأة:

double reward = profit_term - inventory_risk - gas_cost;

حيث:

  • profit_term الربح من الصفقات
  • inventory_risk عقوبة على المخزون الكبير (المخاطرة)
  • gas_cost الغاز المُنفق

أخيراً، لنُدرّب وكيل PPO:

void PPOTrainer::train(int episodes) {
    for (int ep = 0; ep  states;
        std::vector actions;
        std::vector rewards;

        while (true) {
            // Get action from policy
            auto action_probs = policy_net_->forward(torch::tensor(state));
            auto action = action_probs.multinomial(1);

            // Take a step in the environment
            auto [next_state, reward, done] = env_.step(action);

            // Save transition
            states.push_back(torch::tensor(state));
            actions.push_back(action);
            rewards.push_back(reward);

            if (done) break;
            state = next_state;
        }

        // Update PPO policy
        update_policy(states, actions, rewards);
    }
}

وكيل التعلم المعزز PPO لتحسين السبريد التعلم المعزز قيد العمل: وكيل PPO يعالج حالات السوق المعقدة لتحسين سبريدات الشراء/البيع ديناميكياً لأقصى مكافأة متوقعة.

الخطوة 7: الاختبار والتصور

لاختبار خوارزميتنا، لننشئ محاكاة بسيطة:

int main() {
    // Use T = 300 seconds as specified in the task
    MarketMaker mm(0.1, 300.0);

    // Simulate historical data for volatility
    std::vector prices = {2000.0};
    double S_t = 2000.0;
    double trade_size = 1.0;
    double initial_sigma = 0.05;  // 5% volatility

    for (int i = 0; i < 300; ++i) {
        std::cout << "Step " << i + 1 << ": ";

        // Get data (stubs)
        auto [mid_price, bid_ask] = mm.get_binance_data("USD+/wETH");
        auto [gas_cost, latency] = mm.get_onchain_metrics();

        // Add random price movement to simulate a real market
        S_t = mid_price + utils::normal_dist(0.0, mid_price * 0.01);

        // Calculate volatility
        double sigma = mm.calculate_volatility(prices, 5);
        if (sigma < 0.01) sigma = initial_sigma;

        // Order arrival rate (stub)
        double k = 5.0;

        mm.step(S_t, sigma, k, latency, gas_cost, trade_size);

        // Update price for next step
        S_t += utils::normal_dist(0.0, S_t * 0.02);
        prices.push_back(S_t);
    }

    return 0;
}

ما التالي؟

خوارزمية صناعة السوق جاهزة، لكن هناك طرق عديدة لتحسينها:

  1. الاتصال بواجهات API حقيقية: استبدال البذور بطلبات حقيقية إلى Binance API وعقدة Ethereum
  2. تحسين نموذج التقلب: استخدام GARCH أو نماذج متقدمة أخرى
  3. توسيع PPO: إضافة المزيد من المعاملات للحالة والإجراء
  4. تحسين الغاز: استراتيجيات لتقليل تكاليف الغاز
  5. استراتيجية متعددة الأصول: التوسع لعدة أزواج في وقت واحد

الخاتمة

لقد بنينا خوارزمية صناعة سوق تأخذ في الاعتبار ميزات التداول على السلسلة وتستخدم كلاً من نموذج A-S الكلاسيكي وأساليب RL الحديثة. هذا النهج يسمح بالتكيف مع ظروف السوق المتغيرة وتعظيم الربح مع التحكم في المخاطر.

بالطبع، في التداول الحقيقي هناك عوامل إضافية كثيرة يجب مراعاتها، لكن خوارزميتنا توفر أساساً متيناً لمزيد من التطوير. تذكر: في التداول الخوارزمي، ليست الرياضيات وحدها المهمة، بل أيضاً الاختبار الدقيق والمراقبة والتحسين المستمر.

أتمنى أن يكون هذا المقال قد ساعدك في فهم مبادئ صناعة السوق بشكل أفضل وألهمك لإنشاء خوارزمياتك الخاصة. حظاً سعيداً في التداول!

Citation

@software{soloviov2025marketmakingavellanedastoikov,
  author = {Soloviov, Eugen},
  title = {Building a Market Making Algorithm for Crypto Pairs Using the Avellaneda-Stoikov Model},
  year = {2025},
  url = {https://marketmaker.cc/en/blog/post/market-making-avellaneda-stoikov},
  version = {0.1.0},
  description = {A step-by-step guide to building a market making algorithm for USD+/wETH and USD+/cbbtc pairs using the Avellaneda-Stoikov model and PPO. Onchain trading features, inventory management, RL training.}
}
blog.disclaimer

MarketMaker.cc Team

البحوث والاستراتيجيات الكمية

ناقش في تلغرام
Newsletter

ابقَ متقدماً على السوق

اشترك في نشرتنا الإخبارية للحصول على رؤى حصرية حول تداول الذكاء الاصطناعي وتحليلات السوق وتحديثات المنصة.

نحترم خصوصيتك. يمكنك إلغاء الاشتراك في أي وقت.