Skip to main content

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: preparesignsubmit.

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

FieldTypeRequiredNotes
kind"increase" | "decrease" | "swap"Yes
symbolstringYesMarket symbol, e.g. "ETH/USD [WETH-USDC]"
direction"long" | "short"For increase/decrease
orderType"market" | "limit" | "stop-market" | "take-profit" | "stop-loss" | "twap"Yes
sizebigintYesUSD value with 30 decimals for positions; token decimals for swaps
triggerPricebigintFor limit/conditional30 decimals
slippagenumberNoBasis points
collateralTokenstringNoToken symbol for position collateral
collateralToPay{ amount: bigint, token: string }For increase/swapToken amount in native decimals
receiveTokenstringFor swap/decreaseToken symbol to receive
keepLeveragebooleanNoFor decrease — withdraw collateral proportionally
manualSwapPathstring[]NoOverride auto swap path with market addresses
acceptablePriceImpactBpsbigintNoAcceptable price impact in basis points
executionFeeBufferBpsnumberNoExecution fee buffer in basis points
twapConfig{ duration: number, parts: number }For TWAPparts: 2–30, duration in seconds
tpslArray<{ type, triggerPrice, size? }>NoTP/SL sidecar orders (increase only)
gasPaymentTokenstringNoToken for gas payment
mode"express" | "classic"Yes
fromstringYesSender address
subaccountAddressstringNoFor 1CT
subaccountApprovalobjectNoFor 1CT

OrderEstimates

Returned in prepared.estimates:

FieldTypeDescription
sizeDeltaUsdbigintPosition size delta (30 decimals)
executionFeeAmountbigintExecution fee in gas token
positionFeeUsdbigintPosition fee (30 decimals)
acceptablePricebigintWorst acceptable execution price (30 decimals)
positionPriceImpactDeltaUsdbigintPosition price impact (30 decimals)
swapPriceImpactDeltaUsdbigintSwap price impact (30 decimals)
borrowingFeeUsdbigintBorrowing fee (30 decimals)
fundingFeeUsdbigintFunding fee (30 decimals)

OrderStatusResponse

FieldTypeDescription
requestIdstringRequest identifier
statusstringSee status values above
txHashstring?Relay transaction hash
createdTxnHashstring?On-chain order creation tx
executionTxnHashstring?On-chain execution tx
orderKeysstring[]?Created order keys
cancellationReasonstring?Why the order was cancelled
error{ code, message }?Error details