Your First Trade
Place your first order on LX - a complete beginner guide with code examples in TypeScript, Python, and Go
Your First Trade
This tutorial walks you through placing your first order on LX. By the end, you will understand the complete trading flow from connection to order confirmation.
Objectives
After completing this tutorial, you will be able to:
- Connect to the LX API
- Query market data
- Place limit and market orders
- Check order status and fills
- Cancel open orders
Prerequisites
- LX node running locally (see Getting Started)
- SDK installed for your preferred language
- Basic understanding of trading concepts (orders, orderbooks)
Step 1: Start the DEX Node
First, ensure your local DEX node is running:
# In the dex directory
./bin/lxd --testnet --log-level=infoYou should see output indicating the node is ready:
INFO Starting LX node
INFO JSON-RPC server listening on :8080
INFO WebSocket server listening on :8081
INFO gRPC server listening on :50051
INFO Node ready for tradingStep 2: Connect to the API
TypeScript
import { DEX } from '@luxfi/trading'
// Create client instance
const dex = await DEX({
rpcUrl: 'http://localhost:8080/rpc',
wsUrl: 'ws://localhost:8081'
})
// Test connection
async function testConnection() {
try {
const info = await dex.getInfo()
console.log('Connected to LX')
console.log('Node version:', info.version)
console.log('Network:', info.network)
return true
} catch (error) {
console.error('Connection failed:', error.message)
return false
}
}
testConnection()Python
from lux_dex import Client
# Create client instance
client = Client(
json_rpc_url='http://localhost:8080/rpc',
ws_url='ws://localhost:8081'
)
# Test connection
def test_connection():
try:
info = client.get_info()
print('Connected to LX')
print(f'Node version: {info["version"]}')
print(f'Network: {info["network"]}')
return True
except Exception as e:
print(f'Connection failed: {e}')
return False
test_connection()Go
package main
import (
"context"
"fmt"
"log"
"github.com/luxfi/dex/sdk/go/lxdex"
)
func main() {
// Create client instance
client := lxdex.NewClient(
lxdex.WithJSONRPC("http://localhost:8080/rpc"),
)
ctx := context.Background()
// Test connection
info, err := client.GetInfo(ctx)
if err != nil {
log.Fatalf("Connection failed: %v", err)
}
fmt.Println("Connected to LX")
fmt.Printf("Node version: %s\n", info.Version)
fmt.Printf("Network: %s\n", info.Network)
}cURL
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "lx_getInfo",
"params": {},
"id": 1
}'Expected Output:
{
"jsonrpc": "2.0",
"result": {
"version": "1.0.0",
"network": "testnet",
"uptime": 3600,
"orders_processed": 1250000
},
"id": 1
}Step 3: Check the Order Book
Before placing an order, check the current market state:
TypeScript
async function checkOrderBook() {
const book = await dex.getOrderBook('BTC-USD', 5)
console.log('\n=== BTC-USD Order Book ===')
console.log('\nAsks (Sell Orders):')
book.asks.slice().reverse().forEach(([price, size]) => {
console.log(` ${price.toFixed(2)} | ${size.toFixed(4)} BTC`)
})
console.log('\n--- Spread ---')
console.log('\nBids (Buy Orders):')
book.bids.forEach(([price, size]) => {
console.log(` ${price.toFixed(2)} | ${size.toFixed(4)} BTC`)
})
// Calculate spread
const bestBid = book.bids[0][0]
const bestAsk = book.asks[0][0]
const spread = bestAsk - bestBid
const spreadPercent = (spread / bestBid) * 100
console.log(`\nSpread: $${spread.toFixed(2)} (${spreadPercent.toFixed(3)}%)`)
return book
}
checkOrderBook()Python
def check_order_book():
book = client.get_order_book('BTC-USD', depth=5)
print('\n=== BTC-USD Order Book ===')
print('\nAsks (Sell Orders):')
for price, size in reversed(book['asks']):
print(f' {price:,.2f} | {size:.4f} BTC')
print('\n--- Spread ---')
print('\nBids (Buy Orders):')
for price, size in book['bids']:
print(f' {price:,.2f} | {size:.4f} BTC')
# Calculate spread
best_bid = book['bids'][0][0]
best_ask = book['asks'][0][0]
spread = best_ask - best_bid
spread_percent = (spread / best_bid) * 100
print(f'\nSpread: ${spread:,.2f} ({spread_percent:.3f}%)')
return book
check_order_book()Go
func checkOrderBook(ctx context.Context, client *lxdex.Client) {
book, err := client.GetOrderBook(ctx, "BTC-USD", 5)
if err != nil {
log.Fatalf("Failed to get order book: %v", err)
}
fmt.Println("\n=== BTC-USD Order Book ===")
fmt.Println("\nAsks (Sell Orders):")
for i := len(book.Asks) - 1; i >= 0; i-- {
ask := book.Asks[i]
fmt.Printf(" %.2f | %.4f BTC\n", ask.Price, ask.Size)
}
fmt.Println("\n--- Spread ---")
fmt.Println("\nBids (Buy Orders):")
for _, bid := range book.Bids {
fmt.Printf(" %.2f | %.4f BTC\n", bid.Price, bid.Size)
}
// Calculate spread
bestBid := book.Bids[0].Price
bestAsk := book.Asks[0].Price
spread := bestAsk - bestBid
spreadPercent := (spread / bestBid) * 100
fmt.Printf("\nSpread: $%.2f (%.3f%%)\n", spread, spreadPercent)
}Expected Output:
=== BTC-USD Order Book ===
Asks (Sell Orders):
50,150.00 | 0.8500 BTC
50,125.00 | 1.2000 BTC
50,100.00 | 2.5000 BTC
50,075.00 | 0.5000 BTC
50,050.00 | 1.0000 BTC
--- Spread ---
Bids (Buy Orders):
50,000.00 | 1.5000 BTC
49,975.00 | 2.0000 BTC
49,950.00 | 0.7500 BTC
49,925.00 | 1.8000 BTC
49,900.00 | 3.0000 BTC
Spread: $50.00 (0.100%)Step 4: Place a Limit Order
Now let us place a limit buy order:
TypeScript
async function placeLimitOrder() {
try {
const order = await dex.limitBuy('BTC-USD', '0.1', '49500', { timeInForce: 'GTC' })
console.log('\n=== Order Placed ===')
console.log('Order ID:', order.orderId)
console.log('Symbol:', order.symbol)
console.log('Side:', order.side)
console.log('Type:', order.type)
console.log('Price:', order.price)
console.log('Size:', order.size)
console.log('Status:', order.status)
console.log('Created:', new Date(order.createdAt).toISOString())
return order
} catch (error) {
console.error('Failed to place order:', error.message)
throw error
}
}
const myOrder = await placeLimitOrder()Python
def place_limit_order():
try:
order = client.place_order(
symbol='BTC-USD',
side='buy',
order_type='limit',
price=49500, # Price below market
size=0.1, # 0.1 BTC
time_in_force='GTC' # Good Till Cancelled
)
print('\n=== Order Placed ===')
print(f'Order ID: {order["order_id"]}')
print(f'Symbol: {order["symbol"]}')
print(f'Side: {order["side"]}')
print(f'Type: {order["type"]}')
print(f'Price: {order["price"]}')
print(f'Size: {order["size"]}')
print(f'Status: {order["status"]}')
print(f'Created: {order["created_at"]}')
return order
except Exception as e:
print(f'Failed to place order: {e}')
raise
my_order = place_limit_order()Go
func placeLimitOrder(ctx context.Context, client *lxdex.Client) (*lxdex.Order, error) {
order, err := client.PlaceOrder(ctx, &lxdex.OrderRequest{
Symbol: "BTC-USD",
Side: lxdex.Buy,
Type: lxdex.Limit,
Price: 49500, // Price below market
Size: 0.1, // 0.1 BTC
TimeInForce: lxdex.GTC, // Good Till Cancelled
})
if err != nil {
return nil, fmt.Errorf("failed to place order: %w", err)
}
fmt.Println("\n=== Order Placed ===")
fmt.Printf("Order ID: %s\n", order.OrderID)
fmt.Printf("Symbol: %s\n", order.Symbol)
fmt.Printf("Side: %s\n", order.Side)
fmt.Printf("Type: %s\n", order.Type)
fmt.Printf("Price: %.2f\n", order.Price)
fmt.Printf("Size: %.4f\n", order.Size)
fmt.Printf("Status: %s\n", order.Status)
fmt.Printf("Created: %s\n", order.CreatedAt.Format(time.RFC3339))
return order, nil
}cURL
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "lx_placeOrder",
"params": {
"symbol": "BTC-USD",
"side": 0,
"type": 0,
"price": 49500,
"size": 0.1,
"userID": "tutorial-user"
},
"id": 1
}'Expected Output:
=== Order Placed ===
Order ID: 550e8400-e29b-41d4-a716-446655440000
Symbol: BTC-USD
Side: buy
Type: limit
Price: 49500
Size: 0.1
Status: open
Created: 2024-01-15T10:30:45.123ZStep 5: Check Order Status
Monitor your order:
TypeScript
async function checkOrderStatus(orderId: string) {
const order = await dex.getOrder(orderId)
console.log('\n=== Order Status ===')
console.log('Order ID:', order.orderId)
console.log('Status:', order.status)
console.log('Filled:', order.filledSize, '/', order.size)
console.log('Remaining:', order.remainingSize)
console.log('Average Fill Price:', order.avgFillPrice || 'N/A')
if (order.fills && order.fills.length > 0) {
console.log('\nFills:')
order.fills.forEach((fill, i) => {
console.log(` ${i + 1}. ${fill.size} @ ${fill.price} (${fill.timestamp})`)
})
}
return order
}
await checkOrderStatus(myOrder.orderId)Python
def check_order_status(order_id):
order = client.get_order(order_id)
print('\n=== Order Status ===')
print(f'Order ID: {order["order_id"]}')
print(f'Status: {order["status"]}')
print(f'Filled: {order["filled_size"]} / {order["size"]}')
print(f'Remaining: {order["remaining_size"]}')
print(f'Average Fill Price: {order.get("avg_fill_price", "N/A")}')
if order.get('fills'):
print('\nFills:')
for i, fill in enumerate(order['fills'], 1):
print(f' {i}. {fill["size"]} @ {fill["price"]} ({fill["timestamp"]})')
return order
check_order_status(my_order['order_id'])Go
func checkOrderStatus(ctx context.Context, client *lxdex.Client, orderID string) {
order, err := client.GetOrder(ctx, orderID)
if err != nil {
log.Fatalf("Failed to get order: %v", err)
}
fmt.Println("\n=== Order Status ===")
fmt.Printf("Order ID: %s\n", order.OrderID)
fmt.Printf("Status: %s\n", order.Status)
fmt.Printf("Filled: %.4f / %.4f\n", order.FilledSize, order.Size)
fmt.Printf("Remaining: %.4f\n", order.RemainingSize)
if order.AvgFillPrice > 0 {
fmt.Printf("Average Fill Price: %.2f\n", order.AvgFillPrice)
}
if len(order.Fills) > 0 {
fmt.Println("\nFills:")
for i, fill := range order.Fills {
fmt.Printf(" %d. %.4f @ %.2f (%s)\n", i+1, fill.Size, fill.Price, fill.Timestamp)
}
}
}Expected Output:
=== Order Status ===
Order ID: 550e8400-e29b-41d4-a716-446655440000
Status: open
Filled: 0 / 0.1
Remaining: 0.1
Average Fill Price: N/AStep 6: Place a Market Order
For immediate execution, use a market order:
TypeScript
async function placeMarketOrder() {
const order = await dex.buy('BTC-USD', '0.05') // Market buy 0.05 BTC
console.log('\n=== Market Order Executed ===')
console.log('Order ID:', order.orderId)
console.log('Status:', order.status)
console.log('Filled:', order.filledSize)
console.log('Average Price:', order.avgFillPrice)
return order
}
await placeMarketOrder()Python
def place_market_order():
order = client.place_order(
symbol='BTC-USD',
side='buy',
order_type='market',
size=0.05 # 0.05 BTC
)
print('\n=== Market Order Executed ===')
print(f'Order ID: {order["order_id"]}')
print(f'Status: {order["status"]}')
print(f'Filled: {order["filled_size"]}')
print(f'Average Price: {order["avg_fill_price"]}')
return order
place_market_order()Go
func placeMarketOrder(ctx context.Context, client *lxdex.Client) {
order, err := client.PlaceOrder(ctx, &lxdex.OrderRequest{
Symbol: "BTC-USD",
Side: lxdex.Buy,
Type: lxdex.Market,
Size: 0.05, // 0.05 BTC
})
if err != nil {
log.Fatalf("Failed to place market order: %v", err)
}
fmt.Println("\n=== Market Order Executed ===")
fmt.Printf("Order ID: %s\n", order.OrderID)
fmt.Printf("Status: %s\n", order.Status)
fmt.Printf("Filled: %.4f\n", order.FilledSize)
fmt.Printf("Average Price: %.2f\n", order.AvgFillPrice)
}Expected Output:
=== Market Order Executed ===
Order ID: 660f9500-f30c-52e5-b827-557766551111
Status: filled
Filled: 0.05
Average Price: 50050.00Step 7: Cancel an Order
Cancel your open limit order:
TypeScript
async function cancelOrder(orderId: string) {
try {
const result = await dex.cancelOrder(orderId)
console.log('\n=== Order Cancelled ===')
console.log('Order ID:', result.orderId)
console.log('Status:', result.status)
console.log('Cancelled At:', new Date(result.cancelledAt).toISOString())
return result
} catch (error) {
if (error.code === 'ORDER_NOT_FOUND') {
console.log('Order not found (may already be filled or cancelled)')
} else {
throw error
}
}
}
await cancelOrder(myOrder.orderId)Python
def cancel_order(order_id):
try:
result = client.cancel_order(order_id)
print('\n=== Order Cancelled ===')
print(f'Order ID: {result["order_id"]}')
print(f'Status: {result["status"]}')
print(f'Cancelled At: {result["cancelled_at"]}')
return result
except Exception as e:
if 'ORDER_NOT_FOUND' in str(e):
print('Order not found (may already be filled or cancelled)')
else:
raise
cancel_order(my_order['order_id'])Go
func cancelOrder(ctx context.Context, client *lxdex.Client, orderID string) {
result, err := client.CancelOrder(ctx, orderID)
if err != nil {
if errors.Is(err, lxdex.ErrOrderNotFound) {
fmt.Println("Order not found (may already be filled or cancelled)")
return
}
log.Fatalf("Failed to cancel order: %v", err)
}
fmt.Println("\n=== Order Cancelled ===")
fmt.Printf("Order ID: %s\n", result.OrderID)
fmt.Printf("Status: %s\n", result.Status)
fmt.Printf("Cancelled At: %s\n", result.CancelledAt.Format(time.RFC3339))
}Expected Output:
=== Order Cancelled ===
Order ID: 550e8400-e29b-41d4-a716-446655440000
Status: cancelled
Cancelled At: 2024-01-15T10:35:22.456ZComplete Example
Here is a complete script combining all steps:
TypeScript
import { DEX } from '@luxfi/trading'
async function main() {
// Initialize client
const dex = await DEX({ rpcUrl: 'http://localhost:8080/rpc' })
// 1. Test connection
const info = await dex.getInfo()
console.log('Connected to', info.network)
// 2. Check orderbook
const book = await dex.getOrderBook('BTC-USD', 5)
console.log(`Best bid: ${book.bids[0][0]}, Best ask: ${book.asks[0][0]}`)
// 3. Place limit order
const limitOrder = await dex.limitBuy('BTC-USD', '0.1', '49500')
console.log('Limit order placed:', limitOrder.orderId)
// 4. Place market order
const marketOrder = await dex.buy('BTC-USD', '0.05')
console.log('Market order filled at:', marketOrder.avgFillPrice)
// 5. Check and cancel limit order
const status = await dex.getOrder(limitOrder.orderId)
if (status.status === 'open') {
await dex.cancelOrder(limitOrder.orderId)
console.log('Limit order cancelled')
}
console.log('\nTutorial complete!')
}
main().catch(console.error)Python
from lux_dex import Client
def main():
# Initialize client
client = Client(
json_rpc_url='http://localhost:8080/rpc'
)
# 1. Test connection
info = client.get_info()
print(f'Connected to {info["network"]}')
# 2. Check orderbook
book = client.get_order_book('BTC-USD', depth=5)
print(f'Best bid: {book["bids"][0][0]}, Best ask: {book["asks"][0][0]}')
# 3. Place limit order
limit_order = client.place_order(
symbol='BTC-USD',
side='buy',
order_type='limit',
price=49500,
size=0.1
)
print(f'Limit order placed: {limit_order["order_id"]}')
# 4. Place market order
market_order = client.place_order(
symbol='BTC-USD',
side='buy',
order_type='market',
size=0.05
)
print(f'Market order filled at: {market_order["avg_fill_price"]}')
# 5. Check and cancel limit order
status = client.get_order(limit_order['order_id'])
if status['status'] == 'open':
client.cancel_order(limit_order['order_id'])
print('Limit order cancelled')
print('\nTutorial complete!')
if __name__ == '__main__':
main()Go
package main
import (
"context"
"fmt"
"log"
"github.com/luxfi/dex/sdk/go/lxdex"
)
func main() {
ctx := context.Background()
// Initialize client
client := lxdex.NewClient(
lxdex.WithJSONRPC("http://localhost:8080/rpc"),
)
// 1. Test connection
info, err := client.GetInfo(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Connected to %s\n", info.Network)
// 2. Check orderbook
book, _ := client.GetOrderBook(ctx, "BTC-USD", 5)
fmt.Printf("Best bid: %.2f, Best ask: %.2f\n", book.Bids[0].Price, book.Asks[0].Price)
// 3. Place limit order
limitOrder, _ := client.PlaceOrder(ctx, &lxdex.OrderRequest{
Symbol: "BTC-USD",
Side: lxdex.Buy,
Type: lxdex.Limit,
Price: 49500,
Size: 0.1,
})
fmt.Printf("Limit order placed: %s\n", limitOrder.OrderID)
// 4. Place market order
marketOrder, _ := client.PlaceOrder(ctx, &lxdex.OrderRequest{
Symbol: "BTC-USD",
Side: lxdex.Buy,
Type: lxdex.Market,
Size: 0.05,
})
fmt.Printf("Market order filled at: %.2f\n", marketOrder.AvgFillPrice)
// 5. Check and cancel limit order
status, _ := client.GetOrder(ctx, limitOrder.OrderID)
if status.Status == "open" {
client.CancelOrder(ctx, limitOrder.OrderID)
fmt.Println("Limit order cancelled")
}
fmt.Println("\nTutorial complete!")
}Common Pitfalls
1. Insufficient Balance
Error: INSUFFICIENT_BALANCESolution: Ensure your account has enough funds. On testnet, use the faucet:
curl -X POST http://localhost:8080/rpc \
-d '{"jsonrpc":"2.0","method":"lx_faucet","params":{"address":"your-address","amount":10000},"id":1}'2. Invalid Price Tick
Error: INVALID_PRICE_TICKSolution: Prices must follow the market's tick size. For BTC-USD, the tick size is 0.01:
// Wrong
price: 50000.001
// Correct
price: 50000.003. Order Already Cancelled
Error: ORDER_NOT_FOUNDSolution: The order may have been filled or already cancelled. Always check status first.
4. Rate Limiting
Error: RATE_LIMIT_EXCEEDEDSolution: Slow down your requests. Use exponential backoff:
async function withRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.code === 'RATE_LIMIT_EXCEEDED' && i < maxRetries - 1) {
await sleep(Math.pow(2, i) * 1000);
continue;
}
throw error;
}
}
}Next Steps
Congratulations on completing your first trade! Continue your learning:
- Authentication Setup - Secure your API access
- Testing on Testnet - Practice safely before going live
- Orderbook Synchronization - Build real-time market views
Summary
In this tutorial, you learned to:
- Connect to the LX API
- Query order book data
- Place limit and market orders
- Monitor order status
- Cancel open orders
The complete code examples are available in all supported languages and can be used as starting points for your trading applications.