We develop custom position management systems for perpetual DEXs – from a simple tracker to a full risk manager with automatic stop-losses and margin management. Perpetual DEXs (dYdX, GMX, Hyperliquid, Gains Network) enable leveraged trading with no expiry date and no centralized custodian. But their standard UI doesn't cover programmatic control: bots, vaults, automation protocols require their own solution. Our team has over 5 years of experience in DeFi development and guarantees transparent integration with any perpetual DEX. This article breaks down the architectural differences of key perpetual DEXs, shows a real integration with GMX v2, and provides ready-made templates for tracking and risk management.
What are the architectural differences between orderbook and AMM perpetual DEXs?
Orderbook-based (dYdX v4, Hyperliquid)
Classic orderbook, but on-chain or with off-chain orderbook and on-chain settlement. dYdX v4 is a separate Cosmos appchain, Hyperliquid is its own L1. Interaction via REST API and WebSocket, similar to CEX.
Peculiarity of dYdX v4: transactions are sent not via Ethereum RPC but via Cosmos SDK. Different client, different formats. @dydxprotocol/v4-client-js is the official SDK.
Hyperliquid: its own HTTP API and WebSocket. Signing via EIP-712 (EVM-compatible). Fastest throughput among on-chain perps.
AMM-based (GMX v2, Gains Network)
Positions are opened against a liquidity pool, not a counterparty. Price impact exists, no orderbook. GMX v2 uses synthetic assets via Chainlink price feeds.
GMX v2 contracts: ExchangeRouter for opening/closing positions, OrderVault for storing collateral until execution. All operations via createOrder() with parameters.
How is liquidation price calculated on different exchanges?
Position tracker
A component that continuously monitors open positions:
interface Position {
id: string;
exchange: "dydx" | "gmx" | "hyperliquid";
market: string; // "ETH-USD"
side: "long" | "short";
size: bigint; // in USD
entryPrice: number;
currentPrice: number;
unrealizedPnl: number;
liquidationPrice: number;
leverage: number;
margin: bigint;
fundingPaid: number; // accumulated funding payments
}
Data sources: WebSocket subscriptions to position updates (dYdX, Hyperliquid), polling via REST every 5–30 seconds (GMX via subgraph or direct contract calls).
Risk manager
Monitors proximity to liquidation and executes stop-loss/take-profit:
const riskThresholds = {
liquidationWarning: 0.15, // 15% to liquidation → alert
autoReduceAt: 0.10, // 10% to liquidation → reduce position
emergencyCloseAt: 0.05, // 5% to liquidation → close completely
};
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 – first line of defense. When approaching liquidation price – automatically add collateral instead of closing. Cheaper on gas and preserves position. Requires a reserve USDC balance on the wallet.
Partial close – in heavy situations, reduce size by 30–50%. Reduces risk without full exit.
Emergency close – full close with a market order. High slippage, but when facing real liquidation threat, losing 1–2% on slippage is better than a 5–15% liquidation penalty.
Funding rate monitor
Funding payments on perpetuals are hidden costs that, with the wrong sign, eat PnL. We track:
// For longs: positive funding rate → you pay
// For shorts: positive funding rate → you receive
const calculateFundingCost = (
position: Position,
fundingRate8h: number, // e.g., 0.0001 = 0.01%
periods: number
): number => {
const sign = position.side === "long" ? -1 : 1;
return position.size * fundingRate8h * periods * sign;
};
If accumulated funding cost exceeds expected profit on the position – candidate for closing regardless of PnL.
Integration with GMX v2: step-by-step guide
GMX v2 is the most complex popular perpetual DEX for integration because all operations are asynchronous via order keeper.
- Import GMX contracts via
npm install @gmx-v2/contracts. - Connect Viem provider and get an instance of
ExchangeRouter. - Create and sign
CreateOrderParams. - Send transaction with
executionFee. - Handle callback
afterOrderExecution().
// Opening a long position on ETH
IExchangeRouter.CreateOrderParams memory params = IExchangeRouter.CreateOrderParams({
addresses: IExchangeRouter.CreateOrderParamsAddresses({
receiver: address(this),
callbackContract: address(this), // our contract gets callback
uiFeeReceiver: address(0),
market: ETH_USD_MARKET,
initialCollateralToken: USDC_ADDRESS,
swapPath: new address[](0)
}),
numbers: IExchangeRouter.CreateOrderParamsNumbers({
sizeDeltaUsd: 10_000 * 1e30, // $10,000 position (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);
The order is executed by GMX keeper nodes asynchronously. Callback afterOrderExecution() on your contract signals execution. If the keeper doesn't execute within a certain time – order can be canceled via cancelOrder().
Liquidation price calculation on GMX
| Parameter | Formula |
|---|---|
| Long | liq_price = entry_price * (1 - (margin - borrow_fee) / size) |
| Short | liq_price = entry_price * (1 + (margin - borrow_fee) / size) |
borrow_fee accumulates over time – it must be considered when calculating current state. GMX provides the Reader contract with getPositionInfo() that returns up-to-date data including fees.
Exchange comparison table
| Parameter | dYdX v4 | Hyperliquid | GMX v2 |
|---|---|---|---|
| Architecture | Cosmos appchain | Proprietary L1 | Arbitrum/AVAX |
| API | REST + WebSocket, Cosmos SDK | REST + WebSocket, EIP-712 | Ethereum contracts, async order |
| Integration complexity | Medium | Low | High (async order) |
| Speed | ~0.5 sec | ~0.1 sec | ~1-5 min (keeper) |
Stack and infrastructure
TypeScript + viem for GMX on-chain interactions. @dydxprotocol/v4-client-js for dYdX. WebSocket clients for real-time data. PostgreSQL + TimescaleDB for history of positions and PnL. Redis for caching current state. Grafana dashboard with metrics for all open positions.
Timeline estimates
| Stage | Duration | Result |
|---|---|---|
| Analysis | 1–3 days | Requirements, stack selection |
| Design | 2–4 days | Architecture, diagrams |
| Implementation | 5–10 days | Working prototype |
| Testing | 2–3 days | Unit + integration tests |
| Deployment | 1–2 days | Production environment |
Position tracking system for one perpetual DEX with alerts – 3–5 days. Full system with risk management, auto-margin-add and stop-loss/take-profit for one protocol (GMX or dYdX) – 1–1.5 weeks. Multi-protocol system (GMX + dYdX + Hyperliquid) – 2–3 weeks. Cost is determined after clarifying target exchanges and automation requirements.
Get a consultation on your project – we'll assess complexity and timeline. We deliver turnkey in 2–3 weeks.







