Order Examples
This page shows how to create, edit, cancel, and track orders using GmxApiSdk. All examples assume Arbitrum (chainId: 42161).
Setup
import { GmxApiSdk, PrivateKeySigner } from "@gmx-io/sdk/v2";
const sdk = new GmxApiSdk({ chainId: 42161 });
// For signing orders — PrivateKeySigner wraps viem's privateKeyToAccount
const signer = new PrivateKeySigner("0xYOUR_PRIVATE_KEY");
const account = signer.address;
IAbstractSigner is the minimal interface the SDK needs. You can implement it with any wallet:
import type { IAbstractSigner } from "@gmx-io/sdk/v2";
const walletSigner: IAbstractSigner = {
address: "0x...",
async signTypedData(domain, types, value) {
return wallet.signTypedData({ domain, types, message: value });
},
async signMessage(message) {
return wallet.signMessage({ message });
},
// Optional - only needed for classic mode
async sendTransaction(tx) {
return wallet.sendTransaction(tx);
},
};
Discovering markets and prices
Before creating orders, you need to know which markets exist and what prices to use. The symbol field used in order requests (e.g. "ETH/USD [WETH-USDC]") comes from the market data.
List available markets
const markets = await sdk.fetchMarkets();
for (const m of markets) {
console.log(m.symbol); // "ETH/USD [WETH-USDC]"
console.log(m.marketTokenAddress); // "0x70d95587d40A2caf56bd97485aB3Eec10Bee6336"
console.log(m.isSpotOnly); // false (perp market) or true (spot only)
console.log(m.leverageTiers); // [{ maxLeverage, minCollateralFactor, maxPositionSize }]
console.log(m.minPositionSizeUsd); // Minimum position size (30 decimals)
console.log(m.minCollateralUsd); // Minimum collateral (30 decimals)
}
Get current prices and market data
// All markets
const tickers = await sdk.fetchMarketsTickers();
// Filter by symbol
const ethTickers = await sdk.fetchMarketsTickers({
symbols: ["ETH/USD [WETH-USDC]"],
});
// Filter by market address
const filtered = await sdk.fetchMarketsTickers({
addresses: ["0x70d95587d40A2caf56bd97485aB3Eec10Bee6336"],
});
const ticker = ethTickers[0];
console.log(ticker.symbol); // "ETH/USD [WETH-USDC]"
console.log(ticker.markPrice); // Current mark price (30 decimals)
console.log(ticker.maxPrice); // Max price
console.log(ticker.minPrice); // Min price
console.log(ticker.high24h); // 24h high
console.log(ticker.low24h); // 24h low
console.log(ticker.priceChangePercent24hBps); // 24h change in bps
console.log(ticker.longInterestUsd); // Open interest long (30 decimals)
console.log(ticker.shortInterestUsd); // Open interest short (30 decimals)
console.log(ticker.availableLiquidityLong);
console.log(ticker.availableLiquidityShort);
console.log(ticker.fundingRateLong); // Current funding rate
console.log(ticker.borrowingRateLong); // Current borrowing rate
Get token info
// Static token catalog (symbols, decimals, addresses)
const tokens = await sdk.fetchTokens();
// Token metadata with current prices
const tokensData = await sdk.fetchTokensData();
Read positions and orders
// Current positions for an account
const positions = await sdk.fetchPositionsInfo({ address: account });
for (const p of positions) {
console.log(p.indexName); // "ETH/USD"
console.log(p.isLong); // true or false
console.log(p.sizeInUsd); // Position size (30-decimal bigint)
console.log(p.collateralUsd); // Collateral value
console.log(p.marketAddress); // Market address
}
// Positions with their related TP/SL orders
const positionsWithOrders = await sdk.fetchPositionsInfo({
address: account,
includeRelatedOrders: true,
});
// Active orders
const orders = await sdk.fetchOrders({ address: account });
for (const o of orders) {
console.log(o.key); // Order key (used for edit/cancel)
console.log(o.isLong);
console.log(o.sizeDeltaUsd); // Size delta (30-decimal bigint)
console.log(o.triggerPrice); // Trigger price for limit/conditional orders
console.log(o.executionFee);
}
Check wallet balances and allowances
const balances = await sdk.fetchWalletBalances({ address: account });
const allowances = await sdk.fetchAllowances({
address: account,
spender: "router",
});
// Build an ERC-20 approval if needed
const approveTx = sdk.buildApproveTransaction({
tokenAddress: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
spender: "router",
amount: 1_000_000_000n, // 1000 USDC
});
// approveTx.to, approveTx.data — send via your wallet
Express orders — three-step flow
Express orders use the API relay (Gelato). The flow is: prepare → sign → submit.
1. Prepare
const prepared = await sdk.prepareOrder({
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n, // $10 (30 decimals)
collateralToken: "USDC",
collateralToPay: { amount: 1_000_000n, token: "USDC" }, // 1 USDC (6 decimals)
mode: "express",
from: account,
});
// prepared.payloadType === "typed-data"
// prepared.estimates contains fee and price impact data
console.log(prepared.estimates);
// {
// sizeDeltaUsd: 10000000000000000000000000000000n,
// executionFeeAmount: ...,
// positionFeeUsd: ...,
// acceptablePrice: ...,
// swapPriceImpactDeltaUsd: ...,
// positionPriceImpactDeltaUsd: ...,
// borrowingFeeUsd: ...,
// fundingFeeUsd: ...,
// }
2. Sign
const signature = await sdk.signOrder(prepared, signer);
3. Submit
const submitted = await sdk.submitOrder({
mode: prepared.mode,
requestId: prepared.requestId,
signature,
from: account,
idempotencyKey: prepared.idempotencyKey,
eip712Data: {
batchParams: prepared.payload.batchParams,
relayParams: prepared.payload.relayParams,
},
});
console.log(submitted.requestId); // Use this to track the order
console.log(submitted.status); // "relay_accepted", "relay_pending", etc.
Express orders — one-call convenience
executeExpressOrder runs prepare + sign + submit in a single call:
const result = await sdk.executeExpressOrder(
{
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n,
collateralToken: "USDC",
collateralToPay: { amount: 1_000_000n, token: "USDC" },
mode: "express",
from: account,
},
signer
);
console.log(result.requestId);
Tracking order status
Poll fetchOrderStatus with the requestId returned from submission:
const status = await sdk.fetchOrderStatus({
requestId: submitted.requestId,
});
console.log(status.status);
// Possible values:
// "prepared" | "relay_accepted" | "relay_pending" | "relay_submitted"
// | "created" | "executed" | "cancelled" | "relay_failed" | "relay_reverted"
// Terminal statuses: "executed", "cancelled", "relay_failed", "relay_reverted"
Polling loop example:
async function waitForExecution(sdk, requestId, timeoutMs = 60_000) {
const terminal = new Set(["executed", "cancelled", "relay_failed", "relay_reverted"]);
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const status = await sdk.fetchOrderStatus({ requestId });
if (terminal.has(status.status)) return status;
await new Promise((r) => setTimeout(r, 2000));
}
throw new Error(`Order ${requestId} did not reach terminal status within ${timeoutMs}ms`);
}
const finalStatus = await waitForExecution(sdk, result.requestId);
// finalStatus.executionTxnHash — on-chain execution tx
// finalStatus.orderKeys — created order keys
// finalStatus.error — error details if failed
Market increase (open / add to position)
Long
await sdk.executeExpressOrder(
{
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 100n * 10n ** 30n, // $100
collateralToken: "USDC",
collateralToPay: { amount: 10_000_000n, token: "USDC" }, // 10 USDC
mode: "express",
from: account,
},
signer
);
Short
await sdk.executeExpressOrder(
{
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "short",
orderType: "market",
size: 100n * 10n ** 30n,
collateralToken: "USDC",
collateralToPay: { amount: 10_000_000n, token: "USDC" },
mode: "express",
from: account,
},
signer
);
Limit increase
Set triggerPrice for the entry price. The order stays open until the price is reached.
const result = await sdk.executeExpressOrder(
{
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "limit",
size: 10n * 10n ** 30n,
triggerPrice: 2000n * 10n ** 30n, // $2,000 entry
collateralToken: "USDC",
collateralToPay: { amount: 1_000_000n, token: "USDC" },
mode: "express",
from: account,
},
signer
);
// The order is created on-chain; verify it appears in your orders list
const orders = await sdk.fetchOrders({ address: account });
Market decrease (close / reduce position)
Partial close
// Get current position size
const positions = await sdk.fetchPositionsInfo({ address: account });
const ethLong = positions.find((p) => p.isLong && p.indexName?.includes("ETH/USD"));
const currentSize = BigInt(ethLong.sizeInUsd);
await sdk.executeExpressOrder(
{
kind: "decrease",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: currentSize / 2n, // Close half
collateralToken: "USDC",
receiveToken: "USDC",
mode: "express",
from: account,
},
signer
);
Full close
await sdk.executeExpressOrder(
{
kind: "decrease",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: currentSize, // Close entire position
collateralToken: "USDC",
receiveToken: "USDC",
mode: "express",
from: account,
},
signer
);
keepLeverage
When decreasing, keepLeverage controls whether collateral is withdrawn proportionally:
// keepLeverage: true — removes collateral proportionally, preserving leverage ratio
await sdk.executeExpressOrder(
{
kind: "decrease",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: currentSize / 5n,
keepLeverage: true,
collateralToken: "USDC",
receiveToken: "USDC",
mode: "express",
from: account,
},
signer
);
// keepLeverage: false — keeps collateral, reducing leverage
receiveToken
Choose which token to receive when closing:
await sdk.executeExpressOrder(
{
kind: "decrease",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: currentSize,
collateralToken: "USDC",
receiveToken: "ETH", // Receive ETH instead of USDC
mode: "express",
from: account,
},
signer
);
Conditional decrease (stop-loss / take-profit)
Stop-loss
const result = await sdk.executeExpressOrder(
{
kind: "decrease",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "stop-loss",
size: 10n * 10n ** 30n,
triggerPrice: 1800n * 10n ** 30n, // Trigger at $1,800
collateralToken: "USDC",
receiveToken: "USDC",
mode: "express",
from: account,
},
signer
);
Take-profit
const result = await sdk.executeExpressOrder(
{
kind: "decrease",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "take-profit",
size: 10n * 10n ** 30n,
triggerPrice: 5000n * 10n ** 30n, // Trigger at $5,000
collateralToken: "USDC",
receiveToken: "USDC",
mode: "express",
from: account,
},
signer
);
TP/SL with position entry
Attach take-profit and stop-loss orders when opening a position using tpsl:
// Get current mark price for TP/SL calculation
const tickers = await sdk.fetchMarketsTickers({ symbols: ["ETH/USD [WETH-USDC]"] });
const markPrice = BigInt(tickers[0].maxPrice);
await sdk.executeExpressOrder(
{
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n,
collateralToken: "USDC",
collateralToPay: { amount: 1_000_000n, token: "USDC" },
mode: "express",
from: account,
tpsl: [
{ type: "take-profit", triggerPrice: markPrice * 105n / 100n, size: 10n * 10n ** 30n },
{ type: "stop-loss", triggerPrice: markPrice * 95n / 100n, size: 10n * 10n ** 30n },
],
},
signer
);
tpsl supports partial-size TP/SL — omit size to use the full position size. tpsl is only valid on increase orders with market or limit order types. It cannot be used with twap, decrease, or swap orders.
Swap orders
await sdk.executeExpressOrder(
{
kind: "swap",
symbol: "ETH/USD [WETH-USDC]",
orderType: "market",
size: 1_000_000n, // 1 USDC (token decimals)
collateralToPay: { amount: 1_000_000n, token: "USDC" },
receiveToken: "ETH",
mode: "express",
from: account,
},
signer
);
TWAP orders
Split a large order into multiple parts executed over time:
await sdk.executeExpressOrder(
{
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "twap",
size: 20n * 10n ** 30n, // $20 total
collateralToken: "USDC",
collateralToPay: { amount: 3_000_000n, token: "USDC" },
twapConfig: { duration: 600, parts: 2 }, // 2 parts over 10 minutes
mode: "express",
from: account,
},
signer
);
twapConfig.parts must be between 2 and 30 inclusive. twapConfig.duration must be greater than 0. TWAP cannot be combined with tpsl.
Edit orders
Change the trigger price (or size) of an existing limit/conditional order:
const orders = await sdk.fetchOrders({ address: account });
const orderId = orders[0].key;
const prepared = await sdk.prepareEditOrder({
orderIds: [orderId],
newTriggerPrice: 2500n * 10n ** 30n, // New trigger: $2,500
mode: "express",
from: account,
});
const signature = await sdk.signOrder(prepared, signer);
const submitted = await sdk.submitOrder({
mode: prepared.mode,
requestId: prepared.requestId,
signature,
from: account,
idempotencyKey: prepared.idempotencyKey,
eip712Data: {
batchParams: prepared.payload.batchParams,
relayParams: prepared.payload.relayParams,
},
});
prepareEditOrder accepts newSize, newTriggerPrice, newAcceptablePrice, newAutoCancel, and executionFeeTopUp.
Cancel orders
Cancel specific orders
const orders = await sdk.fetchOrders({ address: account });
const orderId = orders[0].key;
const prepared = await sdk.prepareCancelOrder({
orderIds: [orderId],
mode: "express",
from: account,
});
const signature = await sdk.signOrder(prepared, signer);
await sdk.submitOrder({
mode: prepared.mode,
requestId: prepared.requestId,
signature,
from: account,
idempotencyKey: prepared.idempotencyKey,
eip712Data: {
batchParams: prepared.payload.batchParams,
relayParams: prepared.payload.relayParams,
},
});
Cancel all orders
const prepared = await sdk.prepareCancelOrder({
all: true,
mode: "express",
from: account,
});
const signature = await sdk.signOrder(prepared, signer);
await sdk.submitOrder({
mode: prepared.mode,
requestId: prepared.requestId,
signature,
from: account,
idempotencyKey: prepared.idempotencyKey,
eip712Data: {
batchParams: prepared.payload.batchParams,
relayParams: prepared.payload.relayParams,
},
});
Classic mode (on-chain transactions)
Classic mode returns raw transaction calldata instead of typed data. You sign and broadcast the transaction yourself — no relay is involved.
const prepared = await sdk.prepareOrder({
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n,
collateralToken: "USDC",
collateralToPay: { amount: 1_000_000n, token: "USDC" },
mode: "classic",
from: account,
});
// prepared.payloadType === "transaction"
// prepared.payload.to — contract address
// prepared.payload.data — calldata
// prepared.payload.value — ETH value (execution fee)
// Send with your wallet / viem / ethers:
const txHash = await signer.sendTransaction({
to: prepared.payload.to,
data: prepared.payload.data,
value: BigInt(prepared.payload.value ?? 0),
});
PrivateKeySigner.sendTransaction requires rpcUrl in the constructor:
import { getViemChain } from "@gmx-io/sdk/configs/chains";
const signer = new PrivateKeySigner("0xYOUR_PRIVATE_KEY", {
rpcUrl: "https://arb1.arbitrum.io/rpc",
chain: getViemChain(42161),
});
Slippage and execution fee buffer
Slippage
Controls the acceptable price deviation in basis points (default varies by order type). Higher slippage widens the acceptable price range without affecting size or fee estimates.
const prepared = await sdk.prepareOrder({
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n,
collateralToPay: { amount: 1_000_000n, token: "USDC" },
slippage: 30, // 0.3% (in basis points)
mode: "express",
from: account,
});
Execution fee buffer
Adds a buffer to the execution fee in basis points. Higher buffer reduces the chance of order failure due to gas spikes.
const prepared = await sdk.prepareOrder({
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n,
collateralToPay: { amount: 1_000_000n, token: "USDC" },
executionFeeBufferBps: 5000, // 50% buffer
mode: "express",
from: account,
});
One-click trading (subaccounts)
Subaccounts let you sign orders with a derived key, avoiding wallet popups for each trade. The main wallet signs a one-time approval.
Quick setup
// Generate and activate in one call
const subaccountAddress = await sdk.activateSubaccount(signer, {
expiresInSeconds: 86400, // 24 hours
maxAllowedCount: 100, // Max 100 actions
});
console.log(sdk.subaccountAddress); // "0x..."
console.log(sdk.hasActiveSubaccount); // true
Submit orders with subaccount
Once activated, executeExpressOrder automatically uses the subaccount signer:
const result = await sdk.executeExpressOrder(
{
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n,
collateralToken: "USDC",
collateralToPay: { amount: 1_000_000n, token: "USDC" },
mode: "express",
from: account, // Main account address
},
signer // Main signer (SDK uses subaccount internally)
);
Manual subaccount flow
For more control, pass subaccountAddress and subaccountApproval explicitly:
const prepared = await sdk.prepareOrder({
kind: "increase",
symbol: "ETH/USD [WETH-USDC]",
direction: "long",
orderType: "market",
size: 10n * 10n ** 30n,
collateralToken: "USDC",
collateralToPay: { amount: 1_000_000n, token: "USDC" },
mode: "express",
from: account,
subaccountAddress: sdk.subaccountAddress,
subaccountApproval: sdk.subaccountApprovalMessage,
});
const signature = await sdk.signOrder(prepared, signer);
const submitted = await sdk.submitOrder({
mode: prepared.mode,
requestId: prepared.requestId,
signature,
from: account,
idempotencyKey: prepared.idempotencyKey,
eip712Data: {
batchParams: prepared.payload.batchParams,
relayParams: prepared.payload.relayParams,
subaccountApproval: sdk.subaccountApprovalMessage,
},
});
Step-by-step setup
// 1. Generate subaccount (deterministic from main signer)
const subAddr = await sdk.generateSubaccount(signer);
// 2. Check on-chain status
const status = await sdk.fetchSubaccountStatus({
account: signer.address,
subaccountAddress: subAddr,
});
// 3. Activate with custom limits
await sdk.activateSubaccount(signer, {
expiresInSeconds: 86400,
maxAllowedCount: Number(status.currentActionsCount) + 50,
});
// 4. Clear when done
sdk.clearSubaccount();
Collateral management
Deposit or withdraw collateral on an existing position using prepareCollateral:
const prepared = await sdk.prepareCollateral({
operation: "deposit", // or "withdraw"
positionKey: "0x...", // Position key from fetchPositionsInfo
amount: 5_000_000n, // 5 USDC (token decimals)
mode: "express",
from: account,
});
const signature = await sdk.signOrder(prepared, signer);
await sdk.submitOrder({
mode: prepared.mode,
requestId: prepared.requestId,
signature,
from: account,
idempotencyKey: prepared.idempotencyKey,
eip712Data: {
batchParams: prepared.payload.batchParams,
relayParams: prepared.payload.relayParams,
},
});
prepareCollateral also accepts optional slippage, executionFeeBufferBps, and gasPaymentToken parameters.
Type reference
PrepareOrderRequest
| Field | Type | Required | Notes |
|---|---|---|---|
kind | "increase" | "decrease" | "swap" | Yes | |
symbol | string | Yes | Market symbol, e.g. "ETH/USD [WETH-USDC]" |
direction | "long" | "short" | For increase/decrease | |
orderType | "market" | "limit" | "stop-market" | "take-profit" | "stop-loss" | "twap" | Yes | |
size | bigint | Yes | USD value with 30 decimals for positions; token decimals for swaps |
triggerPrice | bigint | For limit/conditional | 30 decimals |
slippage | number | No | Basis points |
collateralToken | string | No | Token symbol for position collateral |
collateralToPay | { amount: bigint, token: string } | For increase/swap | Token amount in native decimals |
receiveToken | string | For swap/decrease | Token symbol to receive |
keepLeverage | boolean | No | For decrease — withdraw collateral proportionally |
manualSwapPath | string[] | No | Override auto swap path with market addresses |
acceptablePriceImpactBps | bigint | No | Acceptable price impact in basis points |
executionFeeBufferBps | number | No | Execution fee buffer in basis points |
twapConfig | { duration: number, parts: number } | For TWAP | parts: 2–30, duration in seconds |
tpsl | Array<{ type, triggerPrice, size? }> | No | TP/SL sidecar orders (increase only) |
gasPaymentToken | string | No | Token for gas payment |
mode | "express" | "classic" | Yes | |
from | string | Yes | Sender address |
subaccountAddress | string | No | For 1CT |
subaccountApproval | object | No | For 1CT |
OrderEstimates
Returned in prepared.estimates:
| Field | Type | Description |
|---|---|---|
sizeDeltaUsd | bigint | Position size delta (30 decimals) |
executionFeeAmount | bigint | Execution fee in gas token |
positionFeeUsd | bigint | Position fee (30 decimals) |
acceptablePrice | bigint | Worst acceptable execution price (30 decimals) |
positionPriceImpactDeltaUsd | bigint | Position price impact (30 decimals) |
swapPriceImpactDeltaUsd | bigint | Swap price impact (30 decimals) |
borrowingFeeUsd | bigint | Borrowing fee (30 decimals) |
fundingFeeUsd | bigint | Funding fee (30 decimals) |
OrderStatusResponse
| Field | Type | Description |
|---|---|---|
requestId | string | Request identifier |
status | string | See status values above |
txHash | string? | Relay transaction hash |
createdTxnHash | string? | On-chain order creation tx |
executionTxnHash | string? | On-chain execution tx |
orderKeys | string[]? | Created order keys |
cancellationReason | string? | Why the order was cancelled |
error | { code, message }? | Error details |