Avellaneda-Stoikov моделин колдонуп крипто жуптары үчүн маркет-мейкинг алгоритмин түзүү
Салам, достор! Бүгүн мен силерге USD+/wETH жана USD+/cbbtc крипто жуптары үчүн маркет-мейкинг алгоритмин кантип түзүүнү көрсөтөм. Биз Avellaneda-Stoikov (A-S) моделин колдонуп, аны спредди динамикалык оптималдаштыруу үчүн Reinforcement Learning (PPO) алгоритми менен жакшыртабыз. Татаал угулабы? Тынчсызданбагыла, мен баарын так кадамдарга бөлүп берем, ошондуктан жаңы башталган иштеп чыгуучу да түшүнө алат.
Маркет-мейкингдин маанисин чагылдыруу: оптималдуу рыноктук ликвиддүүлүктү синтездөө үчүн адилеттүү баа тегерегинде сатып алуу жана сатуу ордерлерин үзгүлтүксүз тең салмактоо.
Маркет-мейкинг деген эмне жана ал бизге эмне үчүн керек?
Маркет-мейкинг — бул трейдер активге бир учурда сатып алуу жана сатуу ордерлерин коюп, спредден (баалардын ортосундагы айырмадан) киреше табуучу стратегия. DeFi чөйрөсүндө маркет-мейкерлер ликвиддүүлүктү камсыз кылуу жана башка рынок катышуучулары үчүн слиппажды азайтуу аркылуу негизги ролду ойношот.
Силерди базардагы соодагер деп элестеткиле, дайыма товарды рыноктук баадан бир аз төмөн сатып алууга жана бир аз жогору сатууга даяр. Силердин пайдаңар сатып алуу жана сатуу баалардын ортосундагы айырма. Бирок бир кыйынчылык бар: эгер баа кокустан бир багытта жылса, силерде өтө көп инвентарь топтолуп калышы мүмкүн, же тескерисинче, сатууга эч нерсе калбашы мүмкүн.
Avellaneda-Stoikov модели: соода кызматындагы математика
A-S модели маркет-мейкинг үчүн оптималдуу баалуулуктарды аныктоонун математикалык ыкмасы болуп саналат. Анын негизги артыкчылыгы — учурдагы рыноктук бааны гана эмес, силердин позицияңардын көлөмүн (инвентарь), рыноктун туруксуздугун жана тобокелге болгон табитти да эске алат.
Модель формулалары:
δ_a = S_t + (1/γ) * ln(1 + γ/k) + q_t * σ² * T
δ_b = S_t - (1/γ) * ln(1 + γ/k) - q_t * σ² * T
мында:
δ_aжанаδ_b— аск жана бид бааларыS_t— учурдагы рыноктук бааγ— тобокел параметри (канчалык жогору болсо, спред ошончолук кең болот)k— ордерлердин келүү ылдамдыгыq_t— учурдагы инвентарьσ— туруксуздукT— убакыт горизонту
Ончейн соодасынын өзгөчөлүктөрү
Алгоритмди ончейнге өткөргөндө кошумча кыйынчылыктар пайда болот:
- Кечигүү (latency) – блокчейндеги транзакциялар дароо болбойт, ошондуктан ордер аткарылганга чейин баа өзгөрүшү мүмкүн
- Газ чыгымдары – ар бир транзакция үчүн тармак комиссиясы талап кылынат
- AMM/PMM өзгөчөлүктөрү – ликвиддүүлүк пулдарынын механикасы салттуу биржалардан айырмаланат
Ушул факторлорду алгоритмибизде кантип эске аларыбызды көрөлү.
1-кадам: Чөйрөнү жөндөө жана маалыматтарды чогултуу
Алгач, рыноктук маалыматтарды алуу үчүн чөйрөнү жөндөшүбүз керек. Учурдагы бааларды жана ордер китебинин тереңдигин алуу үчүн Binance API колдонобуз.
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};
}
Бизге газ чыгымы жана тармак кечигүүсү сыяктуу ончейн метрикалары да керек болот:
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 моделин ишке ашыруу
Эми 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-ге көңүл буруңуздар. Эгер силерде оң инвентарь болсо (активдин көп өлчөмү), аск баасы төмөндөйт, ал эми бид баасы андан да көбүрөөк төмөндөйт, бул сатууну кубаттайт жана сатып алууну чектейт. Терс инвентарь үчүн тескерисинче.
3-кадам: Модельди ончейн соодага ыңгайлаштыруу
Эми блокчейндин өзгөчөлүктөрүн эске алышыбыз керек. Кечигүүдөн баштайлы:
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) моделин колдонобуз: туруксуздук канчалык жогору жана кечигүү канчалык узак болсо, ордер аткарылганга чейин баа ошончолук көп өзгөрүшү мүмкүн.
Эми газ чыгымын эске алалы:
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
}
Акырында, спредтерди 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};
}
4-кадам: Инвентаризацияны башкаруу
Инвентарды көзөмөлдөө жана башкаруу үчүн жөнөкөй класс түзөлү:
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_;
};
Инвентарь тобокелин визуализациялоо: бир багыттуу рыноктук кыймылдарга ашыкча дуушар болбоо (лонг же шорт) үчүн позиция көлөмдөрүн көзөмөлдөө.
5-кадам: Баарын бир алгоритмге бириктирүү
Эми бардык компоненттерди бир маркет-мейкинг алгоритмине бириктиребиз:
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_;
};
Чөйрөбүздүн абалы — учурдагы баа, инвентарь, туруксуздук, тармак кечигүүсү жана пул тереңдигинен турган вектор. Аракет — спредтердин жана сатып алуу/сатуу көлөмдөрүнүн векторуна.
Эми сыйлык функциясын ишке ашыралы:
double reward = profit_term - inventory_risk - gas_cost;
Мында:
profit_term— соодалардан алынган пайдаinventory_risk— чоң инвентарь үчүн айыппул (тобокел)gas_cost— коротулган газ
Акырында, 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: PPO агенти максималдуу күтүлгөн сыйлык үчүн сатып алуу/сатуу спредтерин динамикалык түрдө оптималдаштыруу максатында татаал рыноктук абалдарды иштетет.
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;
}
Андан ары эмне кылуу керек?
Маркет-мейкинг алгоритмибиз даяр, бирок аны жакшыртуунун көптөгөн жолдору бар:
- Чыныгы API'лерге туташуу: заглушкаларды Binance API жана Ethereum түйүнүнө чыныгы суроо-талаптар менен алмаштыруу
- Туруксуздук моделин жакшыртуу: GARCH же башка өнүккөн моделдерди колдонуу
- PPO кеңейтүү: абалга жана аракетке көбүрөөк параметр кошуу
- Газды оптималдаштыруу: газ чыгымдарын азайтуу стратегиялары
- Мульти-активдүү стратегия: бир эле учурда бир нече жупка кеңейтүү
Корутунду
Биз ончейн соодасынын өзгөчөлүктөрүн эске алган жана классикалык A-S моделин да, заманбап RL ыкмаларын да колдонгон маркет-мейкинг алгоритмин түздүк. Бул мамиле рыноктун өзгөрүлмө шарттарына ыңгайлашууга жана тобокелди көзөмөлдөп туруп пайданы максималдаштырууга мүмкүндүк берет.
Албетте, чыныгы соодада эске алынуучу дагы көптөгөн факторлор бар, бирок алгоритмибиз андан аркы өнүктүрүү үчүн бекем негиз берет. Эсиңерде болсун: алгоритмдик соодада жалгыз гана математика эмес, ошондой эле мукиятталган сыноо, мониторинг жана үзгүлтүксүз оптималдаштыруу да маанилүү.
Бул макала маркет-мейкингдин принциптерин жакшыраак түшүнүүгө жардам берди жана силерди өз алгоритмдериңерди түзүүгө шыктандырды деп үмүттөнөм. Соодада ийгилик каалайм!
Citation
@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/en/blog/post/market-making-avellaneda-stoikov},
version = {0.1.0},
description = {A step-by-step guide to building a market making algorithm for USD+/wETH and USD+/cbbtc pairs using the Avellaneda-Stoikov model and PPO. Onchain trading features, inventory management, RL training.}
}
Authors
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.