Розробка grid-бота для торговлі
Grid-бот розставляє сітку лімітних ордерів вище та нижче поточної ціни і автоматично переставляє їх при виконанні. Заробляє на боковому русі ринку: ціна "стрибає" вгору-вниз, бот купує при падінні та продає при зростанні, фіксуючи прибуток на кожному кроці сітки.
Типи grid-ботів
Arithmetic grid (рівномірна сітка)
Ордери розставлені на фіксованій відстані в USDT:
$51,000 SELL
$50,500 SELL
$50,000 — поточна ціна
$49,500 BUY
$49,000 BUY
Крок = $500 (фіксований). Простий у розумінні, але % дохід на кожному рівні різний.
Geometric grid (геометрична сітка)
Ордери розставлені на фіксованій % відстані:
$51,020 SELL (+2%)
$50,020 SELL (+2% від попереднього)
$49,040 BUY (-2%)
$48,060 BUY (-2%)
Крок = 2% (фіксований відсоток). Більш коректно: % прибуток однаковий на кожному кроці.
Реалізація
Ініціалізація сітки
from decimal import Decimal
import math
class GridBot:
def __init__(self, config: GridConfig, exchange_client):
self.config = config
self.exchange = exchange_client
self.active_orders: dict[str, GridOrder] = {}
self.realized_pnl = Decimal(0)
def calculate_grid_levels(self) -> list[Decimal]:
"""Розраховуємо ціневі рівні сітки"""
lower = self.config.lower_price
upper = self.config.upper_price
num_grids = self.config.grid_count
levels = []
if self.config.grid_type == 'arithmetic':
step = (upper - lower) / num_grids
for i in range(num_grids + 1):
levels.append(lower + step * i)
elif self.config.grid_type == 'geometric':
# Геометрична прогресія
ratio = (upper / lower) ** (Decimal(1) / num_grids)
for i in range(num_grids + 1):
levels.append(lower * (ratio ** i))
return levels
async def initialize_grid(self, current_price: Decimal):
levels = self.calculate_grid_levels()
investment_per_grid = self.config.total_investment / self.config.grid_count
for i in range(len(levels) - 1):
lower_level = levels[i]
upper_level = levels[i + 1]
mid_level = (lower_level + upper_level) / 2
if mid_level < current_price:
# Нижче поточної ціни — BUY ордер
quantity = investment_per_grid / lower_level
order = await self.exchange.place_limit_order(
side='buy',
price=lower_level,
quantity=quantity
)
self.active_orders[order.id] = GridOrder(
order_id=order.id,
side='buy',
price=lower_level,
quantity=quantity,
grid_index=i
)
else:
# Вище поточної ціни — SELL ордер (якщо є позиція)
# При старті без базового активу — тільки BUY ордери
pass
Обробка виконаних ордерів
async def on_order_filled(self, order_id: str, fill_price: Decimal):
grid_order = self.active_orders.pop(order_id, None)
if not grid_order:
return
levels = self.calculate_grid_levels()
step_profit = Decimal(0)
if grid_order.side == 'buy':
# Ордер на покупку виконаний → виставляємо SELL на наступний рівень вгору
sell_price = levels[grid_order.grid_index + 1]
sell_order = await self.exchange.place_limit_order(
side='sell',
price=sell_price,
quantity=grid_order.quantity
)
self.active_orders[sell_order.id] = GridOrder(
order_id=sell_order.id,
side='sell',
price=sell_price,
quantity=grid_order.quantity,
grid_index=grid_order.grid_index + 1,
buy_price=fill_price # запам'ятовуємо ціну покупки
)
elif grid_order.side == 'sell':
# Ордер на продаж виконаний → виставляємо BUY назад
buy_price = levels[grid_order.grid_index - 1]
# Фіксуємо прибуток
step_profit = (grid_order.price - grid_order.buy_price) * grid_order.quantity
self.realized_pnl += step_profit
buy_order = await self.exchange.place_limit_order(
side='buy',
price=buy_price,
quantity=grid_order.quantity
)
self.active_orders[buy_order.id] = GridOrder(
order_id=buy_order.id,
side='buy',
price=buy_price,
quantity=grid_order.quantity,
grid_index=grid_order.grid_index - 1
)
logger.info(f"Прибуток кроку сітки: {step_profit:.4f} USDT, Всього реалізовано: {self.realized_pnl:.4f}")
Параметри та конфігурація
Ключові параметри
| Параметр | Описання | Типове значення |
|---|---|---|
lower_price |
Нижня межа сітки | -15% від поточної |
upper_price |
Верхня межа | +15% від поточної |
grid_count |
Кількість рівнів | 10-50 |
total_investment |
Загальний бюджет | За балансом |
grid_type |
arithmetic / geometric | geometric |
stop_loss |
Зупинити при виході за межу | Опціонально |
take_profit |
Закрити при досягненні цільового PnL | Опціонально |
Оптимізація параметрів
Оптимальний крок сітки залежить від волатильності активу:
def suggest_grid_step(volatility_daily_percent: float, holding_days: int = 30) -> float:
"""
Якщо актив рухається в середньому X% на день,
крок сітки повинен бути достатнім для захоплення руху.
Приблизно: 0.5x - 1x дневної волатильності.
"""
suggested_step = volatility_daily_percent * 0.7
return max(0.5, min(5.0, suggested_step)) # від 0.5% до 5%
BTC з волатильністю 3%/день → крок ~2%. ETH (5%/день) → крок ~3.5%.
Ризики та обмеження
Трендовий ринок — головний враг grid-бота. При сильному тренді вниз: BUY ордери виконуються один за одним, SELL не виконуються, накопичується збиткова позиція в базовому активі.
Управління: обмеження кількості відкритих BUY ордерів, автоматичний стоп при виході ціни за нижню межу сітки, trailing grid (сітка слідує за ціною).
Комісії: при малому кроці сітки та високих комісіях прибуток на кожному кроці може бути менше комісії. Формула: min_grid_step = 2 × fee_rate × 1.2 (буфер). При комісії 0.1%: мінімальний крок = 0.24%.
Grid-бот ідеально працює на боковому ринку та на парах стейблкоїнів (asset/stablecoin пари з низькою волатильністю на довгих горизонтах). На зростаючому ринку він заробляє менше, ніж просто холдувати.







