TypeScript SDK

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