Developing a position management system for perpetual DEX
Perpetual DEX — these are dYdX, GMX, Hyperliquid, Gains Network, Vertex. They all allow trading with leverage without expiration date and without CEX custody. But the interface of most of them is just UI over contracts. If you need to manage positions programmatically (bot, vault, automation protocol) — you need a custom system.
Position management on perpetual DEX is more complex than on spot DEX: a position has state (size, entry price, leverage, margin), changes over time (PnL, funding payments), can be liquidated. The system must track all of this in real time and react to threshold events.
Types of perpetual DEX and their architectural differences
Orderbook-based (dYdX v4, Hyperliquid)
Classic orderbook, but on-chain or off-chain orderbook with on-chain settlement. dYdX v4 is a separate Cosmos appchain, Hyperliquid is its own L1. Interaction via REST API and WebSocket, similar to CEX.
dYdX v4 specifics: transactions are sent not via Ethereum RPC, but via Cosmos SDK. Different client, different formats. @dydxprotocol/v4-client-js is the official SDK.
Hyperliquid: own HTTP API and WebSocket. Signing via EIP-712 (EVM-compatible). Highest throughput among on-chain perps.
AMM-based (GMX v2, Gains Network)
Positions are opened against liquidity pool, not 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.
Position management system: what's included
Position tracker
A component that continuously tracks the state of 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 approach to liquidation and executes stop-loss/take-profit:
const riskThresholds = {
liquidationWarning: 0.15, // 15% until liquidation → alert
autoReduceAt: 0.10, // 10% until liquidation → reduce position
emergencyCloseAt: 0.05, // 5% until 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 the position. Cheaper in gas and preserves the position. Requires reserve USDC balance on the wallet.
Partial close — in a difficult situation, reduce size by 30-50%. Reduces risk size without full exit.
Emergency close — complete closing with market order. High slippage, but when facing real liquidation threat — better to lose 1-2% on slippage than 5-15% liquidation penalty.
Funding rate monitor
Funding payments on perpetuals are hidden costs that, with wrong sign, eat into 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
GMX v2 is the most complex of popular perpetual DEX for integration because all operations are asynchronous via order keeper.
// Opening long position on ETH
IExchangeRouter.CreateOrderParams memory params = IExchangeRouter.CreateOrderParams({
addresses: IExchangeRouter.CreateOrderParamsAddresses({
receiver: address(this),
callbackContract: address(this), // our contract receives 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 asynchronously by GMX keeper node. Callback afterOrderExecution() on your contract signals execution. If keeper didn't execute within certain time — the order can be cancelled via cancelOrder().
Calculating liquidation price on GMX
// 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 — must be accounted for when calculating current state. GMX provides a Reader contract with getPositionInfo() which returns actual data including fees.
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 storing position history and PnL. Redis for caching current state. Grafana dashboard with metrics for all open positions.
Timeline estimates
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 calculated after clarifying target exchanges and automation requirements.







