Order Management
Place, cancel, and manage orders with full TypeScript examples
Order Management
This guide covers all order management operations in the TypeScript SDK, including order placement, cancellation, and status tracking.
Order Types
The SDK supports the following order types:
enum OrderType {
LIMIT = 0, // Order at specific price
MARKET = 1, // Execute at best available price
STOP = 2, // Trigger when price reaches stop
STOP_LIMIT = 3, // Stop that becomes limit order
ICEBERG = 4, // Hidden quantity order
PEG = 5 // Pegged to best bid/ask
}Placing Orders
Limit Order
A limit order executes at a specific price or better:
import { DEX, OrderType, OrderSide, TimeInForce } from '@luxfi/trading'
async function placeLimitOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
try {
// Using convenience method
const order = await dex.limitBuy('BTC-USD', '0.5', '50000')
console.log('Order ID:', order.orderId)
console.log('Status:', order.status)
} catch (error) {
console.error('Order placement failed:', error)
}
}Market Order
A market order executes immediately at the best available price:
import { DEX } from '@luxfi/trading'
async function placeMarketOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
try {
// Market buy
const order = await dex.buy('BTC-USD', '1.0')
console.log('Market order executed:', order.orderId)
} catch (error) {
console.error('Market order failed:', error)
}
}Stop Order
A stop order triggers when the market price reaches the stop price:
import { DEX } from '@luxfi/trading'
async function placeStopOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
try {
// Stop-loss order: Sell when price drops to 48000
const order = await dex.stopLoss('BTC-USD', '0.5', '48000')
console.log('Stop order placed:', order.orderId)
} catch (error) {
console.error('Stop order failed:', error)
}
}Stop-Limit Order
A stop-limit order becomes a limit order when triggered:
import { DEX, OrderSide } from '@luxfi/trading'
interface StopLimitParams {
symbol: string
side: OrderSide
stopPrice: string
limitPrice: string
size: string
}
async function placeStopLimitOrder(params: StopLimitParams): Promise<string> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
const order = await dex.stopLimit(
params.symbol,
params.side,
params.size,
params.stopPrice,
params.limitPrice
)
return order.orderId
}
// Example: Buy BTC when price rises above 51000, but limit to 51500
placeStopLimitOrder({
symbol: 'BTC-USD',
side: OrderSide.BUY,
stopPrice: '51000',
limitPrice: '51500',
size: '0.25'
})Iceberg Order
An iceberg order hides the full order quantity:
import { DEX, OrderSide } from '@luxfi/trading'
async function placeIcebergOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
try {
const order = await dex.iceberg('BTC-USD', OrderSide.BUY, '10.0', '50000', {
displaySize: '1.0' // Show only 1 BTC at a time
})
console.log('Iceberg order placed:', order.orderId)
} catch (error) {
console.error('Iceberg order failed:', error)
}
}Time in Force Options
Control how long an order remains active:
enum TimeInForce {
GTC = 'GTC', // Good Till Cancelled - remains until filled or cancelled
IOC = 'IOC', // Immediate Or Cancel - fill what you can, cancel rest
FOK = 'FOK', // Fill Or Kill - fill entirely or cancel entirely
DAY = 'DAY' // Day Order - expires at end of trading day
}IOC Order Example
import { DEX, TimeInForce } from '@luxfi/trading'
async function placeIOCOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
// IOC: Execute immediately, cancel unfilled portion
const order = await dex.limitBuy('BTC-USD', '1.0', '50000', {
timeInForce: TimeInForce.IOC
})
console.log('IOC order result:', order)
// Check if fully filled or partially filled
}FOK Order Example
import { DEX, TimeInForce } from '@luxfi/trading'
async function placeFOKOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
// FOK: Must fill entirely or reject
const order = await dex.limitBuy('BTC-USD', '1.0', '50000', {
timeInForce: TimeInForce.FOK
})
if (order.status === 'filled') {
console.log('Order fully filled')
} else {
console.log('Order rejected - could not fill entirely')
}
}Order Options
Post-Only Orders
Post-only orders only add liquidity (maker orders):
import { DEX } from '@luxfi/trading'
async function placePostOnlyOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
const order = await dex.limitBuy('BTC-USD', '0.5', '49900', {
postOnly: true // Reject if would take liquidity
})
console.log('Post-only order:', order.orderId)
}Reduce-Only Orders
Reduce-only orders can only reduce an existing position:
import { DEX } from '@luxfi/trading'
async function placeReduceOnlyOrder(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
// Close or reduce long position
const order = await dex.limitSell('BTC-USD', '0.5', '51000', {
reduceOnly: true // Cannot increase position
})
console.log('Reduce-only order:', order.orderId)
}Cancelling Orders
Cancel Single Order
import { DEX } from '@luxfi/trading'
async function cancelOrder(orderId: string): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
try {
const result = await dex.cancelOrder(orderId)
if (result.success) {
console.log('Order cancelled successfully')
} else {
console.log('Cancel failed:', result.message)
}
} catch (error) {
console.error('Cancel error:', error)
}
}
// Usage
cancelOrder('12345')Cancel Multiple Orders
import { DEX } from '@luxfi/trading'
async function cancelMultipleOrders(orderIds: string[]): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
const results = await Promise.allSettled(
orderIds.map(id => dex.cancelOrder(id))
)
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Order ${orderIds[index]}: cancelled`)
} else {
console.log(`Order ${orderIds[index]}: failed - ${result.reason}`)
}
})
}
// Usage
cancelMultipleOrders(['12345', '12346', '12347'])Querying Orders
Get Single Order
import { DEX, Order } from '@luxfi/trading'
async function getOrderDetails(orderId: string): Promise<Order> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
const order = await dex.getOrder(orderId)
console.log('Order Details:')
console.log(' ID:', order.orderId)
console.log(' Symbol:', order.symbol)
console.log(' Type:', order.type)
console.log(' Side:', order.side === 0 ? 'BUY' : 'SELL')
console.log(' Price:', order.price)
console.log(' Size:', order.size)
console.log(' Filled:', order.filled)
console.log(' Remaining:', order.remaining)
console.log(' Status:', order.status)
console.log(' Timestamp:', new Date(order.timestamp!))
return order
}Order Builder Pattern
For complex order creation, use a builder pattern:
import { Client, Order, OrderType, OrderSide, TimeInForce } from '@luxfi/trading'
class OrderBuilder {
private order: Partial<Order> = {}
symbol(symbol: string): OrderBuilder {
this.order.symbol = symbol
return this
}
limit(): OrderBuilder {
this.order.type = OrderType.LIMIT
return this
}
market(): OrderBuilder {
this.order.type = OrderType.MARKET
return this
}
buy(): OrderBuilder {
this.order.side = OrderSide.BUY
return this
}
sell(): OrderBuilder {
this.order.side = OrderSide.SELL
return this
}
price(price: string): OrderBuilder {
this.order.price = price
return this
}
size(size: string): OrderBuilder {
this.order.size = size
return this
}
gtc(): OrderBuilder {
this.order.timeInForce = TimeInForce.GTC
return this
}
ioc(): OrderBuilder {
this.order.timeInForce = TimeInForce.IOC
return this
}
fok(): OrderBuilder {
this.order.timeInForce = TimeInForce.FOK
return this
}
postOnly(): OrderBuilder {
this.order.postOnly = true
return this
}
reduceOnly(): OrderBuilder {
this.order.reduceOnly = true
return this
}
build(): Partial<Order> {
if (!this.order.symbol) throw new Error('Symbol is required')
if (this.order.type === undefined) throw new Error('Type is required')
if (this.order.side === undefined) throw new Error('Side is required')
if (!this.order.size) throw new Error('Size is required')
if (this.order.type === OrderType.LIMIT && !this.order.price) {
throw new Error('Price is required for limit orders')
}
return this.order
}
}
// Usage
async function placeOrderWithBuilder(): Promise<void> {
const client = new Client({ rpcUrl: 'http://localhost:8080/rpc' })
const order = new OrderBuilder()
.symbol('BTC-USD')
.limit()
.buy()
.price('50000')
.size('0.5')
.gtc()
.postOnly()
.build()
const result = await client.placeOrder(order)
console.log('Order placed:', result.orderId)
}Error Handling
Handle order-related errors appropriately:
import { DEX } from '@luxfi/trading'
interface OrderError extends Error {
code?: string
details?: Record<string, unknown>
}
async function placeOrderWithErrorHandling(): Promise<void> {
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
try {
const order = await dex.limitBuy('BTC-USD', '1.0', '50000')
console.log('Order successful:', order.orderId)
} catch (error) {
const orderError = error as OrderError
// Handle specific error cases
if (orderError.message.includes('insufficient')) {
console.error('Insufficient balance to place order')
} else if (orderError.message.includes('rate limit')) {
console.error('Rate limit exceeded - waiting before retry')
} else if (orderError.message.includes('invalid symbol')) {
console.error('Invalid trading pair')
} else if (orderError.message.includes('market closed')) {
console.error('Market is currently closed')
} else {
console.error('Order failed:', orderError.message)
}
}
}Batch Order Operations
Place multiple orders efficiently:
import { Client, Order, OrderType, OrderSide } from '@luxfi/trading'
interface BatchOrderResult {
successful: Array<{ orderId: string; index: number }>
failed: Array<{ error: Error; index: number }>
}
async function placeBatchOrders(orders: Partial<Order>[]): Promise<BatchOrderResult> {
const client = new Client({ rpcUrl: 'http://localhost:8080/rpc' })
const results = await Promise.allSettled(
orders.map(order => client.placeOrder(order))
)
const successful: Array<{ orderId: string; index: number }> = []
const failed: Array<{ error: Error; index: number }> = []
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
successful.push({ orderId: result.value.orderId, index })
} else {
failed.push({ error: result.reason, index })
}
})
console.log(`Batch result: ${successful.length} successful, ${failed.length} failed`)
return { successful, failed }
}
// Usage: Place grid orders
async function placeGridOrders(): Promise<void> {
const basePrice = 50000
const gridSize = 5
const gridSpacing = 100
const orderSize = '0.1'
const buyOrders: Partial<Order>[] = []
const sellOrders: Partial<Order>[] = []
for (let i = 1; i <= gridSize; i++) {
// Buy orders below current price
buyOrders.push({
symbol: 'BTC-USD',
type: OrderType.LIMIT,
side: OrderSide.BUY,
price: String(basePrice - (i * gridSpacing)),
size: orderSize
})
// Sell orders above current price
sellOrders.push({
symbol: 'BTC-USD',
type: OrderType.LIMIT,
side: OrderSide.SELL,
price: String(basePrice + (i * gridSpacing)),
size: orderSize
})
}
const allOrders = [...buyOrders, ...sellOrders]
const result = await placeBatchOrders(allOrders)
console.log('Grid orders placed:', result.successful.length)
}Next Steps
- Order Book - Access real-time order book data
- Trade History - Query executed trades
- WebSocket Guide - Real-time order updates