Membangun Algoritma Market Making untuk Pasangan Kripto Menggunakan Model Avellaneda-Stoikov
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.
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:
δ_adanδ_badalah harga ask dan bidS_tadalah harga pasar saat iniγadalah parameter risiko (semakin tinggi nilainya, semakin lebar spread)kadalah tingkat kedatangan orderq_tadalah inventaris saat iniσadalah volatilitasTadalah cakrawala waktu
Fitur Perdagangan Onchain
Ketika kita memindahkan algoritma ke onchain, tantangan tambahan muncul:
- Latensi – transaksi di blockchain tidak instan, dan harga mungkin berubah sebelum order dieksekusi
- Biaya gas – setiap transaksi memerlukan biaya jaringan
- 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 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_termadalah keuntungan dari perdaganganinventory_riskadalah penalti untuk inventaris besar (risiko)gas_costadalah 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);
}
}
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:
- Hubungkan ke API nyata: ganti stub dengan permintaan nyata ke Binance API dan node Ethereum
- Tingkatkan model volatilitas: gunakan GARCH atau model lanjutan lainnya
- Perluas PPO: tambahkan lebih banyak parameter ke state dan action
- Optimalkan gas: strategi untuk meminimalkan biaya gas
- 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.}
}
Penulis
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.