Разработка торгового бота для фьючерсной торговли
Фьючерсный бот торгует perpetual contracts с кредитным плечом. По сравнению со спотовым, это другой уровень сложности и риска: маржин-колл, ликвидация, funding rate, сложное управление позициями. Но и возможности значительно шире: шорт без заимствования, усиление прибыли через плечо.
Ключевые отличия от спотового бота
Leverage management — плечо усиливает как прибыль, так и убытки. При плече 10x движение цены на 10% против позиции = полная ликвидация.
Margin management — нужно следить за margin ratio и пополнять при необходимости.
Funding rate — регулярный платёж в зависимости от направления и рыночных условий.
Liquidation price — цена, при которой позиция принудительно закрывается. Должна быть выше stop-loss.
Hedge mode vs One-way mode — Binance позволяет держать лонг и шорт одновременно (hedge mode).
Расчёт ключевых параметров
from decimal import Decimal
class FuturesPositionCalculator:
def calculate_position_size(
self,
capital: Decimal,
risk_pct: Decimal, # % капитала под риском
entry_price: Decimal,
stop_loss_price: Decimal,
leverage: int,
) -> dict:
"""Рассчитываем безопасный размер позиции"""
risk_amount = capital * risk_pct
price_diff_pct = abs(entry_price - stop_loss_price) / entry_price
# Размер позиции при данном риске
position_size_usd = risk_amount / price_diff_pct
# С учётом плеча
required_margin = position_size_usd / Decimal(str(leverage))
if required_margin > capital * Decimal('0.3'):
# Не рискуем более 30% капитала в margin
position_size_usd = capital * Decimal('0.3') * Decimal(str(leverage))
required_margin = capital * Decimal('0.3')
quantity = position_size_usd / entry_price
return {
'position_size_usd': position_size_usd,
'quantity': quantity,
'required_margin': required_margin,
'leverage_used': leverage,
}
def calculate_liquidation_price(
self,
entry_price: Decimal,
leverage: int,
side: str,
maintenance_margin_rate: Decimal = Decimal('0.005'), # 0.5%
) -> Decimal:
"""Рассчитываем цену ликвидации"""
if side == 'LONG':
liq_price = entry_price * (1 - 1/Decimal(str(leverage)) + maintenance_margin_rate)
else:
liq_price = entry_price * (1 + 1/Decimal(str(leverage)) - maintenance_margin_rate)
return liq_price
Архитектура фьючерсного бота
class FuturesTradingBot:
def __init__(
self,
exchange,
symbol: str,
leverage: int = 5,
max_position_pct: float = 0.20, # макс 20% капитала в одну позицию
):
self.exchange = exchange
self.symbol = symbol
self.leverage = leverage
self.max_position_pct = max_position_pct
self.calculator = FuturesPositionCalculator()
async def initialize(self):
"""Настройка перед торговлей"""
# Устанавливаем плечо
await self.exchange.set_leverage(self.leverage, self.symbol)
# Изолированная маржа для ограничения риска
await self.exchange.set_margin_mode('isolated', self.symbol)
async def open_long(self, entry_price: Decimal, stop_loss: Decimal):
balance = await self.get_available_margin()
params = self.calculator.calculate_position_size(
capital=balance,
risk_pct=Decimal('0.02'),
entry_price=entry_price,
stop_loss_price=stop_loss,
leverage=self.leverage,
)
liq_price = self.calculator.calculate_liquidation_price(entry_price, self.leverage, 'LONG')
# Проверяем: ликвидация должна быть ниже stop-loss
if liq_price >= stop_loss:
logger.warning(f"Liquidation price {liq_price} >= stop loss {stop_loss}. Reducing size.")
params['quantity'] *= Decimal('0.5')
# Выставляем ордера
entry_order = await self.exchange.create_order(
symbol=self.symbol,
type='market',
side='buy',
amount=float(params['quantity']),
params={'reduceOnly': False},
)
# Стоп-лосс как отдельный ордер
sl_order = await self.exchange.create_order(
symbol=self.symbol,
type='stop_market',
side='sell',
amount=float(params['quantity']),
params={
'stopPrice': float(stop_loss),
'reduceOnly': True,
'closePosition': False,
},
)
logger.info(f"Long opened: qty={params['quantity']}, entry={entry_price}, SL={stop_loss}, liq={liq_price}")
return entry_order, sl_order
async def monitor_margin_ratio(self):
"""Мониторинг маржи — критическая функция"""
while self.is_running:
position = await self.exchange.fetch_positions([self.symbol])
if position:
margin_ratio = float(position[0].get('marginRatio', 0))
if margin_ratio > 0.8: # маржа использована более чем на 80%
logger.critical(f"MARGIN RATIO CRITICAL: {margin_ratio:.1%}")
await self.emergency_close()
elif margin_ratio > 0.6:
logger.warning(f"Margin ratio high: {margin_ratio:.1%}")
await self.alerter.send(f"Futures margin ratio: {margin_ratio:.1%}")
await asyncio.sleep(30) # проверяем каждые 30 секунд
async def emergency_close(self):
"""Аварийное закрытие всех позиций"""
logger.critical("EMERGENCY CLOSE INITIATED")
# Отменяем все pending ордера
await self.exchange.cancel_all_orders(self.symbol)
# Закрываем позицию по рынку
await self.exchange.create_order(
symbol=self.symbol,
type='market',
side='sell', # или buy для шорта
params={'reduceOnly': True, 'closePosition': True},
)
Учёт funding rate в стратегии
class FundingAwareStrategy:
EXTREME_FUNDING_THRESHOLD = 0.001 # 0.1% за 8 часов
async def get_adjusted_signal(self, base_signal: Signal, symbol: str) -> Signal:
"""Корректируем сигнал с учётом текущего funding rate"""
funding = await self.exchange.fetch_funding_rate(symbol)
current_rate = float(funding['fundingRate'])
# При экстремально высоком positive funding — не открываем лонги
if current_rate > self.EXTREME_FUNDING_THRESHOLD and base_signal == Signal.LONG:
logger.info(f"Skipping long: funding rate too high ({current_rate:.4%})")
return Signal.HOLD
# При очень negative funding — не открываем шорты
if current_rate < -self.EXTREME_FUNDING_THRESHOLD and base_signal == Signal.SHORT:
logger.info(f"Skipping short: funding rate too negative ({current_rate:.4%})")
return Signal.HOLD
return base_signal
Риски фьючерсной торговли
Основные причины потерь при фьючерсной торговле ботом:
- Ликвидация из-за высокого плеча — используйте максимум 3–5x для автоматических стратегий
- Stop-hunting — цена ненадолго выходит за стоп и возвращается. Используйте стопы с небольшим буфером
- Funding drain — при постоянном positive funding лонговая стратегия теряет 0.03–0.15% в день только на funding
- Flash crash — резкое падение цены может ликвидировать позицию раньше стопа при недостаточной ликвидности
Рекомендуемый старт: изолированная маржа, плечо 3x, размер позиции не более 10% капитала.







