| name | gdex-perp-copy-trading |
| description | HyperLiquid perpetual futures copy trading — discover top perp traders, create/manage perp copy trades, fill history, opposite-direction copying, and market data |
GDEX: Perp Copy Trading (HyperLiquid)
Automatically mirror perpetual futures positions (long/short) from top-performing HyperLiquid traders. Supports opposite-direction copying, fixed or proportional sizing, and TP/SL controls.
This is completely separate from Solana spot copy trading (gdex-copy-trading). Different chain (EVM, chainId=1 vs Solana 622112261), different ABI methods (hl_create/hl_update vs create_copy_trade/update_copy_trade), different field schemas. Both isDelete and isChangeStatus permanently DELETE copy trades on both chains.
When to Use
- Browsing top HyperLiquid perp traders (by volume, PnL, or deposit)
- Getting detailed trading stats for a specific trader
- Creating a perp copy trade to follow a trader's long/short positions
- Updating or deleting a perp copy trade
- Viewing perp copy trade fill history with enrichment
- Checking market data (assets, DEXes, clearinghouse state, open orders)
- Checking deposit tokens and USDC balance
Prerequisites
@gdexsdk/gdex-skill installed
- For discovery:
loginWithApiKey() only
- For read (list/tx_list): Full sign-in with session key (
chainId: 1)
- For write (create/update): Full sign-in + computedData
Auth Tiers
| Tier | Endpoints | Auth Needed |
|---|
| Discovery | top_traders, top_traders_by_pnl, user_stats, perp_dexes, all_assets, clearinghouse_state, open_orders, deposit_tokens, usdc_balance | API key only |
| Read | list, tx_list | Session-key auth (userId + encrypted data) |
| Write | create, update | computedData (ABI-encode + sign + AES-encrypt) |
Key Differences from Solana Copy Trading
| Feature | Solana (gdex-copy-trading) | HL Perp (gdex-perp-copy-trading) |
|---|
| Chain | Solana (622112261) | EVM (chainId = 1) |
| Asset Type | Spot tokens | Perpetual futures (long/short) |
| ABI Methods | create_copy_trade / update_copy_trade | hl_create / hl_update |
| ABI Fields | 12 create / 16 update (chainId=uint256) | 8 create / 11 update (all strings) |
| Opposite Copy | ❌ Not supported | ✅ oppositeCopy flag |
isChangeStatus | ⚠️ Permanently deletes! | ⚠️ Also permanently deletes (same as isDelete) |
| Copy Modes | 1=fixed SOL, 2=% of trader | 1=fixed USD per order, 2=proportion of trader's size |
| TP/SL | Optional | Mandatory (both > 0, lossPercent < 100) |
| Max Copies | config.maxCopyTrades | Default 3 (hyperLiquidConfig.maxFuturesCopy) |
Discovery Endpoints (No Auth)
Top Traders by Volume/TradeCount/Deposit
const topByVolume = await skill.getHlTopTraders('volume');
const topByTrades = await skill.getHlTopTraders('tradeCount');
const topByDeposit = await skill.getHlTopTraders('deposit');
Top 30 Traders by PnL
const topPnl = await skill.getHlTopTradersByPnl();
Detailed User Stats
const stats = await skill.getHlUserStats('0xManagedWalletAddress');
HlUserStats Shape
interface HlUserStats {
'24h': number;
'7d': number;
'30d': number;
week: number;
dailyPnls: Array<{
timeMs: number;
date: string;
pnl: number;
pnlPercentage: number;
capitalDeployed: number;
}>;
volumes: Record<string, number>;
tradesCount: Record<string, { win: number; lose: number; total: number }>;
percentagePnl: Record<string, number>;
capitalDeployed: Record<string, number>;
allTime: { pnl: number; pnlPercentage: number; capitalDeployed: number };
}
Perp DEXes
const dexes = await skill.getHlPerpDexes();
All Tradeable Assets
const assets = await skill.getHlAllAssets();
Clearinghouse State (Account Positions)
const state = await skill.getHlClearinghouseState('0xTraderAddress');
const stateAll = await skill.getHlClearinghouseStateAll('0xTraderAddress');
Open Orders
const orders = await skill.getHlOpenOrdersForCopy('0xTraderAddress');
const ordersAll = await skill.getHlOpenOrdersAllForCopy('0xTraderAddress');
Deposit Tokens
const tokens = await skill.getHlDepositTokens();
USDC Balance (Arbitrum)
const balance = await skill.getHlUsdcBalanceForCopy('0xTraderAddress');
Read Endpoints (Session-Key Auth)
Require userId and data (AES-encrypted session key from buildGdexUserSessionData).
List User's HL Copy Trades
import { buildGdexUserSessionData } from '@gdexsdk/gdex-skill';
const data = buildGdexUserSessionData(sessionKey, apiKey);
const list = await skill.getHlCopyTradeList({ userId, data });
HlCopyTradeConfig Shape
interface HlCopyTradeConfig {
copyTradeId: string;
copyTradeName: string;
copyMode: number;
chainId: number;
isActive: boolean;
userId: string;
userWallet: string;
traderWallet: string;
lossPercent: number;
profitPercent: number;
fixedAmountCostPerOrder: string;
oppositeCopy: boolean;
createdAt: number;
lastUpdated: number;
totalTrades: number;
totalVolumes: number;
totalPnl: number;
}
Fill History
const txList = await skill.getHlCopyTradeTxList({
userId,
data,
page: '1',
limit: '20',
});
HlCopyTradeTx Shape
interface HlCopyTradeTx {
coin: string;
px: string;
sz: string;
side: string;
time: number;
closedPnl: string;
oid: string;
dir: string;
copyTradeName: string;
traderTxHash: string;
traderSize: string;
traderPrice: string;
traderWallet: string;
}
Write Endpoints (ComputedData Auth)
Create an HL Perp Copy Trade
await skill.createHlCopyTrade({
apiKey,
userId,
sessionPrivateKey,
traderWallet: '0xTraderEvmAddress',
copyTradeName: 'BTC Whale Follower',
copyMode: 1,
fixedAmountCostPerOrder: '50',
lossPercent: '25',
profitPercent: '100',
oppositeCopy: false,
});
ABI Schema (hl_create, 8 fields, ALL strings):
| # | Field | Type | Description |
|---|
| 0 | traderWallet | string | EVM address to copy |
| 1 | copyTradeName | string | Human-readable label |
| 2 | copyMode | string | "1" or "2" |
| 3 | fixedAmountCostPerOrder | string | USD amount (mode 1) or ratio (mode 2) |
| 4 | lossPercent | string | Stop-loss % |
| 5 | profitPercent | string | Take-profit % |
| 6 | nonce | string | Auto-generated |
| 7 | oppositeCopy | string | "1" or "" |
Update an HL Perp Copy Trade
await skill.updateHlCopyTrade({
apiKey,
userId,
sessionPrivateKey,
copyTradeId: 'abc123...',
traderWallet: '0xTraderEvmAddress',
copyTradeName: 'BTC Whale (Updated)',
copyMode: 2,
fixedAmountCostPerOrder: '0.5',
lossPercent: '30',
profitPercent: '150',
oppositeCopy: true,
});
Delete an HL Perp Copy Trade
Use either isDelete or isChangeStatus — both permanently delete the trade.
await skill.updateHlCopyTrade({
...existingParams,
isDelete: true,
});
⚠️ WARNING: isChangeStatus also PERMANENTLY DELETES the trade.
Despite the name suggesting a toggle, isChangeStatus behaves identically to isDelete
on the current backend. This matches Solana copy trade behavior.
ABI Schema (hl_update, 11 fields, ALL strings):
| # | Field | Type | Description |
|---|
| 0 | traderWallet | string | EVM address |
| 1 | copyTradeName | string | Label |
| 2 | copyMode | string | "1" or "2" |
| 3 | fixedAmountCostPerOrder | string | Amount or ratio |
| 4 | lossPercent | string | Stop-loss % |
| 5 | profitPercent | string | Take-profit % |
| 6 | nonce | string | Auto-generated |
| 7 | isDelete | string | "1" or "" |
| 8 | isChangeStatus | string | "1" or "" |
| 9 | copyTradeId | string | Existing trade ID |
| 10 | oppositeCopy | string | "1" or "" |
Backend Quirks (Live E2E Findings)
These are verified behaviors observed during live E2E testing.
-
copyMode in responses is the ABI byte-offset, not the actual value. For hl_create (8 fields) the offset is 416; for hl_update (11 fields) it's 480. The actual copy mode value (1 or 2) exists in the ABI data but the backend stores the offset instead.
-
oppositeCopy in responses is always true for the same ABI-offset reason. The offset slot is always a non-zero number (736 for create, 960 for update), which the backend interprets as truthy.
-
Both isDelete and isChangeStatus permanently DELETE the copy trade. isChangeStatus does NOT toggle isActive on/off. This matches Solana copy trade behavior exactly.
-
user_stats requires the MANAGED wallet address (userWallet from the copy trade config), not the control wallet address. The control wallet and external trader wallets return {"code":103,"error":"Wallet not found"}.
-
Discovery endpoints use different query params:
user_stats: ?user=<address> (managed wallet only)
clearinghouse_state, clearinghouse_state_all: ?address=<address>
open_orders, open_orders_all: ?address=<address>
usdc_balance: ?address=<address>
-
top_traders_by_pnl returns nested structure: { day: [...], week: [...], month: [...] } where each entry has ethAddress, accountValue, and windowPerformances.
-
deposit_tokens response keys are chain IDs (e.g., "42161" for Arbitrum), not chain names. Each token includes name, symbol, address, chainId, decimals, minDeposit, HLReceiver.
Backend Validation Rules
- TP/SL mandatory: Both
lossPercent > 0 (and < 100) and profitPercent > 0
- Copy modes: Mode 1 = fixed USD per order, Mode 2 = proportion of trader's size
- Max copies: Default 3 per user (
hyperLiquidConfig.maxFuturesCopy)
- No self-copy: Can't copy your own wallet
- Circular dependency: Full DFS graph cycle detection (A→B→C→A prevented)
- No duplicates: Can't copy the same trader wallet twice
How Copies Execute
Copies are NOT executed at API call time. A background watcher monitors tracked traders:
- Detects trader's new perp position (open/close/modify)
- Calculates your position size based on copyMode
- Opens/closes a mirrored position (or opposite if
oppositeCopy=true)
- Applies TP/SL based on your lossPercent/profitPercent settings
- Tracks fill in
HLCopyTradeTrack collection for tx_list
Example: Full HL Perp Copy Trading Flow
import {
GdexSkill,
buildGdexUserSessionData,
generateGdexSessionKeyPair,
buildGdexSignInMessage,
buildGdexSignInComputedData,
} from '@gdexsdk/gdex-skill';
import { ethers } from 'ethers';
const skill = new GdexSkill();
skill.loginWithApiKey(apiKey);
const wallet = ethers.Wallet.fromPhrase(mnemonic);
const { sessionPrivateKey, sessionKey } = generateGdexSessionKeyPair();
const nonce = String(Date.now());
const msg = buildGdexSignInMessage(wallet.address, nonce, sessionKey);
const sig = await wallet.signMessage(msg);
const payload = buildGdexSignInComputedData({
apiKey, userId: wallet.address, sessionKey, nonce, signature: sig,
});
await skill.signInWithComputedData({ computedData: payload.computedData, chainId: 1 });
const data = buildGdexUserSessionData(sessionKey, apiKey);
const userId = wallet.address.toLowerCase();
const topTraders = await skill.getHlTopTradersByPnl();
const bestTrader = topTraders.topTraders[0];
console.log(`Top trader: ${bestTrader.address}, volume: $${bestTrader.volume}`);
const stats = await skill.getHlUserStats(bestTrader.address);
console.log(`30d PnL: $${stats.userStats['30d']}`);
await skill.createHlCopyTrade({
apiKey,
userId,
sessionPrivateKey,
traderWallet: bestTrader.address,
copyTradeName: `Top PnL: ${bestTrader.address.slice(0, 8)}`,
copyMode: 1,
fixedAmountCostPerOrder: '25',
lossPercent: '30',
profitPercent: '100',
});
const list = await skill.getHlCopyTradeList({ userId, data });
for (const ct of list.allCopyTrades) {
console.log(`${ct.copyTradeName}: active=${ct.isActive}, trades=${ct.totalTrades}, PnL=$${ct.totalPnl}`);
}
const fills = await skill.getHlCopyTradeTxList({ userId, data, limit: '20' });
for (const tx of fills.txes) {
console.log(`${tx.coin} ${tx.dir}: ${tx.sz} @ $${tx.px}, PnL=${tx.closedPnl}`);
}
Autonomous Agent Notes (Live-Tested)
getHlUserStats() requires the MANAGED wallet address. Passing the control address or any external trader address returns 400 "Wallet not found". Use the managed EVM address from /v1/user?chainId=1.
- All 7 other discovery endpoints (topTraders, topTradersByPnl, allAssets, perpDexes, depositTokens, clearinghouseState, openOrders) work with the control address or any external address. Only
user_stats has the managed-address requirement.
- Don't trust
copyMode or oppositeCopy in API responses. The backend returns ABI byte-offsets (416, 480, 736, etc.) instead of the real values. Store your own copy trade configs locally.
- To pause a copy trade, you must delete and recreate it. There is no toggle endpoint —
isChangeStatus deletes permanently.
- Sign-in for HL copy trading must use
chainId: 1 (EVM), not 622112261 (Solana).
Related Skills
- gdex-authentication — Auth setup and sign-in required for read/write
- gdex-copy-trading — Solana spot copy trading (separate system)
- gdex-perp-trading — HL perp order management, positions, leverage
- gdex-perp-funding — Deposit/withdraw USDC to HL account
- gdex-portfolio — Monitor portfolio including copied positions