← Quay lại danh sách bài viết
May 17, 2025
5 phút đọc

Xây Dựng Thuật Toán Tạo Lập Thị Trường Cho Các Cặp Tiền Điện Tử Sử Dụng Mô Hình Avellaneda-Stoikov

Xây Dựng Thuật Toán Tạo Lập Thị Trường Cho Các Cặp Tiền Điện Tử Sử Dụng Mô Hình Avellaneda-Stoikov
#tạo lập thị trường
#tiền điện tử
#Avellaneda-Stoikov
#giao dịch thuật toán
#học tăng cường
#PPO
#DeFi

Xin chào các bạn! Hôm nay tôi sẽ hướng dẫn cách xây dựng thuật toán tạo lập thị trường cho các cặp tiền điện tử USD+/wETH và USD+/cbbtc. Chúng ta sẽ sử dụng mô hình Avellaneda-Stoikov (A-S) và nâng cấp nó với thuật toán Học Tăng Cường (PPO) để tối ưu hóa spread động. Nghe có vẻ phức tạp? Đừng lo, tôi sẽ phân tích mọi thứ thành các bước rõ ràng để ngay cả một lập trình viên mới bắt đầu cũng có thể theo dõi.

Trực Quan Hóa Tạo Lập Thị Trường Trực quan hóa bản chất của tạo lập thị trường: liên tục cân bằng lệnh mua và bán xung quanh một mức giá hợp lý để tổng hợp thanh khoản thị trường tối ưu.

Tạo Lập Thị Trường Là Gì Và Tại Sao Chúng Ta Cần Nó?

Tạo lập thị trường là một chiến lược trong đó nhà giao dịch đồng thời đặt lệnh mua và bán cho một tài sản, kiếm lợi nhuận từ spread (chênh lệch giữa các mức giá). Trong không gian DeFi, các nhà tạo lập thị trường đóng vai trò quan trọng bằng cách cung cấp thanh khoản và giảm slippage cho các bên tham gia thị trường khác.

Hãy tưởng tượng bạn là một người bán hàng tại chợ, luôn sẵn sàng mua hàng hóa với giá thấp hơn thị trường một chút và bán với giá cao hơn một chút. Lợi nhuận của bạn là chênh lệch giữa giá mua và giá bán. Nhưng có một điểm mấu chốt: nếu giá đột ngột di chuyển theo một chiều, bạn có thể tích lũy quá nhiều tồn kho hoặc ngược lại, không còn gì để bán.

Mô Hình Avellaneda-Stoikov: Toán Học Phục Vụ Giao Dịch

Mô hình A-S là một phương pháp toán học để xác định giá tối ưu cho việc tạo lập thị trường. Ưu điểm chính của nó là xem xét không chỉ giá thị trường hiện tại mà còn cả quy mô vị thế của bạn (tồn kho), biến động thị trường và khẩu vị rủi ro.

Các công thức chính của mô hình:

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

trong đó:

  • δ_aδ_b là giá ask và bid
  • S_t là giá thị trường hiện tại
  • γ là tham số rủi ro (càng cao, spread càng rộng)
  • k là tốc độ đến của lệnh
  • q_t là tồn kho hiện tại
  • σ là độ biến động
  • T là khung thời gian

Các Tính Năng Giao Dịch Onchain

Khi chúng ta đưa thuật toán lên onchain, các thách thức bổ sung xuất hiện:

  1. Độ trễ – các giao dịch trên blockchain không tức thời, và giá có thể thay đổi trước khi lệnh được thực thi
  2. Chi phí gas – mỗi giao dịch đòi hỏi phí mạng
  3. Đặc thù AMM/PMM – cơ chế pool thanh khoản khác với các sàn giao dịch truyền thống

Hãy cùng xem cách tính đến những yếu tố này trong thuật toán của chúng ta.

Bước 1: Thiết Lập Môi Trường Và Thu Thập Dữ Liệu

Đầu tiên, chúng ta cần thiết lập môi trường để lấy dữ liệu thị trường. Chúng ta sẽ sử dụng Binance API để lấy giá hiện tại và độ sâu 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};
}

Chúng ta cũng sẽ cần các chỉ số onchain như chi phí gas và độ trễ mạng:

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

Bước 2: Triển Khai Mô Hình A-S Cơ Bản

Bây giờ hãy triển khai tính toán spread sử dụng mô hình 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};
}

Lưu ý inventory_term. Nếu bạn có tồn kho dương (nhiều tài sản), giá ask giảm và giá bid giảm nhiều hơn để khuyến khích bán và hạn chế mua. Và ngược lại đối với tồn kho âm.

Bước 3: Điều Chỉnh Mô Hình Cho Giao Dịch Onchain

Bây giờ chúng ta cần tính đến các đặc thù blockchain. Hãy bắt đầu với độ trễ:

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

Ở đây chúng ta sử dụng mô hình random walk: độ biến động càng cao và độ trễ càng dài, giá càng có thể thay đổi nhiều trước khi lệnh được thực thi.

Bây giờ hãy tính đến chi phí gas:

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
}

Cuối cùng, hãy điều chỉnh spread cho các đặc thù pool 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};
}

Bước 4: Quản Lý Tồn Kho

Để theo dõi và quản lý tồn kho, hãy tạo một lớp đơn giản:

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

Trực quan hóa quản lý tồn kho và rủi ro Trực quan hóa Rủi ro Tồn kho: Theo dõi quy mô vị thế để tránh tiếp xúc quá mức (dài hoặc ngắn) với các biến động thị trường một chiều.

Bước 5: Kết Hợp Tất Cả Thành Một Thuật Toán Duy Nhất

Bây giờ hãy kết hợp tất cả các thành phần thành một thuật toán tạo lập thị trường duy nhất:

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

Trạng thái môi trường của chúng ta là một vector gồm giá hiện tại, tồn kho, độ biến động, độ trễ mạng và độ sâu pool. Hành động là một vector gồm spread và kích thước mua/bán.

Bây giờ hãy triển khai hàm phần thưởng:

double reward = profit_term - inventory_risk - gas_cost;

Trong đó:

  • profit_term là lợi nhuận từ các giao dịch
  • inventory_risk là hình phạt cho tồn kho lớn (rủi ro)
  • gas_cost là gas đã tiêu thụ

Cuối cùng, hãy huấn luyện agent 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);
    }
}

Agent Học Tăng Cường PPO để tối ưu hóa spread Học Tăng Cường trong hành động: Agent PPO xử lý các trạng thái thị trường phức tạp để tối ưu hóa động các spread mua/bán nhằm đạt phần thưởng kỳ vọng tối đa.

Bước 7: Kiểm Thử Và Trực Quan Hóa

Để kiểm thử thuật toán của chúng ta, hãy tạo một mô phỏng đơn giản:

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

Tiếp Theo Là Gì?

Thuật toán tạo lập thị trường của chúng ta đã sẵn sàng, nhưng có nhiều cách để cải thiện nó:

  1. Kết nối với API thực: thay thế stub bằng các yêu cầu thực đến Binance API và Ethereum node
  2. Cải thiện mô hình biến động: sử dụng GARCH hoặc các mô hình nâng cao khác
  3. Mở rộng PPO: thêm nhiều tham số hơn vào trạng thái và hành động
  4. Tối ưu hóa gas: các chiến lược để giảm thiểu chi phí gas
  5. Chiến lược đa tài sản: mở rộng sang nhiều cặp cùng một lúc

Kết Luận

Chúng ta đã xây dựng một thuật toán tạo lập thị trường tính đến các tính năng giao dịch onchain và sử dụng cả mô hình A-S cổ điển lẫn các phương pháp RL hiện đại. Phương pháp này cho phép bạn thích nghi với các điều kiện thị trường thay đổi và tối đa hóa lợi nhuận trong khi kiểm soát rủi ro.

Tất nhiên, trong giao dịch thực tế có nhiều yếu tố bổ sung cần xem xét, nhưng thuật toán của chúng ta cung cấp một nền tảng vững chắc để phát triển thêm. Hãy nhớ: trong giao dịch thuật toán, không chỉ toán học mà còn cả việc kiểm thử kỹ lưỡng, giám sát và tối ưu hóa liên tục đều quan trọng.

Tôi hy vọng bài viết này giúp bạn hiểu rõ hơn các nguyên tắc tạo lập thị trường và truyền cảm hứng để bạn tạo ra các thuật toán của riêng mình. Chúc bạn giao dịch thành công!

Trích Dẫn

@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/vi/blog/post/market-making-avellaneda-stoikov},
  version = {0.1.0},
  description = {Hướng dẫn từng bước xây dựng thuật toán tạo lập thị trường cho các cặp USD+/wETH và USD+/cbbtc sử dụng mô hình Avellaneda-Stoikov và PPO. Các tính năng giao dịch onchain, quản lý tồn kho, huấn luyện RL.}
}
Tuyên bố miễn trừ trách nhiệm: Thông tin được cung cấp trong bài viết này chỉ nhằm mục đích giáo dục và thông tin, không cấu thành lời khuyên về tài chính, đầu tư hoặc giao dịch. Giao dịch tiền mã hóa tiềm ẩn rủi ro thua lỗ đáng kể.

Tác Giả

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

Đi Trước Thị Trường

Đăng ký nhận bản tin của chúng tôi để có những thông tin chuyên sâu độc quyền về AI trading, phân tích thị trường và các cập nhật nền tảng.

Chúng tôi tôn trọng quyền riêng tư của bạn. Hủy đăng ký bất kỳ lúc nào.