mirror of
https://github.com/luxfi/dex.git
synced 2026-09-24 00:26:31 +00:00
Apply consistent naming conventions throughout: - Standardize product name to "LX" in documentation - Update README files and API documentation - Apply linter fixes to all source files - Update Hummingbot connector documentation
173 lines
5.5 KiB
Rust
173 lines
5.5 KiB
Rust
//! Basic trading example for LX.
|
|
//!
|
|
//! Demonstrates:
|
|
//! - Connecting to WebSocket
|
|
//! - Authentication
|
|
//! - Subscribing to market data
|
|
//! - Placing and canceling orders
|
|
//! - Handling events
|
|
|
|
use lux_dex::{Client, ClientConfig, Order, Side, WsEvent};
|
|
use std::env;
|
|
use tracing::{info, warn};
|
|
|
|
#[tokio::main]
|
|
async fn main() -> lux_dex::Result<()> {
|
|
// Initialize logging
|
|
tracing_subscriber::fmt::init();
|
|
|
|
// Configuration from environment or defaults
|
|
let ws_url = env::var("LX_WS_URL").unwrap_or_else(|_| "ws://localhost:8081".into());
|
|
let http_url = env::var("LX_HTTP_URL").unwrap_or_else(|_| "http://localhost:8080".into());
|
|
let api_key = env::var("LX_API_KEY").ok();
|
|
let api_secret = env::var("LX_API_SECRET").ok();
|
|
|
|
let mut config = ClientConfig::default()
|
|
.with_ws_url(&ws_url)
|
|
.with_http_url(&http_url);
|
|
|
|
if let (Some(key), Some(secret)) = (api_key, api_secret) {
|
|
config = config.with_credentials(key, secret);
|
|
}
|
|
|
|
// Create client
|
|
let client = Client::with_config(config);
|
|
|
|
// Take event receiver before connecting
|
|
let mut events = client.take_event_receiver().await.unwrap();
|
|
|
|
// Connect to WebSocket
|
|
info!("Connecting to {}", ws_url);
|
|
client.connect().await?;
|
|
|
|
// Spawn event handler
|
|
let event_handle = tokio::spawn(async move {
|
|
while let Some(event) = events.recv().await {
|
|
match event {
|
|
WsEvent::Connected { client_id } => {
|
|
info!("Connected with client_id: {}", client_id);
|
|
}
|
|
WsEvent::Authenticated { user_id } => {
|
|
info!("Authenticated as user: {}", user_id);
|
|
}
|
|
WsEvent::OrderBook(book) => {
|
|
info!(
|
|
"Order book {}: bid={:?} ask={:?} spread={:?}",
|
|
book.symbol,
|
|
book.best_bid(),
|
|
book.best_ask(),
|
|
book.spread()
|
|
);
|
|
}
|
|
WsEvent::Trade(trade) => {
|
|
info!(
|
|
"Trade: {} {} @ {} (value: {})",
|
|
trade.symbol,
|
|
trade.size,
|
|
trade.price,
|
|
trade.value()
|
|
);
|
|
}
|
|
WsEvent::OrderUpdate { order, status } => {
|
|
info!(
|
|
"Order update: {} {} {} @ {} - {}",
|
|
order.order_id.unwrap_or(0),
|
|
order.side,
|
|
order.size,
|
|
order.price,
|
|
status
|
|
);
|
|
}
|
|
WsEvent::Position(pos) => {
|
|
info!(
|
|
"Position: {} {} size={} entry={} pnl={}",
|
|
pos.symbol, pos.side, pos.size, pos.entry_price, pos.unrealized_pnl
|
|
);
|
|
}
|
|
WsEvent::Price { symbol, price } => {
|
|
info!("Price update: {} = {}", symbol, price);
|
|
}
|
|
WsEvent::Error { message, request_id } => {
|
|
warn!("Error: {} (request: {:?})", message, request_id);
|
|
}
|
|
WsEvent::Pong => {
|
|
info!("Pong received");
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Wait for connection
|
|
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
|
|
|
// Authenticate if credentials are configured
|
|
if client.is_connected() {
|
|
info!("Attempting authentication...");
|
|
client.authenticate_configured().await.ok();
|
|
}
|
|
|
|
// Subscribe to market data
|
|
info!("Subscribing to BTC-USDT order book");
|
|
client.subscribe_orderbook("BTC-USDT").await?;
|
|
|
|
info!("Subscribing to ETH-USDT trades");
|
|
client.subscribe_trades("ETH-USDT").await?;
|
|
|
|
// Get order book via HTTP
|
|
info!("Fetching order book via HTTP...");
|
|
match client.get_orderbook("BTC-USDT", 10).await {
|
|
Ok(book) => {
|
|
info!(
|
|
"HTTP Order book: {} levels, mid={:?}",
|
|
book.bids.len() + book.asks.len(),
|
|
book.mid_price()
|
|
);
|
|
|
|
// Demonstrate slippage estimation
|
|
if let Some(avg_price) = book.estimate_buy_slippage(1.0) {
|
|
info!("Estimated buy price for 1 BTC: {}", avg_price);
|
|
}
|
|
}
|
|
Err(e) => {
|
|
warn!("Failed to fetch order book: {}", e);
|
|
}
|
|
}
|
|
|
|
// Place a test order (only if authenticated)
|
|
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
|
|
|
|
if client.is_authenticated() {
|
|
info!("Placing test limit order...");
|
|
let order = Order::limit("BTC-USDT", Side::Buy, 45000.0, 0.001)
|
|
.with_client_id("rust-sdk-test-001")
|
|
.post_only();
|
|
|
|
client.place_order(&order).await?;
|
|
info!("Order placed");
|
|
|
|
// Wait for confirmation
|
|
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
|
|
}
|
|
|
|
// Ping to keep connection alive
|
|
client.ping().await?;
|
|
|
|
// Run for a while to receive events
|
|
info!("Listening for events... (press Ctrl+C to exit)");
|
|
tokio::select! {
|
|
_ = tokio::signal::ctrl_c() => {
|
|
info!("Shutting down...");
|
|
}
|
|
_ = event_handle => {
|
|
info!("Event handler finished");
|
|
}
|
|
}
|
|
|
|
// Disconnect
|
|
client.disconnect().await?;
|
|
info!("Disconnected");
|
|
|
|
Ok(())
|
|
}
|