← กลับไปยังบทความ
May 17, 2025
อ่าน 5 นาที

การสร้างอัลกอริทึม Market Making สำหรับคู่เหรียญคริปโตด้วยโมเดล Avellaneda-Stoikov

การสร้างอัลกอริทึม Market Making สำหรับคู่เหรียญคริปโตด้วยโมเดล Avellaneda-Stoikov
#market making
#คริปโตเคอร์เรนซี
#Avellaneda-Stoikov
#algorithmic trading
#reinforcement learning
#PPO
#DeFi

สวัสดีเพื่อนๆ ทุกคน! วันนี้ผมจะแสดงวิธีการสร้างอัลกอริทึม market making สำหรับคู่เหรียญ USD+/wETH และ USD+/cbbtc เราจะใช้โมเดล Avellaneda-Stoikov (A-S) และเพิ่มประสิทธิภาพด้วยอัลกอริทึม Reinforcement Learning (PPO) สำหรับการปรับ spread แบบไดนามิก ฟังดูซับซ้อนไหม? ไม่ต้องกังวล ผมจะอธิบายทุกอย่างเป็นขั้นตอนที่ชัดเจนเพื่อให้แม้แต่นักพัฒนามือใหม่ก็สามารถทำตามได้

การแสดงภาพ Market Making การแสดงภาพแก่นแท้ของ market making: การจัดสมดุลคำสั่งซื้อและขายอย่างต่อเนื่องรอบราคาที่เป็นธรรมเพื่อสังเคราะห์สภาพคล่องของตลาดที่ดีที่สุด

Market Making คืออะไร และทำไมเราจึงต้องการมัน?

Market making เป็นกลยุทธ์ที่เทรดเดอร์วางคำสั่งซื้อและขายสินทรัพย์พร้อมกัน โดยทำกำไรจาก spread (ส่วนต่างระหว่างราคา) ในระบบนิเวศ DeFi, market makers มีบทบาทสำคัญในการจัดหาสภาพคล่องและลด slippage สำหรับผู้ร่วมตลาดคนอื่น

ลองนึกภาพว่าคุณเป็นพ่อค้าในตลาด พร้อมซื้อสินค้าในราคาต่ำกว่าราคาตลาดเล็กน้อยและขายในราคาสูงกว่าเล็กน้อย กำไรของคุณคือส่วนต่างระหว่างราคาซื้อและราคาขาย แต่มีข้อระวัง: หากราคาเคลื่อนที่ไปในทิศทางเดียวอย่างฉับพลัน คุณอาจสะสม inventory มากเกินไป หรือในทางกลับกัน ไม่มีสินค้าเหลือขาย

โมเดล Avellaneda-Stoikov: คณิตศาสตร์ในการรับใช้การเทรด

โมเดล A-S เป็นวิธีการทางคณิตศาสตร์สำหรับการกำหนดราคาที่เหมาะสมสำหรับ market making ข้อดีหลักคือมันไม่เพียงแค่คำนึงถึงราคาตลาดปัจจุบัน แต่ยังรวมถึงขนาดตำแหน่ง (inventory), ความผันผวนของตลาด และความเสี่ยงที่ยอมรับได้

สูตรหลักของโมเดล:

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

โดยที่:

  • δ_a และ δ_b คือราคา ask และ bid
  • S_t คือราคาตลาดปัจจุบัน
  • γ คือพารามิเตอร์ความเสี่ยง (ยิ่งสูง spread ยิ่งกว้าง)
  • k คืออัตราการมาถึงของคำสั่ง
  • q_t คือ inventory ปัจจุบัน
  • σ คือความผันผวน
  • T คือขอบเวลา

ฟีเจอร์การเทรด Onchain

เมื่อเราย้ายอัลกอริทึมไป onchain จะเกิดความท้าทายเพิ่มเติม:

  1. Latency – ธุรกรรมบน blockchain ไม่ได้เกิดขึ้นทันที และราคาอาจเปลี่ยนแปลงก่อนที่คำสั่งจะถูกดำเนินการ
  2. Gas costs – ทุกธุรกรรมต้องใช้ค่าธรรมเนียมเครือข่าย
  3. AMM/PMM specifics – กลไกของ liquidity pool แตกต่างจากตลาดแบบดั้งเดิม

มาดูวิธีการคำนึงถึงปัจจัยเหล่านี้ในอัลกอริทึมของเรา

ขั้นตอนที่ 1: ตั้งค่าสภาพแวดล้อมและเก็บข้อมูล

ก่อนอื่น เราต้องตั้งค่าสภาพแวดล้อมเพื่อรับข้อมูลตลาด เราจะใช้ Binance API เพื่อรับราคาปัจจุบันและความลึกของ order book

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};
}

เราจะต้องใช้ onchain metrics เช่น gas cost และ network latency ด้วย:

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 พื้นฐาน

ตอนนี้มาใช้งานการคำนวณ spread โดยใช้โมเดล 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 หากคุณมี inventory บวก (มีสินทรัพย์มาก) ราคา ask จะลดลง และราคา bid ลดลงมากกว่าเพื่อกระตุ้นการขายและจำกัดการซื้อ และในทางกลับกันสำหรับ inventory ติดลบ

ขั้นตอนที่ 3: ปรับโมเดลสำหรับการเทรด Onchain

ตอนนี้เราต้องคำนึงถึงข้อจำเพาะของ blockchain มาเริ่มด้วย latency:

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;
}

ที่นี่เราใช้โมเดล random walk: ยิ่งความผันผวนสูงและ latency นานขึ้น ราคายิ่งเปลี่ยนแปลงได้มากก่อนที่คำสั่งจะถูกดำเนินการ

ตอนนี้มาคำนึงถึง gas cost:

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
}

สุดท้าย มาปรับ spread สำหรับข้อจำเพาะของ PMM pool:

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: การจัดการ Inventory

เพื่อติดตามและจัดการ inventory มาสร้าง class ง่ายๆ:

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_;
};

การแสดงภาพการจัดการ inventory และความเสี่ยง การแสดงภาพ Inventory Risk: การติดตามขนาดตำแหน่งเพื่อหลีกเลี่ยงการเปิดรับความเสี่ยงมากเกินไป (long หรือ short) ต่อการเคลื่อนไหวของตลาดในทิศทางเดียว

ขั้นตอนที่ 5: รวมทุกอย่างเป็นอัลกอริทึมเดียว

ตอนนี้มารวมองค์ประกอบทั้งหมดเป็นอัลกอริทึม market making เดียว:

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_;
};

สถานะสภาพแวดล้อมของเราคือ vector ของราคาปัจจุบัน, inventory, ความผันผวน, network latency และ pool depth การกระทำคือ vector ของ spread และขนาดซื้อ/ขาย

ตอนนี้มาใช้งาน reward function:

double reward = profit_term - inventory_risk - gas_cost;

โดยที่:

  • profit_term คือกำไรจากการเทรด
  • inventory_risk คือบทลงโทษสำหรับ inventory ขนาดใหญ่ (ความเสี่ยง)
  • gas_cost คือ gas ที่ใช้ไป

สุดท้าย มาฝึก PPO agent:

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 Reinforcement Learning agent สำหรับการปรับ spread Reinforcement Learning ในการทำงาน: PPO agent ประมวลผลสถานะตลาดที่ซับซ้อนเพื่อปรับ spread ซื้อ/ขายแบบไดนามิกเพื่อรางวัลที่คาดหวังสูงสุด

ขั้นตอนที่ 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;
}

ขั้นตอนต่อไปคืออะไร?

อัลกอริทึม market making ของเราพร้อมแล้ว แต่มีหลายวิธีในการปรับปรุง:

  1. เชื่อมต่อกับ API จริง: แทนที่ stub ด้วยคำขอจริงไปยัง Binance API และ Ethereum node
  2. ปรับปรุงโมเดลความผันผวน: ใช้ GARCH หรือโมเดลขั้นสูงอื่นๆ
  3. ขยาย PPO: เพิ่มพารามิเตอร์มากขึ้นสำหรับ state และ action
  4. ปรับให้ gas ดีที่สุด: กลยุทธ์เพื่อลด gas costs ให้เหลือน้อยที่สุด
  5. กลยุทธ์หลายสินทรัพย์: ขยายไปยังหลายคู่พร้อมกัน

บทสรุป

เราได้สร้างอัลกอริทึม market making ที่คำนึงถึงฟีเจอร์การเทรด onchain และใช้ทั้งโมเดล A-S แบบคลาสสิกและวิธีการ RL สมัยใหม่ แนวทางนี้ช่วยให้คุณปรับตัวกับสภาวะตลาดที่เปลี่ยนแปลงและเพิ่มกำไรสูงสุดในขณะที่ควบคุมความเสี่ยง

แน่นอนในการเทรดจริงมีปัจจัยเพิ่มเติมอีกมากมายที่ต้องคำนึงถึง แต่อัลกอริทึมของเราให้รากฐานที่มั่นคงสำหรับการพัฒนาต่อไป จำไว้ว่า: ในการเทรดแบบอัลกอริทึม ไม่ใช่แค่คณิตศาสตร์เท่านั้นที่สำคัญ แต่ยังรวมถึงการทดสอบอย่างละเอียด, การติดตาม และการปรับให้ดีที่สุดอย่างต่อเนื่อง

ผมหวังว่าบทความนี้จะช่วยให้คุณเข้าใจหลักการของ market making ได้ดีขึ้น และสร้างแรงบันดาลใจให้คุณสร้างอัลกอริทึมของตัวเอง ขอให้โชคดีในการเทรด!

การอ้างอิง

@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/th/blog/post/market-making-avellaneda-stoikov},
  version = {0.1.0},
  description = {คู่มือทีละขั้นตอนสำหรับการสร้างอัลกอริทึม market making สำหรับคู่ USD+/wETH และ USD+/cbbtc โดยใช้โมเดล Avellaneda-Stoikov และ PPO รวมถึงฟีเจอร์การเทรด onchain, การจัดการ inventory และการฝึก RL}
}
ข้อจำกัดความรับผิดชอบ: ข้อมูลที่ให้ไว้ในบทความนี้มีไว้เพื่อการศึกษาและให้ข้อมูลเท่านั้น และไม่ถือเป็นคำแนะนำทางการเงิน การลงทุน หรือการเทรด การเทรดสกุลเงินดิจิทัลมีความเสี่ยงสูงที่จะขาดทุน

ผู้เขียน

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

ก้าวนำหน้าตลาด

สมัครรับจดหมายข่าวของเราเพื่อรับข้อมูลเชิงลึกการเทรดด้วย AI เฉพาะ การวิเคราะห์ตลาด และการอัปเดตแพลตฟอร์ม

เราเคารพความเป็นส่วนตัวของคุณ ยกเลิกการสมัครได้ทุกเมื่อ