Go SDK

Orders

Placing, canceling, and modifying orders with the Go SDK

Order Management

The Go SDK provides comprehensive order management capabilities including limit orders, market orders, stop orders, and advanced order types.

Order Types

TypeDescriptionUse Case
OrderTypeLimitExecute at specific price or betterPrice-sensitive trades
OrderTypeMarketExecute at best available priceImmediate execution
OrderTypeStopTrigger at stop price, execute as marketStop-loss protection
OrderTypeStopLimitTrigger at stop price, execute as limitControlled stop-loss
OrderTypeIcebergHidden quantity orderLarge orders without impact
OrderTypePegPegged to best bid/askMarket making

Placing Orders

Limit Order

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Place a limit buy order
    order := &client.Order{
        Symbol:      "BTC-USD",
        Type:        client.OrderTypeLimit,
        Side:        client.OrderSideBuy,
        Price:       50000.00,
        Size:        0.1,
        UserID:      "trader-001",
        ClientID:    "my-order-001", // Your internal reference
        TimeInForce: client.TimeInForceGTC,
        PostOnly:    false,          // Allow taking liquidity
        ReduceOnly:  false,          // Not for position reduction only
    }

    resp, err := c.PlaceOrder(ctx, order)
    if err != nil {
        log.Fatal("Failed to place order:", err)
    }

    fmt.Printf("Order placed successfully\n")
    fmt.Printf("  Order ID: %d\n", resp.OrderID)
    fmt.Printf("  Status: %s\n", resp.Status)
    if resp.Message != "" {
        fmt.Printf("  Message: %s\n", resp.Message)
    }
}

Market Order

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Place a market sell order
    order := &client.Order{
        Symbol:      "BTC-USD",
        Type:        client.OrderTypeMarket,
        Side:        client.OrderSideSell,
        Size:        0.5,              // Size in base currency
        UserID:      "trader-001",
        ClientID:    "market-sell-001",
        TimeInForce: client.TimeInForceIOC, // Immediate or Cancel
    }

    resp, err := c.PlaceOrder(ctx, order)
    if err != nil {
        log.Fatal("Failed to place order:", err)
    }

    fmt.Printf("Market order executed: ID=%d, Status=%s\n", resp.OrderID, resp.Status)
}

Stop-Loss Order

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Stop-loss: Sell BTC if price drops to $48,000
    order := &client.Order{
        Symbol:      "BTC-USD",
        Type:        client.OrderTypeStop,
        Side:        client.OrderSideSell,
        Price:       48000.00,     // Stop trigger price
        Size:        0.1,
        UserID:      "trader-001",
        ClientID:    "stop-loss-001",
        TimeInForce: client.TimeInForceGTC,
        ReduceOnly:  true,         // Only reduce existing position
    }

    resp, err := c.PlaceOrder(ctx, order)
    if err != nil {
        log.Fatal("Failed to place stop order:", err)
    }

    fmt.Printf("Stop order placed: ID=%d\n", resp.OrderID)
}

Post-Only Order (Maker Only)

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Post-only order: Only add liquidity, never take
    // Rejected if it would immediately match
    order := &client.Order{
        Symbol:      "BTC-USD",
        Type:        client.OrderTypeLimit,
        Side:        client.OrderSideBuy,
        Price:       49500.00,     // Below current ask
        Size:        1.0,
        UserID:      "trader-001",
        ClientID:    "maker-001",
        TimeInForce: client.TimeInForceGTC,
        PostOnly:    true,         // Reject if would take liquidity
    }

    resp, err := c.PlaceOrder(ctx, order)
    if err != nil {
        log.Fatal("Failed to place post-only order:", err)
    }

    if resp.Status == "rejected" {
        fmt.Println("Order would have taken liquidity - rejected")
    } else {
        fmt.Printf("Post-only order placed: ID=%d\n", resp.OrderID)
    }
}

Canceling Orders

Cancel Single Order

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Cancel by order ID
    orderID := uint64(12345)
    if err := c.CancelOrder(ctx, orderID); err != nil {
        log.Printf("Failed to cancel order %d: %v", orderID, err)
        return
    }

    fmt.Printf("Order %d cancelled successfully\n", orderID)
}

Cancel Multiple Orders

package main

import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Orders to cancel
    orderIDs := []uint64{12345, 12346, 12347, 12348}

    // Cancel concurrently with rate limiting
    var wg sync.WaitGroup
    sem := make(chan struct{}, 10) // Max 10 concurrent cancellations
    results := make(chan struct {
        ID  uint64
        Err error
    }, len(orderIDs))

    for _, id := range orderIDs {
        wg.Add(1)
        go func(orderID uint64) {
            defer wg.Done()
            sem <- struct{}{}
            defer func() { <-sem }()

            err := c.CancelOrder(ctx, orderID)
            results <- struct {
                ID  uint64
                Err error
            }{orderID, err}
        }(id)
    }

    // Wait and close results channel
    go func() {
        wg.Wait()
        close(results)
    }()

    // Process results
    var cancelled, failed int
    for result := range results {
        if result.Err != nil {
            fmt.Printf("Failed to cancel order %d: %v\n", result.ID, result.Err)
            failed++
        } else {
            fmt.Printf("Cancelled order %d\n", result.ID)
            cancelled++
        }
    }

    fmt.Printf("\nSummary: %d cancelled, %d failed\n", cancelled, failed)
}

Order Lifecycle

Order with Callback Updates

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithJSONRPCURL("http://localhost:8080"),
        client.WithWebSocketURL("ws://localhost:8081"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
    defer cancel()

    // Connect to WebSocket for order updates
    if err := c.ConnectWebSocket(ctx); err != nil {
        log.Fatal("Failed to connect WebSocket:", err)
    }

    // Channel to receive order updates
    orderUpdates := make(chan *client.Order, 100)

    // Subscribe to user order updates
    err = c.Subscribe("user:orders:trader-001", func(data interface{}) {
        if orderData, ok := data.(map[string]interface{}); ok {
            order := &client.Order{
                OrderID: uint64(orderData["orderId"].(float64)),
                Status:  client.OrderStatus(orderData["status"].(string)),
                Filled:  orderData["filled"].(float64),
            }
            select {
            case orderUpdates <- order:
            default:
                log.Println("Order update channel full, dropping update")
            }
        }
    })
    if err != nil {
        log.Fatal("Failed to subscribe:", err)
    }

    // Place an order
    order := &client.Order{
        Symbol:      "BTC-USD",
        Type:        client.OrderTypeLimit,
        Side:        client.OrderSideBuy,
        Price:       50000.00,
        Size:        1.0,
        UserID:      "trader-001",
        ClientID:    "tracked-order-001",
        TimeInForce: client.TimeInForceGTC,
    }

    resp, err := c.PlaceOrder(ctx, order)
    if err != nil {
        log.Fatal("Failed to place order:", err)
    }

    fmt.Printf("Order placed: ID=%d\n", resp.OrderID)

    // Monitor order updates
    for {
        select {
        case update := <-orderUpdates:
            if update.OrderID == resp.OrderID {
                fmt.Printf("Order update: Status=%s, Filled=%.4f\n",
                    update.Status, update.Filled)

                if update.IsClosed() {
                    fmt.Println("Order completed")
                    return
                }
            }
        case <-ctx.Done():
            fmt.Println("Timeout waiting for order completion")
            return
        }
    }
}

Bulk Order Operations

Place Multiple Orders

package main

import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Create grid of orders
    basePrice := 50000.0
    gridStep := 100.0
    orders := make([]*client.Order, 0, 20)

    // Buy orders below market
    for i := 1; i <= 10; i++ {
        orders = append(orders, &client.Order{
            Symbol:      "BTC-USD",
            Type:        client.OrderTypeLimit,
            Side:        client.OrderSideBuy,
            Price:       basePrice - float64(i)*gridStep,
            Size:        0.01,
            UserID:      "trader-001",
            ClientID:    fmt.Sprintf("grid-buy-%d", i),
            TimeInForce: client.TimeInForceGTC,
        })
    }

    // Sell orders above market
    for i := 1; i <= 10; i++ {
        orders = append(orders, &client.Order{
            Symbol:      "BTC-USD",
            Type:        client.OrderTypeLimit,
            Side:        client.OrderSideSell,
            Price:       basePrice + float64(i)*gridStep,
            Size:        0.01,
            UserID:      "trader-001",
            ClientID:    fmt.Sprintf("grid-sell-%d", i),
            TimeInForce: client.TimeInForceGTC,
        })
    }

    // Place orders concurrently
    var wg sync.WaitGroup
    sem := make(chan struct{}, 20) // Limit concurrency
    results := make(chan *client.OrderResponse, len(orders))
    errors := make(chan error, len(orders))

    for _, order := range orders {
        wg.Add(1)
        go func(o *client.Order) {
            defer wg.Done()
            sem <- struct{}{}
            defer func() { <-sem }()

            resp, err := c.PlaceOrder(ctx, o)
            if err != nil {
                errors <- fmt.Errorf("order %s failed: %w", o.ClientID, err)
            } else {
                results <- resp
            }
        }(order)
    }

    // Wait and close channels
    go func() {
        wg.Wait()
        close(results)
        close(errors)
    }()

    // Collect results
    var placed int
    var orderIDs []uint64
    for resp := range results {
        orderIDs = append(orderIDs, resp.OrderID)
        placed++
    }

    // Collect errors
    var errCount int
    for err := range errors {
        log.Printf("Error: %v", err)
        errCount++
    }

    fmt.Printf("\nGrid orders placed: %d success, %d failed\n", placed, errCount)
    fmt.Printf("Order IDs: %v\n", orderIDs)
}

Order Book Integration

Place Order Based on Order Book

package main

import (
    "context"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    defer cancel()

    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Get current order book
    orderBook, err := c.GetOrderBook(ctx, "BTC-USD", 10)
    if err != nil {
        log.Fatal("Failed to get order book:", err)
    }

    // Place buy order at best bid - $10 (deeper in book)
    buyPrice := orderBook.BestBid() - 10
    if buyPrice <= 0 {
        log.Fatal("Invalid buy price")
    }

    order := &client.Order{
        Symbol:      "BTC-USD",
        Type:        client.OrderTypeLimit,
        Side:        client.OrderSideBuy,
        Price:       buyPrice,
        Size:        0.1,
        UserID:      "trader-001",
        ClientID:    "spread-buy-001",
        TimeInForce: client.TimeInForceGTC,
        PostOnly:    true, // Ensure we add liquidity
    }

    resp, err := c.PlaceOrder(ctx, order)
    if err != nil {
        log.Fatal("Failed to place order:", err)
    }

    fmt.Printf("Order placed at %.2f (spread: %.2f)\n",
        buyPrice, orderBook.Spread())
    fmt.Printf("Order ID: %d\n", resp.OrderID)
}

Error Handling

Comprehensive Error Handling

package main

import (
    "context"
    "errors"
    "fmt"
    "log"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

func placeOrderWithRetry(c *client.Client, order *client.Order, maxRetries int) (*client.OrderResponse, error) {
    var lastErr error

    for attempt := 0; attempt < maxRetries; attempt++ {
        ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)

        resp, err := c.PlaceOrder(ctx, order)
        cancel()

        if err == nil {
            return resp, nil
        }

        lastErr = err

        // Check error type
        if errors.Is(err, context.DeadlineExceeded) {
            // Timeout - order may have been placed
            log.Printf("Attempt %d: timeout (order state unknown)", attempt+1)
            // In production, query order status before retrying
            time.Sleep(time.Second)
            continue
        }

        // Check for specific error conditions
        errStr := err.Error()
        switch {
        case contains(errStr, "insufficient balance"):
            // Don't retry - permanent error
            return nil, fmt.Errorf("insufficient balance: %w", err)

        case contains(errStr, "rate limit"):
            // Rate limited - wait and retry
            log.Printf("Attempt %d: rate limited, waiting...", attempt+1)
            time.Sleep(5 * time.Second)
            continue

        case contains(errStr, "market closed"):
            // Market closed - don't retry
            return nil, fmt.Errorf("market closed: %w", err)

        case contains(errStr, "invalid price"):
            // Invalid price - don't retry
            return nil, fmt.Errorf("invalid price: %w", err)

        case contains(errStr, "connection"):
            // Connection issue - retry
            log.Printf("Attempt %d: connection error, retrying...", attempt+1)
            time.Sleep(time.Duration(attempt+1) * time.Second)
            continue

        default:
            // Unknown error - retry with backoff
            log.Printf("Attempt %d: %v", attempt+1, err)
            time.Sleep(time.Duration(attempt+1) * time.Second)
        }
    }

    return nil, fmt.Errorf("failed after %d attempts: %w", maxRetries, lastErr)
}

func contains(s, substr string) bool {
    return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsImpl(s, substr))
}

func containsImpl(s, substr string) bool {
    for i := 0; i <= len(s)-len(substr); i++ {
        if s[i:i+len(substr)] == substr {
            return true
        }
    }
    return false
}

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx := context.Background()
    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    order := &client.Order{
        Symbol:      "BTC-USD",
        Type:        client.OrderTypeLimit,
        Side:        client.OrderSideBuy,
        Price:       50000.00,
        Size:        0.1,
        UserID:      "trader-001",
        ClientID:    "retry-order-001",
        TimeInForce: client.TimeInForceGTC,
    }

    resp, err := placeOrderWithRetry(c, order, 3)
    if err != nil {
        log.Fatal("Order failed:", err)
    }

    fmt.Printf("Order placed: ID=%d\n", resp.OrderID)
}

Performance Tips

Object Pooling for High-Frequency Trading

package main

import (
    "context"
    "log"
    "sync"
    "time"

    "github.com/luxfi/dex/sdk/go/client"
)

var orderPool = sync.Pool{
    New: func() interface{} {
        return &client.Order{}
    },
}

func getOrder() *client.Order {
    return orderPool.Get().(*client.Order)
}

func putOrder(o *client.Order) {
    // Reset fields
    o.OrderID = 0
    o.Symbol = ""
    o.Type = 0
    o.Side = 0
    o.Price = 0
    o.Size = 0
    o.Filled = 0
    o.Remaining = 0
    o.Status = ""
    o.UserID = ""
    o.ClientID = ""
    o.Timestamp = 0
    o.TimeInForce = ""
    o.PostOnly = false
    o.ReduceOnly = false
    orderPool.Put(o)
}

func placeFastOrder(c *client.Client, ctx context.Context,
    symbol string, side client.OrderSide, price, size float64) (*client.OrderResponse, error) {

    order := getOrder()
    defer putOrder(order)

    order.Symbol = symbol
    order.Type = client.OrderTypeLimit
    order.Side = side
    order.Price = price
    order.Size = size
    order.TimeInForce = client.TimeInForceGTC

    return c.PlaceOrder(ctx, order)
}

func main() {
    c, err := client.NewClient(
        client.WithGRPCURL("localhost:50051"),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer c.Disconnect()

    ctx := context.Background()
    if err := c.ConnectGRPC(ctx); err != nil {
        log.Fatal("Failed to connect:", err)
    }

    // Benchmark pooled vs non-pooled
    start := time.Now()
    for i := 0; i < 1000; i++ {
        _, err := placeFastOrder(c, ctx, "BTC-USD", client.OrderSideBuy, 50000, 0.001)
        if err != nil {
            // Handle error
        }
    }
    log.Printf("1000 orders in %v", time.Since(start))
}

Next Steps