← Kembali ke artikel
May 17, 2025
Bacaan 5 minit

Membina Algoritma Pembuatan Pasaran untuk Pasangan Kripto Menggunakan Model Avellaneda-Stoikov

Membina Algoritma Pembuatan Pasaran untuk Pasangan Kripto Menggunakan Model Avellaneda-Stoikov
#pembuatan pasaran
#mata wang kripto
#Avellaneda-Stoikov
#perdagangan algoritma
#pembelajaran pengukuhan
#PPO
#DeFi

Helo, rakan-rakan! Hari ini saya akan menunjukkan cara membina algoritma pembuatan pasaran untuk pasangan kripto USD+/wETH dan USD+/cbbtc. Kita akan menggunakan model Avellaneda-Stoikov (A-S) dan memperkasaikannya dengan algoritma Pembelajaran Pengukuhan (PPO) untuk pengoptimuman spread dinamik. Kedengaran rumit? Jangan risau, saya akan memecahkan segalanya kepada langkah-langkah yang jelas supaya pembangun pemula pun boleh mengikutinya.

Visualisasi Pembuatan Pasaran Memvisualisasikan intipati pembuatan pasaran: mengimbangi pesanan beli dan jual secara berterusan di sekitar harga yang adil untuk mensintesis kecairan pasaran yang optimum.

Apa Itu Pembuatan Pasaran dan Mengapa Kita Memerlukannya?

Pembuatan pasaran adalah strategi di mana pedagang secara serentak meletakkan pesanan beli dan jual untuk sesuatu aset, memperoleh keuntungan daripada spread (perbezaan antara harga). Dalam ruang DeFi, pembuat pasaran memainkan peranan utama dengan menyediakan kecairan dan mengurangkan slippage bagi peserta pasaran lain.

Bayangkan anda seorang penjual di pasar, sentiasa bersedia untuk membeli produk sedikit di bawah harga pasaran dan menjualnya sedikit di atas. Keuntungan anda adalah perbezaan antara harga beli dan harga jual anda. Tetapi ada cabarannya: jika harga tiba-tiba bergerak ke satu arah, anda mungkin terkumpul terlalu banyak inventori atau, sebaliknya, tidak ada barang untuk dijual.

Model Avellaneda-Stoikov: Matematik dalam Perkhidmatan Perdagangan

Model A-S adalah pendekatan matematik untuk menentukan harga optimum bagi pembuatan pasaran. Kelebihannya yang utama ialah ia mengambil kira bukan sahaja harga pasaran semasa, tetapi juga saiz kedudukan anda (inventori), volatiliti pasaran, dan selera risiko.

Formula utama model:

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

di mana:

  • δ_a dan δ_b adalah harga ask dan bid
  • S_t adalah harga pasaran semasa
  • γ adalah parameter risiko (semakin tinggi, semakin lebar spread)
  • k adalah kadar ketibaan pesanan
  • q_t adalah inventori semasa
  • σ adalah volatiliti
  • T adalah ufuk masa

Ciri-ciri Perdagangan Onchain

Apabila kita memindahkan algoritma ke onchain, cabaran tambahan timbul:

  1. Latensi – transaksi di blockchain tidak serta-merta, dan harga mungkin berubah sebelum pesanan dilaksanakan
  2. Kos gas – setiap transaksi memerlukan yuran rangkaian
  3. Khususan AMM/PMM – mekanik kumpulan kecairan berbeza daripada bursa tradisional

Mari kita lihat bagaimana untuk mengambil kira faktor-faktor ini dalam algoritma kita.

Langkah 1: Sediakan Persekitaran dan Kumpul Data

Pertama, kita perlu menyediakan persekitaran untuk mendapatkan data pasaran. Kita akan menggunakan API Binance untuk mendapatkan harga semasa dan kedalaman buku pesanan.

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

Kita juga memerlukan metrik onchain seperti kos gas dan latensi rangkaian:

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

Langkah 2: Laksanakan Model A-S Asas

Sekarang mari kita laksanakan pengiraan spread menggunakan model 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};
}

Perhatikan inventory_term. Jika anda mempunyai inventori positif (banyak aset), harga ask menurun, dan harga bid menurun lagi untuk menggalakkan penjualan dan mengehadkan pembelian. Dan sebaliknya untuk inventori negatif.

Langkah 3: Sesuaikan Model untuk Perdagangan Onchain

Sekarang kita perlu mengambil kira khususan blockchain. Mari mulakan dengan latensi:

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

Di sini kita menggunakan model raw rawak: semakin tinggi volatiliti dan semakin lama latensi, semakin besar perubahan harga sebelum pesanan dilaksanakan.

Sekarang mari kita ambil kira kos 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
}

Akhir sekali, mari kita sesuaikan spread untuk khususan kumpulan 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};
}

Langkah 4: Pengurusan Inventori

Untuk menjejaki dan mengurus inventori, mari kita cipta kelas yang mudah:

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

Visualisasi pengurusan inventori dan risiko Visualisasi Risiko Inventori: Memantau saiz kedudukan untuk mengelakkan pendedahan berlebihan (panjang atau pendek) kepada pergerakan pasaran sehala.

Langkah 5: Gabungkan Semua dalam Satu Algoritma

Sekarang mari kita gabungkan semua komponen dalam satu algoritma pembuatan pasaran:

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

Keadaan persekitaran kita adalah vektor harga semasa, inventori, volatiliti, latensi rangkaian, dan kedalaman kumpulan. Tindakan adalah vektor spread dan saiz beli/jual.

Sekarang mari kita laksanakan fungsi ganjaran:

double reward = profit_term - inventory_risk - gas_cost;

Di mana:

  • profit_term adalah keuntungan daripada perdagangan
  • inventory_risk adalah penalti untuk inventori yang besar (risiko)
  • gas_cost adalah gas yang digunakan

Akhir sekali, mari kita latih ejen 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);
    }
}

Ejen Pembelajaran Pengukuhan PPO untuk pengoptimuman spread Pembelajaran Pengukuhan dalam tindakan: Ejen PPO memproses keadaan pasaran yang kompleks untuk mengoptimumkan spread beli/jual secara dinamik bagi ganjaran yang dijangkakan maksimum.

Langkah 7: Pengujian dan Visualisasi

Untuk menguji algoritma kita, mari kita cipta simulasi yang mudah:

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

Apa Seterusnya?

Algoritma pembuatan pasaran kita sudah siap, tetapi terdapat banyak cara untuk memperbaikinya:

  1. Sambung ke API sebenar: gantikan stub dengan permintaan sebenar ke API Binance dan nod Ethereum
  2. Tingkatkan model volatiliti: gunakan GARCH atau model canggih lain
  3. Perluaskan PPO: tambahkan lebih banyak parameter kepada keadaan dan tindakan
  4. Optimalkan gas: strategi untuk meminimumkan kos gas
  5. Strategi berbilang aset: kembangkan kepada beberapa pasangan sekaligus

Kesimpulan

Kita telah membina algoritma pembuatan pasaran yang mengambil kira ciri-ciri perdagangan onchain dan menggunakan kedua-dua model A-S klasik dan kaedah RL moden. Pendekatan ini membolehkan anda menyesuaikan diri dengan keadaan pasaran yang berubah dan memaksimumkan keuntungan sambil mengawal risiko.

Sudah tentu, dalam perdagangan sebenar terdapat banyak faktor tambahan yang perlu dipertimbangkan, tetapi algoritma kita menyediakan asas yang kukuh untuk pembangunan selanjutnya. Ingat: dalam perdagangan algoritma, bukan sahaja matematik yang penting, tetapi juga pengujian menyeluruh, pemantauan, dan pengoptimuman berterusan.

Saya harap artikel ini membantu anda memahami prinsip-prinsip pembuatan pasaran dengan lebih baik dan memberi inspirasi untuk mencipta algoritma anda sendiri. Semoga berjaya dalam perdagangan!

Petikan

@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/ms/blog/post/market-making-avellaneda-stoikov},
  version = {0.1.0},
  description = {Panduan langkah demi langkah untuk membina algoritma pembuatan pasaran bagi pasangan USD+/wETH dan USD+/cbbtc menggunakan model Avellaneda-Stoikov dan PPO. Ciri-ciri perdagangan onchain, pengurusan inventori, latihan RL.}
}
Penafian: Maklumat yang disediakan dalam artikel ini adalah untuk tujuan pendidikan dan maklumat sahaja dan bukan merupakan nasihat kewangan, pelaburan, atau dagangan. Dagangan mata wang kripto melibatkan risiko kerugian yang ketara.

Pengarang

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

Kekal Mendahului Pasaran

Langgan surat berita kami untuk pandangan dagangan AI eksklusif, analisis pasaran, dan kemas kini platform.

Kami menghormati privasi anda. Berhenti melanggan pada bila-bila masa.