// Package main demonstrates the Synor DEX SDK for Go // // This example covers decentralized exchange operations: // - Spot trading (limit/market orders) // - Perpetual futures trading // - Liquidity provision (AMM pools) // - Order book management // - Portfolio tracking package main import ( "context" "fmt" "log" "os" "time" "github.com/synor/sdk-go/dex" ) func main() { // Initialize client config := dex.Config{ APIKey: getEnv("SYNOR_API_KEY", "your-api-key"), Endpoint: "https://dex.synor.io/v1", Timeout: 30 * time.Second, Retries: 3, Debug: false, DefaultMarket: "SYN-USDC", } client, err := dex.NewClient(config) if err != nil { log.Fatalf("Failed to create client: %v", err) } defer client.Close() ctx := context.Background() // Check service health healthy, err := client.HealthCheck(ctx) if err != nil { log.Printf("Health check failed: %v", err) } else { fmt.Printf("Service healthy: %v\n\n", healthy) } // Run examples marketsExample(ctx, client) spotTradingExample(ctx, client) perpsTradingExample(ctx, client) liquidityExample(ctx, client) orderbookExample(ctx, client) portfolioExample(ctx, client) } func marketsExample(ctx context.Context, client *dex.Client) { fmt.Println("=== Markets ===") // Get all markets markets, err := client.Markets.List(ctx) if err != nil { log.Printf("Failed to list markets: %v", err) return } fmt.Printf("Available markets: %d\n", len(markets)) for _, market := range markets[:min(5, len(markets))] { fmt.Printf("\n %s:\n", market.Symbol) fmt.Printf(" Base: %s, Quote: %s\n", market.BaseAsset, market.QuoteAsset) fmt.Printf(" Price: %s\n", market.LastPrice) fmt.Printf(" 24h Volume: %s\n", market.Volume24h) fmt.Printf(" 24h Change: %s%%\n", market.Change24h) fmt.Printf(" Status: %s\n", market.Status) } // Get specific market market, err := client.Markets.Get(ctx, "SYN-USDC") if err != nil { log.Printf("Failed to get market: %v", err) return } fmt.Printf("\nSYN-USDC details:\n") fmt.Printf(" Min order size: %s\n", market.MinOrderSize) fmt.Printf(" Tick size: %s\n", market.TickSize) fmt.Printf(" Maker fee: %s%%\n", market.MakerFee) fmt.Printf(" Taker fee: %s%%\n", market.TakerFee) // Get market statistics stats, err := client.Markets.GetStats(ctx, "SYN-USDC") if err != nil { log.Printf("Failed to get market stats: %v", err) return } fmt.Printf("\nMarket statistics:\n") fmt.Printf(" High 24h: %s\n", stats.High24h) fmt.Printf(" Low 24h: %s\n", stats.Low24h) fmt.Printf(" Open interest: %s\n", stats.OpenInterest) fmt.Printf(" Funding rate: %s%%\n", stats.FundingRate) fmt.Println() } func spotTradingExample(ctx context.Context, client *dex.Client) { fmt.Println("=== Spot Trading ===") // Place a limit order fmt.Println("Placing limit buy order...") limitOrder, err := client.Spot.PlaceOrder(ctx, &dex.OrderRequest{ Market: "SYN-USDC", Side: dex.SideBuy, OrderType: dex.OrderTypeLimit, Price: "1.50", Quantity: "100", TimeInForce: dex.TimeInForceGTC, }) if err != nil { log.Printf("Failed to place limit order: %v", err) } else { fmt.Printf("Limit order placed:\n") fmt.Printf(" Order ID: %s\n", limitOrder.OrderID) fmt.Printf(" Status: %s\n", limitOrder.Status) fmt.Printf(" Price: %s\n", limitOrder.Price) fmt.Printf(" Quantity: %s\n", limitOrder.Quantity) } // Place a market order fmt.Println("\nPlacing market sell order...") marketOrder, err := client.Spot.PlaceOrder(ctx, &dex.OrderRequest{ Market: "SYN-USDC", Side: dex.SideSell, OrderType: dex.OrderTypeMarket, Quantity: "50", }) if err != nil { log.Printf("Failed to place market order: %v", err) } else { fmt.Printf("Market order executed:\n") fmt.Printf(" Order ID: %s\n", marketOrder.OrderID) fmt.Printf(" Status: %s\n", marketOrder.Status) fmt.Printf(" Filled: %s\n", marketOrder.FilledQuantity) fmt.Printf(" Avg price: %s\n", marketOrder.AveragePrice) } // Get order status if limitOrder != nil { status, err := client.Spot.GetOrder(ctx, limitOrder.OrderID) if err != nil { log.Printf("Failed to get order status: %v", err) } else { fmt.Printf("\nOrder status:\n") fmt.Printf(" Status: %s\n", status.Status) fmt.Printf(" Filled: %s / %s\n", status.FilledQuantity, status.Quantity) fmt.Printf(" Remaining: %s\n", status.RemainingQuantity) } // Cancel order fmt.Println("\nCancelling order...") err = client.Spot.CancelOrder(ctx, limitOrder.OrderID) if err != nil { log.Printf("Failed to cancel order: %v", err) } else { fmt.Println("Order cancelled successfully") } } // Get open orders openOrders, err := client.Spot.GetOpenOrders(ctx, "SYN-USDC") if err != nil { log.Printf("Failed to get open orders: %v", err) } else { fmt.Printf("\nOpen orders: %d\n", len(openOrders)) } // Get trade history trades, err := client.Spot.GetTradeHistory(ctx, "SYN-USDC", 10) if err != nil { log.Printf("Failed to get trade history: %v", err) } else { fmt.Printf("\nRecent trades: %d\n", len(trades)) for _, trade := range trades[:min(3, len(trades))] { fmt.Printf(" %s %s @ %s (%s)\n", trade.Side, trade.Quantity, trade.Price, trade.Timestamp.Format(time.RFC3339)) } } fmt.Println() } func perpsTradingExample(ctx context.Context, client *dex.Client) { fmt.Println("=== Perpetual Futures Trading ===") // Get available perps markets perpsMarkets, err := client.Perps.ListMarkets(ctx) if err != nil { log.Printf("Failed to list perps markets: %v", err) return } fmt.Printf("Available perps markets: %d\n", len(perpsMarkets)) for _, market := range perpsMarkets[:min(3, len(perpsMarkets))] { fmt.Printf(" %s: %s (funding: %s%%)\n", market.Symbol, market.MarkPrice, market.FundingRate) } // Open a long position fmt.Println("\nOpening long position...") position, err := client.Perps.OpenPosition(ctx, &dex.PerpsOrderRequest{ Market: "SYN-USDC-PERP", Side: dex.SideBuy, OrderType: dex.OrderTypeLimit, Price: "1.50", Size: "1000", Leverage: 10, ReduceOnly: false, }) if err != nil { log.Printf("Failed to open position: %v", err) } else { fmt.Printf("Position opened:\n") fmt.Printf(" Position ID: %s\n", position.PositionID) fmt.Printf(" Size: %s\n", position.Size) fmt.Printf(" Entry price: %s\n", position.EntryPrice) fmt.Printf(" Leverage: %dx\n", position.Leverage) fmt.Printf(" Liquidation price: %s\n", position.LiquidationPrice) } // Get position details if position != nil { details, err := client.Perps.GetPosition(ctx, position.PositionID) if err != nil { log.Printf("Failed to get position: %v", err) } else { fmt.Printf("\nPosition details:\n") fmt.Printf(" Unrealized PnL: %s\n", details.UnrealizedPnL) fmt.Printf(" Margin: %s\n", details.Margin) fmt.Printf(" Margin ratio: %s%%\n", details.MarginRatio) } } // Set stop loss and take profit if position != nil { fmt.Println("\nSetting stop loss and take profit...") err = client.Perps.SetStopLoss(ctx, position.PositionID, "1.40") if err != nil { log.Printf("Failed to set stop loss: %v", err) } else { fmt.Println("Stop loss set at 1.40") } err = client.Perps.SetTakeProfit(ctx, position.PositionID, "1.80") if err != nil { log.Printf("Failed to set take profit: %v", err) } else { fmt.Println("Take profit set at 1.80") } // Close position fmt.Println("\nClosing position...") closeResult, err := client.Perps.ClosePosition(ctx, position.PositionID) if err != nil { log.Printf("Failed to close position: %v", err) } else { fmt.Printf("Position closed:\n") fmt.Printf(" Realized PnL: %s\n", closeResult.RealizedPnL) fmt.Printf(" Close price: %s\n", closeResult.ClosePrice) } } // Get all positions positions, err := client.Perps.GetPositions(ctx) if err != nil { log.Printf("Failed to get positions: %v", err) } else { fmt.Printf("\nOpen positions: %d\n", len(positions)) } // Get funding history funding, err := client.Perps.GetFundingHistory(ctx, "SYN-USDC-PERP", 10) if err != nil { log.Printf("Failed to get funding history: %v", err) } else { fmt.Printf("Funding payments: %d\n", len(funding)) } fmt.Println() } func liquidityExample(ctx context.Context, client *dex.Client) { fmt.Println("=== Liquidity Provision ===") // Get available pools pools, err := client.Liquidity.ListPools(ctx) if err != nil { log.Printf("Failed to list pools: %v", err) return } fmt.Printf("Available pools: %d\n", len(pools)) for _, pool := range pools[:min(3, len(pools))] { fmt.Printf("\n %s:\n", pool.Name) fmt.Printf(" TVL: $%s\n", pool.TVL) fmt.Printf(" APR: %s%%\n", pool.APR) fmt.Printf(" Volume 24h: $%s\n", pool.Volume24h) fmt.Printf(" Fee tier: %s%%\n", pool.FeeTier) } // Get pool details pool, err := client.Liquidity.GetPool(ctx, "SYN-USDC") if err != nil { log.Printf("Failed to get pool: %v", err) return } fmt.Printf("\nSYN-USDC pool details:\n") fmt.Printf(" Token0: %s (%s)\n", pool.Token0.Symbol, pool.Token0Reserve) fmt.Printf(" Token1: %s (%s)\n", pool.Token1.Symbol, pool.Token1Reserve) fmt.Printf(" Price: %s\n", pool.Price) fmt.Printf(" Total LP tokens: %s\n", pool.TotalLPTokens) // Add liquidity fmt.Println("\nAdding liquidity...") addResult, err := client.Liquidity.AddLiquidity(ctx, &dex.AddLiquidityRequest{ Pool: "SYN-USDC", Amount0: "100", Amount1: "150", SlippageBps: 50, // 0.5% }) if err != nil { log.Printf("Failed to add liquidity: %v", err) } else { fmt.Printf("Liquidity added:\n") fmt.Printf(" LP tokens received: %s\n", addResult.LPTokens) fmt.Printf(" Position ID: %s\n", addResult.PositionID) fmt.Printf(" Share of pool: %s%%\n", addResult.ShareOfPool) } // Get LP positions lpPositions, err := client.Liquidity.GetPositions(ctx) if err != nil { log.Printf("Failed to get LP positions: %v", err) } else { fmt.Printf("\nLP positions: %d\n", len(lpPositions)) for _, pos := range lpPositions { fmt.Printf(" %s: %s LP tokens (value: $%s)\n", pos.Pool, pos.LPTokens, pos.Value) } } // Claim fees if addResult != nil { fmt.Println("\nClaiming fees...") fees, err := client.Liquidity.ClaimFees(ctx, addResult.PositionID) if err != nil { log.Printf("Failed to claim fees: %v", err) } else { fmt.Printf("Fees claimed:\n") fmt.Printf(" Token0: %s\n", fees.Amount0) fmt.Printf(" Token1: %s\n", fees.Amount1) } // Remove liquidity fmt.Println("\nRemoving liquidity...") removeResult, err := client.Liquidity.RemoveLiquidity(ctx, &dex.RemoveLiquidityRequest{ PositionID: addResult.PositionID, LPTokens: addResult.LPTokens, SlippageBps: 50, }) if err != nil { log.Printf("Failed to remove liquidity: %v", err) } else { fmt.Printf("Liquidity removed:\n") fmt.Printf(" Token0 received: %s\n", removeResult.Amount0) fmt.Printf(" Token1 received: %s\n", removeResult.Amount1) } } fmt.Println() } func orderbookExample(ctx context.Context, client *dex.Client) { fmt.Println("=== Order Book ===") // Get order book snapshot orderbook, err := client.Orderbook.GetSnapshot(ctx, "SYN-USDC", 10) if err != nil { log.Printf("Failed to get orderbook: %v", err) return } fmt.Println("Order book for SYN-USDC:") fmt.Println("\nAsks (sells):") for _, ask := range orderbook.Asks[:min(5, len(orderbook.Asks))] { fmt.Printf(" %s @ %s\n", ask.Quantity, ask.Price) } fmt.Println("\nBids (buys):") for _, bid := range orderbook.Bids[:min(5, len(orderbook.Bids))] { fmt.Printf(" %s @ %s\n", bid.Quantity, bid.Price) } fmt.Printf("\nSpread: %s (%s%%)\n", orderbook.Spread, orderbook.SpreadPercent) fmt.Printf("Mid price: %s\n", orderbook.MidPrice) // Get recent trades recentTrades, err := client.Orderbook.GetRecentTrades(ctx, "SYN-USDC", 10) if err != nil { log.Printf("Failed to get recent trades: %v", err) } else { fmt.Println("\nRecent trades:") for _, trade := range recentTrades[:min(5, len(recentTrades))] { fmt.Printf(" %s %s @ %s\n", trade.Side, trade.Quantity, trade.Price) } } // Subscribe to orderbook updates (simulated) fmt.Println("\nSubscribing to orderbook updates...") updates := client.Orderbook.Subscribe(ctx, "SYN-USDC") // Process a few updates (in real usage, this would be a goroutine) go func() { for i := 0; i < 3; i++ { select { case update := <-updates: fmt.Printf(" Update: %s %s @ %s\n", update.Side, update.Quantity, update.Price) case <-time.After(5 * time.Second): return } } }() time.Sleep(2 * time.Second) // Wait for some updates fmt.Println() } func portfolioExample(ctx context.Context, client *dex.Client) { fmt.Println("=== Portfolio ===") // Get portfolio overview portfolio, err := client.Portfolio.GetOverview(ctx) if err != nil { log.Printf("Failed to get portfolio: %v", err) return } fmt.Println("Portfolio overview:") fmt.Printf(" Total value: $%s\n", portfolio.TotalValue) fmt.Printf(" Available balance: $%s\n", portfolio.AvailableBalance) fmt.Printf(" In orders: $%s\n", portfolio.InOrders) fmt.Printf(" In positions: $%s\n", portfolio.InPositions) fmt.Printf(" Unrealized PnL: $%s\n", portfolio.UnrealizedPnL) // Get balances balances, err := client.Portfolio.GetBalances(ctx) if err != nil { log.Printf("Failed to get balances: %v", err) } else { fmt.Println("\nBalances:") for _, balance := range balances { fmt.Printf(" %s: %s (available: %s, in orders: %s)\n", balance.Asset, balance.Total, balance.Available, balance.InOrders) } } // Get PnL history pnlHistory, err := client.Portfolio.GetPnLHistory(ctx, 30) // Last 30 days if err != nil { log.Printf("Failed to get PnL history: %v", err) } else { fmt.Printf("\nPnL history (last %d days):\n", len(pnlHistory)) if len(pnlHistory) > 0 { totalPnL := "0" for _, day := range pnlHistory { totalPnL = day.CumulativePnL } fmt.Printf(" Total PnL: $%s\n", totalPnL) } } // Get trade statistics stats, err := client.Portfolio.GetStats(ctx) if err != nil { log.Printf("Failed to get trade stats: %v", err) } else { fmt.Println("\nTrade statistics:") fmt.Printf(" Total trades: %d\n", stats.TotalTrades) fmt.Printf(" Win rate: %s%%\n", stats.WinRate) fmt.Printf(" Avg profit: $%s\n", stats.AvgProfit) fmt.Printf(" Avg loss: $%s\n", stats.AvgLoss) fmt.Printf(" Best trade: $%s\n", stats.BestTrade) fmt.Printf(" Worst trade: $%s\n", stats.WorstTrade) } fmt.Println() } func min(a, b int) int { if a < b { return a } return b } func getEnv(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue }