Разработка системы фьючерсной торговли
Фьючерсная торговля — это торговля контрактами на будущую цену актива с использованием кредитного плеча. Для биржи это технически самый сложный продукт: margin engine, liquidation system, funding rate механизм, risk management — каждый компонент требует производительности, точности и устойчивости к граничным случаям. Ошибка в расчётах margin может привести к социализации убытков или несостоятельности биржи.
Типы фьючерсных контрактов
Перед архитектурой — понимание типов:
| Тип | Expiry | Settlement | Где применяется |
|---|---|---|---|
| Quarterly futures | Фиксированная дата | Cash или physical | CME, Deribit |
| Perpetual swaps | Нет | Mark price + funding | Binance, Bybit, dYdX |
| Inverse perpetuals | Нет | В базовом активе | Bitmex legacy, Bybit |
| Linear perpetuals | Нет | В stablecoin | Большинство CEX |
Perpetual swaps доминируют на крипторынке. Отсутствие экспирации удобно для трейдеров, а funding rate механизм удерживает цену контракта близко к spot.
Margin система
Isolated vs Cross margin
Isolated margin: для каждой позиции выделяется отдельный маржин. Убыток ограничен выделенным залогом. Пользователь не потеряет весь аккаунт из-за одной позиции.
Cross margin: все позиции используют общий баланс как обеспечение. Unrealized PnL от прибыльных позиций покрывает убытки других. Более эффективное использование капитала, но риск полного дренажа аккаунта.
Реализация в базе данных:
-- Пример схемы margin account
CREATE TABLE margin_accounts (
user_id UUID NOT NULL,
currency VARCHAR(10) NOT NULL,
balance NUMERIC(30, 18) NOT NULL DEFAULT 0,
margin_mode VARCHAR(10) NOT NULL DEFAULT 'cross', -- 'cross' | 'isolated'
PRIMARY KEY (user_id, currency)
);
CREATE TABLE positions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
symbol VARCHAR(20) NOT NULL,
side VARCHAR(5) NOT NULL, -- 'long' | 'short'
size NUMERIC(30, 18) NOT NULL,
entry_price NUMERIC(30, 18) NOT NULL,
leverage SMALLINT NOT NULL,
isolated_margin NUMERIC(30, 18), -- NULL для cross mode
liquidation_price NUMERIC(30, 18),
unrealized_pnl NUMERIC(30, 18) DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Расчёт liquidation price
Для long позиции в linear perpetual:
Liquidation price = Entry price * (1 - 1/leverage + maintenance_margin_rate)
Для short:
Liquidation price = Entry price * (1 + 1/leverage - maintenance_margin_rate)
Где maintenance_margin_rate (MMR) — минимальный уровень маржи, при котором позиция принудительно закрывается. Обычно 0.5% для низкого плеча, до 5% для плеча 100x.
Пример: Long BTC с entry 50,000 USDT, leverage 10x:
Liq price = 50,000 * (1 - 0.1 + 0.005) = 50,000 * 0.905 = 45,250 USDT
Пересчёт liquidation price происходит при каждом изменении позиции и должен быть атомарным с обновлением маржи.
Funding Rate механизм
Назначение
Funding rate — периодический платёж между holders лонгов и шортов. Если perpetual торгуется выше spot (contango), лонги платят шортам. Если ниже (backwardation) — шорты платят лонгам. Это якорит perpetual цену к spot без экспирации.
Формула Binance-стиль
Funding Rate = clamp(
(Premium Index) + clamp(Interest Rate - Premium Index, -0.05%, 0.05%),
-0.75%, 0.75%
)
Premium Index = (Max(0, Impact Bid Price - Mark Price) - Max(0, Mark Price - Impact Ask Price)) / Spot Price
Impact Bid/Ask Price — средневзвешенная цена для ордера на $200k номинала в текущем order book.
Mark Price — защищённая от манипуляций цена для расчёта unrealized PnL и liquidations:
Mark Price = Index Price + EMA(Basis)
Basis = Perpetual Mid Price - Index Price
Funding rate рассчитывается каждые 8 часов (стандарт) или 1 час (Bybit). Реализация:
def calculate_funding_rate(order_book, index_price, interest_rate=0.0001):
impact_size_usd = 200_000
impact_bid = get_impact_price(order_book.bids, impact_size_usd, 'bid')
impact_ask = get_impact_price(order_book.asks, impact_size_usd, 'ask')
mark_price = get_mark_price(index_price)
premium_index = (
max(0, impact_bid - mark_price) - max(0, mark_price - impact_ask)
) / index_price
raw_funding = premium_index + clamp(
interest_rate - premium_index, -0.0005, 0.0005
)
return clamp(raw_funding, -0.0075, 0.0075)
При каждом funding timestamp:
Funding Payment = Position Size * Mark Price * Funding Rate
Positive rate → long платит short. Negative → short платит long.
Liquidation Engine
Уровни защиты
Liquidation система — это многоуровневая защита от потерь биржи:
Уровень 1: Partial liquidation — при приближении к liquidation price закрывается часть позиции для повышения маржи. Bybit использует этот подход для крупных позиций.
Уровень 2: Full liquidation — позиция полностью закрывается liquidation engine по mark price.
Уровень 3: Insurance fund — если liquidation price хуже bankruptcy price (цена при которой маржа = 0), разница покрывается из страхового фонда.
Уровень 4: Auto-Deleveraging (ADL) — если insurance fund недостаточен, прибыльные позиции в противоположном направлении принудительно закрываются. Экстремальная мера.
Архитектура liquidation engine
Liquidation engine мониторит все позиции в реальном времени:
class LiquidationEngine:
def __init__(self, exchange):
self.exchange = exchange
self.check_interval_ms = 100 # 100ms polling
async def run(self):
while True:
mark_prices = await self.exchange.get_mark_prices()
at_risk = await self.db.get_positions_at_risk(mark_prices)
for position in at_risk:
await self.process_liquidation(position, mark_prices[position.symbol])
await asyncio.sleep(self.check_interval_ms / 1000)
async def process_liquidation(self, position, mark_price):
async with self.db.transaction():
# Пересчитать актуальный margin ratio
margin_ratio = self.calculate_margin_ratio(position, mark_price)
if margin_ratio > position.maintenance_margin_rate:
return # Успели выйти из зоны риска
# Попытка market close
fill_price = await self.exchange.market_close(
position, liquidation=True
)
pnl = self.calculate_pnl(position, fill_price)
if pnl < 0 and abs(pnl) > position.margin:
# Ушли в минус — задействуем insurance fund
shortfall = abs(pnl) - position.margin
await self.insurance_fund.cover(shortfall, position.currency)
await self.db.close_position(position.id, fill_price, pnl)
await self.notify_user(position.user_id, "liquidation", position, fill_price)
Производительность критична: 10,000+ открытых позиций должны проверяться за <100ms. Оптимизации:
- Позиции хранятся в Redis sorted set, sorted by distance to liquidation price
- При изменении mark price обновляется только delta — O(1) vs O(N) full scan
- Liquidation orders идут в отдельную очередь с приоритетом
Mark Price и Index Price
Index Price
Index price — это средневзвешенная spot цена с нескольких крупных бирж. Типичные источники для BTC: Binance, Coinbase, Kraken, OKX, Bitstamp.
Ключевые требования:
- Outlier protection: если цена одной биржи отклоняется >3% от медианы — она исключается
- Staleness detection: если фид не обновлялся >30 секунд — исключается
- Минимум 3 активных источника, иначе торги приостанавливаются
Mark Price
Mark price сглаживает краткосрочные манипуляции price. EMA(Basis) с периодом 30 секунд достаточна для большинства случаев. Важно: liquidations происходят по mark price, а не по last traded price. Это защищает трейдеров от flash crashes в низколиквидных окнах.
Risk Management система
Position limits
def get_max_leverage(notional_value_usd: float) -> int:
"""Снижение доступного плеча с ростом размера позиции"""
tiers = [
(50_000, 100),
(500_000, 50),
(2_000_000, 20),
(10_000_000, 10),
(50_000_000, 5),
]
for max_notional, max_leverage in tiers:
if notional_value_usd <= max_notional:
return max_leverage
return 2
Tiered leverage — стандартная практика. Крупные позиции не могут использовать высокое плечо: слишком высокий риск для insurance fund при ликвидации.
Концентрация риска
Мониторинг суммарного exposure по каждому активу:
| Метрика | Порог | Действие |
|---|---|---|
| Net open interest imbalance | >70% в одну сторону | Повышение funding rate |
| Gross open interest | >$X по символу | Ограничение новых позиций |
| Single user concentration | >20% total OI | Manual review |
| Insurance fund drawdown | >50% за день | Снижение макс. плеча |
Технический стек
| Компонент | Технология | Обоснование |
|---|---|---|
| Matching engine | C++/Rust | Latency <1ms |
| Margin calculator | Go | Параллелизм + скорость |
| Funding rate service | Python | Аналитические расчёты |
| Liquidation engine | Go | Надёжность + скорость |
| Market data | Redis Streams | Low-latency pub/sub |
| Positions DB | PostgreSQL | ACID + сложные запросы |
| Price feeds | Chainlink + direct API | Децентрализация + скорость |
Разработка perpetual futures системы — это минимум 6-9 месяцев для команды из 4-6 backend инженеров. Основные риски: ошибки в расчёте liquidation price, race conditions в margin updates, и задержки в price feed при высокой волатильности.







