Розробка системи управління позиціями на perpetual DEX
Perpetual DEX — це dYdX, GMX, Hyperliquid, Gains Network, Vertex. Всі вони дозволяють торгувати з плечем без дати експірації та без cex кастодії. Але інтерфейс більшості з них — це просто UI поверх контрактів. Якщо потрібно управляти позиціями програмно (бот, vault, протокол автоматизації) — потрібна кастомна система.
Управління позицією на perpetual DEX складніше, ніж на спот DEX: позиція має стан (розмір, entry price, плече, маржа), змінюється з часом (PnL, funding payments), може бути ліквідована. Система повинна відстежувати все це в реальному часі та реагувати на пороговані eventos.
Види perpetual DEX та їх архітектурні відмінності
Orderbook-based (dYdX v4, Hyperliquid)
Класичний orderbook, але on-chain або off-chain orderbook з on-chain settlement. dYdX v4 — це окремий Cosmos appchain, Hyperliquid — власний L1. Взаємодія через REST API та WebSocket, аналогічно CEX.
Особливість dYdX v4: транзакції відправляються не через Ethereum RPC, а через Cosmos SDK. Інший клієнт, інші формати. @dydxprotocol/v4-client-js — офіційний SDK.
Hyperliquid: власний HTTP API та WebSocket. Підписання через EIP-712 (EVM-сумісно). Найвищий throughput серед on-chain perps.
AMM-based (GMX v2, Gains Network)
Позиції відкриваються проти liquidity pool, а не counterparty. Price impact існує, orderbook немає. GMX v2 використовує синтетичні активи через Chainlink price feeds.
GMX v2 контракти: ExchangeRouter для відкриття/закриття позицій, OrderVault для зберігання collateral до виконання. Усі операції через createOrder() з параметрами.
Система управління позиціями: що входить
Position tracker
Компонент, який безперервно відстежує стан відкритих позицій:
interface Position {
id: string;
exchange: "dydx" | "gmx" | "hyperliquid";
market: string; // "ETH-USD"
side: "long" | "short";
size: bigint; // в USD
entryPrice: number;
currentPrice: number;
unrealizedPnl: number;
liquidationPrice: number;
leverage: number;
margin: bigint;
fundingPaid: number; // накопленні funding payments
}
Джерела даних: WebSocket підписки на оновлення позицій (dYdX, Hyperliquid), polling через REST кожні 5-30 секунд (GMX через subgraph або прямі контрактні виклики).
Risk manager
Стежить за наближенням до ліквідації та виконує stop-loss/take-profit:
const riskThresholds = {
liquidationWarning: 0.15, // 15% до ліквідації → алерт
autoReduceAt: 0.10, // 10% до ліквідації → зменшити позицію
emergencyCloseAt: 0.05, // 5% до ліквідації → закрити повністю
};
const distanceToLiquidation = (position: Position): number => {
const current = position.currentPrice;
const liq = position.liquidationPrice;
if (position.side === "long") return (current - liq) / current;
return (liq - current) / current;
};
Add margin — перша лінія захисту. При наближенні до liquidation price — автоматично додати collateral замість закриття позиції. Дешевше за газ та зберігає позицію. Потребує резервного балансу USDC на гаманці.
Partial close — у складній ситуації зменшити розмір на 30-50%. Зменшує розмір ризику без повного виходу.
Emergency close — повне закриття ринковим ордером. Високий slippage, але при реальній загрозі ліквідації — краще втратити 1-2% на slippage, ніж 5-15% штрафу за ліквідацію.
Funding rate monitor
Funding payments на perpetuals — приховані витрати, які при поганому знаку з'їдають PnL. Відстежуємо:
// Для longs: позитивний funding rate → ви платите
// Для shorts: позитивний funding rate → ви отримуєте
const calculateFundingCost = (
position: Position,
fundingRate8h: number, // наприклад 0.0001 = 0.01%
periods: number
): number => {
const sign = position.side === "long" ? -1 : 1;
return position.size * fundingRate8h * periods * sign;
};
Якщо накопленний funding cost перевищує очікуваний прибуток по позиції — кандидат на закриття незалежно від PnL.
Інтеграція з GMX v2
GMX v2 — найскладніший серед популярних perpetual DEX для інтеграції, тому що всі операції асинхронні через order keeper.
// Відкриття long позиції на ETH
IExchangeRouter.CreateOrderParams memory params = IExchangeRouter.CreateOrderParams({
addresses: IExchangeRouter.CreateOrderParamsAddresses({
receiver: address(this),
callbackContract: address(this), // наш контракт отримує callback
uiFeeReceiver: address(0),
market: ETH_USD_MARKET,
initialCollateralToken: USDC_ADDRESS,
swapPath: new address[](0)
}),
numbers: IExchangeRouter.CreateOrderParamsNumbers({
sizeDeltaUsd: 10_000 * 1e30, // $10,000 позиція (30 decimals)
initialCollateralDeltaAmount: 1_000 * 1e6, // $1,000 collateral (USDC 6 decimals)
triggerPrice: 0, // market order
acceptablePrice: minAcceptablePrice,
executionFee: executionFee,
callbackGasLimit: 700_000,
minOutputAmount: 0
}),
orderType: Order.OrderType.MarketIncrease,
decreasePositionSwapType: Order.DecreasePositionSwapType.NoSwap,
isLong: true,
shouldUnwrapNativeToken: false,
referralCode: bytes32(0)
});
exchangeRouter.createOrder{value: executionFee}(params);
Ордер виконується асинхронно keeper-нодою GMX. Callback afterOrderExecution() на вашому контракті сигналізує про виконання. Якщо keeper не виконав за певний час — ордер можна відмінити через cancelOrder().
Розрахунок liquidation price на GMX
// Long:
liq_price = entry_price * (1 - (margin - borrow_fee) / size)
// Short:
liq_price = entry_price * (1 + (margin - borrow_fee) / size)
borrow_fee накопляється з часом — потрібно враховувати при розрахунку поточного стану. GMX надає Reader контракт з getPositionInfo(), який повертає актуальні дані включаючи fees.
Стек та інфраструктура
TypeScript + viem для GMX on-chain взаємодій. @dydxprotocol/v4-client-js для dYdX. WebSocket клієнти для real-time даних. PostgreSQL + TimescaleDB для зберігання історії позицій та PnL. Redis для кешування поточного стану. Grafana дашборд з метриками по всім відкритим позиціям.
Часові орієнтири
Система трекінгу позицій для одного perpetual DEX з алертами — 3-5 днів. Повна система з управлінням рисками, auto-margin-add та stop-loss/take-profit для одного протоколу (GMX або dYdX) — 1-1.5 тижня. Мультипротокольна система (GMX + dYdX + Hyperliquid) — 2-3 тижні. Вартість розраховується після уточнення цільових бірж та вимог до автоматизації.







