Дисклеймер: Информация в этой статье предоставлена исключительно в образовательных и ознакомительных целях и не является финансовым, инвестиционным или торговым советом. Торговля криптовалютами сопряжена с высоким риском убытков.
Подпишитесь на нашу рассылку, чтобы получать эксклюзивную аналитику по AI-трейдингу и обновления платформы.
Привет, друзья! Сегодня я расскажу о том, как создать алгоритм маркет-мейкинга для криптовалютных пар USD+/wETH и USD+/cbbtc. Мы будем использовать модель Авелланеда-Стоикова (A-S) и дополним её алгоритмом Reinforcement Learning (PPO) для динамической оптимизации спредов. Звучит сложно? Не волнуйтесь, я разобью всё на понятные шаги, чтобы даже начинающий разработчик смог разобраться.
Визуализация сути маркет-мейкинга: постоянный баланс ордеров на покупку и продажу вокруг справедливой цены для синтеза оптимальной рыночной ликвидности.
Что такое маркет-мейкинг и зачем он нужен?
Маркет-мейкинг - это стратегия, при которой трейдер одновременно выставляет ордера на покупку и продажу актива, зарабатывая на спреде (разнице между ценами). В DeFi-пространстве маркет-мейкеры играют ключевую роль, обеспечивая ликвидность и уменьшая проскальзывание для других участников рынка.
Представьте, что вы - продавец на рынке, который всегда готов купить товар чуть дешевле рыночной цены и продать чуть дороже. Ваша прибыль - разница между ценами покупки и продажи. Но есть нюанс: если цена резко пойдет в одну сторону, вы можете накопить слишком много товара или, наоборот, остаться с пустыми руками.
Модель Авелланеда-Стоикова: математика на службе трейдинга
Модель A-S - это математический подход к определению оптимальных цен для маркет-мейкинга. Её главное преимущество в том, что она учитывает не только текущую рыночную цену, но и размер вашей позиции (инвентаря), волатильность рынка и риск-аппетит.
Когда мы переносим алгоритм в блокчейн, появляются дополнительные сложности:
Latency (задержка) - в блокчейне транзакции не мгновенны, и цена может измениться до исполнения ордера
Gas costs - каждая транзакция требует оплаты комиссии сети
Особенности AMM/PMM - механики пулов ликвидности отличаются от традиционных бирж
Давайте посмотрим, как учесть эти факторы в нашем алгоритме.
Шаг 1: Настраиваем окружение и собираем данные
Первым делом нам нужно настроить среду для получения рыночных данных. Для этого мы будем использовать Binance API для получения текущих цен и глубины книги ордеров.
std::tuple MarketMaker::get_binance_data(const std::string& pair){
// В реальном коде здесь будет запрос к API Binance// Возвращаем: mid_price, bid, ask, bid_volume, ask_volumedouble 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};
}
Также нам понадобятся onchain-метрики, такие как стоимость газа и задержка сети:
std::pair MarketMaker::get_onchain_metrics(){
// В реальном коде здесь будет запрос к Ethereum ноде// Возвращаем: gas_price (wei), latency (seconds)return {50e9, 12.0};
}
Обратите внимание на inventory_term. Если у нас положительный инвентарь (много актива), то цена продажи снижается, а цена покупки ещё сильнее снижается, чтобы стимулировать продажи и ограничить покупки. И наоборот для отрицательного инвентаря.
Шаг 3: Адаптируем модель для onchain-торговли
Теперь нужно учесть особенности блокчейна. Начнем с задержки (latency):
Визуализация инвентарного риска: мониторинг размеров позиций для предотвращения чрезмерной уязвимости (лонг или шорт) к однонаправленным движениям рынка.
Шаг 5: Объединяем всё в один алгоритм
Теперь объединим все компоненты в единый алгоритм маркет-мейкинга:
voidMarketMaker::step(double S_t, double sigma, double k, double latency, double gas_cost, double trade_size){
// Получаем текущий инвентарьdouble current_inventory = inventory_.get_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);
// Генерация независимой рыночной ценыdouble market_price = S_t + utils::normal_dist(0.0, sigma);
// Определяем, должны ли произойти сделки на основе рыночной цены и спредовbool is_buy = (market_price = adjusted_delta_a);
// Выполняем сделки и обновляем инвентарьif (is_buy) {
inventory_.update_inventory(trade_size, true);
std::cout reset();
// Выполнить действие и получить новое состояние, награду и флаг завершения
std::tuple, double, bool> step(const std::array& action);
private:
// Получить текущее состояние средыstd::vector get_state()const;
MarketMaker& mm_;
double current_inventory_;
double current_profit_;
int current_step_;
int max_steps_;
// Текущие параметры рынкаdouble mid_price_;
double sigma_;
double latency_;
double pool_depth_;
std::mt19937 rng_;
};
Состояние нашей среды - это вектор из текущей цены, инвентаря, волатильности, задержки сети и глубины пула. Действие - это вектор из спредов и объемов для покупки и продажи.
inventory_risk - штраф за большой инвентарь (риск)
gas_cost - затраты на газ
Наконец, обучим PPO-агента:
voidPPOTrainer::train(int episodes){
for (int ep = 0; ep states;
std::vector actions;
std::vector rewards;
while (true) {
// Получаем действие из политикиauto action_probs = policy_net_->forward(torch::tensor(state));
auto action = action_probs.multinomial(1);
// Выполняем шаг в средеauto [next_state, reward, done] = env_.step(action);
// Сохраняем переход
states.push_back(torch::tensor(state));
actions.push_back(action);
rewards.push_back(reward);
if (done) break;
state = next_state;
}
// Обновляем политику PPOupdate_policy(states, actions, rewards);
}
}
Обучение с подкреплением в действии: PPO-агент анализирует сложные состояния рынка для динамической оптимизации спредов покупки/продажи с целью максимизации профита.
Шаг 7: Тестирование и визуализация
Для тестирования нашего алгоритма создадим простую симуляцию:
intmain(){
// Используем T = 300 секунд, как указано в задачеMarketMaker mm(0.1, 300.0);
// Симуляция исторических данных для волатильности
std::vector prices = {2000.0};
double S_t = 2000.0;
double trade_size = 1.0;
double initial_sigma = 0.05; // 5% волатильностьfor (int i = 0; i < 300; ++i) {
std::cout << "Step " << i + 1 << ": ";
// Получение данных (заглушки)auto [mid_price, bid_ask] = mm.get_binance_data("USD+/wETH");
auto [gas_cost, latency] = mm.get_onchain_metrics();
// Добавляем случайное движение цены для симуляции реального рынка
S_t = mid_price + utils::normal_dist(0.0, mid_price * 0.01);
// Вычисление волатильностиdouble sigma = mm.calculate_volatility(prices, 5);
if (sigma < 0.01) sigma = initial_sigma;
// Интенсивность ордеров (заглушка)double k = 5.0;
mm.step(S_t, sigma, k, latency, gas_cost, trade_size);
// Обновление цены для следующего шага
S_t += utils::normal_dist(0.0, S_t * 0.02);
prices.push_back(S_t);
}
return0;
}
Что дальше?
Наш алгоритм маркет-мейкинга готов, но есть множество направлений для улучшения:
Подключение к реальным API: заменить заглушки на реальные запросы к Binance API и Ethereum ноде
Улучшение модели волатильности: использовать GARCH или другие продвинутые модели
Расширение PPO: добавить больше параметров в состояние и действие
Оптимизация газа: стратегии для минимизации затрат на газ
Мультиактивная стратегия: расширение на несколько пар одновременно
Заключение
Мы создали алгоритм маркет-мейкинга, который учитывает особенности onchain-торговли и использует как классическую модель A-S, так и современные методы RL. Этот подход позволяет адаптироваться к изменяющимся рыночным условиям и максимизировать прибыль при контролируемом риске.
Конечно, в реальной торговле есть множество дополнительных факторов, которые нужно учитывать, но наш алгоритм даёт хорошую основу для дальнейшего развития. Главное помните: в алгоритмической торговле важна не только математика, но и тщательное тестирование, мониторинг и постоянная оптимизация.
Надеюсь, эта статья помогла вам лучше понять принципы маркет-мейкинга и вдохновила на создание собственных алгоритмов. Удачи в торговле!
Цитирование
@software{soloviov2025marketmakingavellanedastoikov,
author = {Soloviov, Eugen},
title = {Создаем алгоритм маркет-мейкинга для криптовалютных пар с использованием модели Авелланеда-Стоикова},
year = {2025},
url = {https://marketmaker.cc/ru/blog/post/market-making-avellaneda-stoikov},
version = {0.1.0},
description = {Пошаговое руководство по созданию алгоритма маркет-мейкинга для криптовалютных пар USD+/wETH и USD+/cbbtc с использованием модели Авелланеда-Стоикова и PPO. Особенности onchain-торговли, управление инвентарём, RL-обучение.}
}