← Kembali ke artikel
May 17, 2025
5 menit baca

Membangun Algoritma Market Making untuk Pasangan Kripto Menggunakan Model Avellaneda-Stoikov

Membangun Algoritma Market Making untuk Pasangan Kripto Menggunakan Model Avellaneda-Stoikov
#market making
#cryptocurrency
#Avellaneda-Stoikov
#perdagangan algoritmik
#pembelajaran penguatan
#PPO
#DeFi

Halo, teman-teman! Hari ini saya akan menunjukkan cara membangun algoritma market making untuk pasangan kripto USD+/wETH dan USD+/cbbtc. Kita akan menggunakan model Avellaneda-Stoikov (A-S) dan meningkatkannya dengan algoritma Reinforcement Learning (PPO) untuk optimasi spread dinamis. Terdengar rumit? Jangan khawatir, saya akan menguraikan semuanya menjadi langkah-langkah yang jelas sehingga bahkan pengembang pemula pun bisa mengikutinya.

Visualisasi Market Making Memvisualisasikan esensi market making: terus menyeimbangkan order beli dan jual di sekitar harga wajar untuk mensintesis likuiditas pasar yang optimal.

Apa itu Market Making dan Mengapa Kita Membutuhkannya?

Market making adalah strategi di mana seorang trader secara bersamaan menempatkan order beli dan jual untuk sebuah aset, menghasilkan keuntungan dari spread (selisih antara harga). Dalam ruang DeFi, market maker memainkan peran kunci dengan menyediakan likuiditas dan mengurangi slippage bagi peserta pasar lainnya.

Bayangkan Anda adalah seorang pedagang di pasar, selalu siap membeli produk sedikit di bawah harga pasar dan menjualnya sedikit di atas. Keuntungan Anda adalah selisih antara harga beli dan harga jual. Namun ada kendalanya: jika harga tiba-tiba bergerak ke satu arah, Anda mungkin mengumpulkan terlalu banyak inventaris atau sebaliknya, tidak memiliki apa pun untuk dijual.

Model Avellaneda-Stoikov: Matematika dalam Layanan Trading

Model A-S adalah pendekatan matematis untuk menentukan harga optimal dalam market making. Keunggulan utamanya adalah mempertimbangkan tidak hanya harga pasar saat ini, tetapi juga ukuran posisi Anda (inventaris), volatilitas pasar, dan selera risiko.

Rumus 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 pasar saat ini
  • γ adalah parameter risiko (semakin tinggi nilainya, semakin lebar spread)
  • k adalah tingkat kedatangan order
  • q_t adalah inventaris saat ini
  • σ adalah volatilitas
  • T adalah cakrawala waktu

Fitur Perdagangan Onchain

Ketika kita memindahkan algoritma ke onchain, tantangan tambahan muncul:

  1. Latensi – transaksi di blockchain tidak instan, dan harga mungkin berubah sebelum order dieksekusi
  2. Biaya gas – setiap transaksi memerlukan biaya jaringan
  3. Spesifisitas AMM/PMM – mekanisme pool likuiditas berbeda dari bursa tradisional

Mari kita lihat bagaimana memperhitungkan faktor-faktor ini dalam algoritma kita.

Langkah 1: Siapkan Lingkungan dan Kumpulkan Data

Pertama, kita perlu menyiapkan lingkungan untuk mendapatkan data pasar. Kita akan menggunakan Binance API untuk mendapatkan harga saat ini dan kedalaman 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};
}

Kita juga memerlukan metrik onchain seperti biaya gas dan latensi jaringan:

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: Implementasi Model A-S Dasar

Sekarang mari implementasikan perhitungan 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 memiliki inventaris positif (banyak aset), harga ask menurun, dan harga bid juga menurun lebih jauh untuk mendorong penjualan dan membatasi pembelian. Dan sebaliknya untuk inventaris negatif.

Langkah 3: Adaptasi Model untuk Perdagangan Onchain

Sekarang kita perlu memperhitungkan spesifisitas blockchain. Mari mulai 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 random walk: semakin tinggi volatilitas dan semakin lama latensi, semakin banyak harga dapat berubah sebelum order dieksekusi.

Sekarang mari perhitungkan biaya 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
}

Akhirnya, mari adaptasikan spread untuk spesifisitas 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};
}

Langkah 4: Manajemen Inventaris

Untuk melacak dan mengelola inventaris, mari buat kelas sederhana:

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 manajemen inventaris dan risiko Visualisasi Risiko Inventaris: Memantau ukuran posisi untuk menghindari eksposur berlebihan (long atau short) terhadap pergerakan pasar searah.

Langkah 5: Gabungkan Semuanya dalam Satu Algoritma

Sekarang mari gabungkan semua komponen menjadi satu algoritma 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_;
};

Status lingkungan kita adalah vektor dari harga saat ini, inventaris, volatilitas, latensi jaringan, dan kedalaman pool. Tindakan adalah vektor spread dan ukuran beli/jual.

Sekarang mari implementasikan fungsi reward:

double reward = profit_term - inventory_risk - gas_cost;

Di mana:

  • profit_term adalah keuntungan dari perdagangan
  • inventory_risk adalah penalti untuk inventaris besar (risiko)
  • gas_cost adalah gas yang dihabiskan

Akhirnya, mari latih agen 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);
    }
}

Agen Reinforcement Learning PPO untuk optimasi spread Reinforcement Learning dalam aksi: Agen PPO memproses keadaan pasar yang kompleks untuk mengoptimalkan spread beli/jual secara dinamis demi reward yang diharapkan maksimal.

Langkah 7: Pengujian dan Visualisasi

Untuk menguji algoritma kita, mari buat simulasi sederhana:

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 Selanjutnya?

Algoritma market making kita sudah siap, tetapi ada banyak cara untuk meningkatkannya:

  1. Hubungkan ke API nyata: ganti stub dengan permintaan nyata ke Binance API dan node Ethereum
  2. Tingkatkan model volatilitas: gunakan GARCH atau model lanjutan lainnya
  3. Perluas PPO: tambahkan lebih banyak parameter ke state dan action
  4. Optimalkan gas: strategi untuk meminimalkan biaya gas
  5. Strategi multi-aset: perluas ke beberapa pasangan sekaligus

Kesimpulan

Kita telah membangun algoritma market making yang memperhitungkan fitur perdagangan onchain dan menggunakan model A-S klasik serta metode RL modern. Pendekatan ini memungkinkan Anda beradaptasi dengan kondisi pasar yang berubah dan memaksimalkan keuntungan sambil mengendalikan risiko.

Tentu saja, dalam perdagangan nyata ada banyak faktor tambahan yang perlu dipertimbangkan, tetapi algoritma kita memberikan fondasi yang kuat untuk pengembangan lebih lanjut. Ingat: dalam perdagangan algoritmik, bukan hanya matematika yang penting, tetapi juga pengujian menyeluruh, pemantauan, dan optimasi yang berkelanjutan.

Saya berharap artikel ini membantu Anda lebih memahami prinsip-prinsip market making dan menginspirasi Anda untuk membuat algoritma Anda sendiri. Selamat berdagang!

Kutipan

@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/id/blog/post/market-making-avellaneda-stoikov},
  version = {0.1.0},
  description = {Panduan langkah demi langkah untuk membangun algoritma market making untuk pasangan USD+/wETH dan USD+/cbbtc menggunakan model Avellaneda-Stoikov dan PPO. Fitur perdagangan onchain, manajemen inventaris, pelatihan RL.}
}
Penafian: Informasi yang disediakan dalam artikel ini hanya untuk tujuan edukasi dan informasi serta tidak merupakan nasihat keuangan, investasi, atau trading. Trading mata uang kripto mengandung risiko kerugian yang signifikan.

Penulis

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

Selangkah Lebih Maju dari Pasar

Berlangganan newsletter kami untuk wawasan AI trading eksklusif, analisis pasar, dan pembaruan platform.

Kami menghormati privasi Anda. Berhenti berlangganan kapan saja.