A unified Go library for cryptocurrency exchange APIs, supporting multiple exchanges with a consistent interface.
Migrated from go-okex with multi-exchange support architecture.
- 🔄 Unified Interface: Common API across multiple exchanges
- 🎯 Type-Safe: Strong typing with proper error handling
- 📦 Modular Design: Use native exchange APIs or unified interface
- 🔌 Extensible: Easy to add support for new exchanges
- ⚡ High Performance: Efficient WebSocket and REST implementations
- 🔙 Backward Compatible: Existing
go-okexcode works with minimal changes
- ✅ OKEx (Full native client support + adapter layer)
- 🚧 BitMart (In Progress - Infrastructure ready)
- 🚧 Binance (Planned)
- 🚧 BingX (Planned)
go get github.com/djpken/go-exc- Go 1.25 or higher
- Dependencies managed via
go.mod
The native OKEx client provides full access to all OKEx features:
package main
import (
"context"
"log"
"github.com/djpken/go-exc/exchanges/okex"
)
func main() {
ctx := context.Background()
// Create OKEx client
client, err := okex.NewClient(
ctx,
"your-api-key",
"your-secret-key",
"your-passphrase",
okex.NormalServer, // or okex.DemoServer for testing
)
if err != nil {
log.Fatal(err)
}
// Access all native OKEx APIs
// REST API examples
balance, err := client.Rest.Account.GetBalance(/* params */)
positions, err := client.Rest.Account.GetPositions(/* params */)
orderResp, err := client.Rest.Trade.PlaceOrder(/* params */)
// WebSocket examples
// Subscribe to order book
orderBookChan := make(chan *public.OrderBook)
err = client.Ws.Public.OrderBook(req, orderBookChan)
// Subscribe to private channels
positionChan := make(chan *private.BalanceAndPosition)
err = client.Ws.Private.BalanceAndPosition(positionChan)
}The adapter layer provides a unified interface across exchanges:
package main
import (
"context"
"log"
"github.com/djpken/go-exc"
)
func main() {
ctx := context.Background()
// Create OKEx client through adapter
client, err := exc.NewOKExClient(
ctx,
"api-key",
"secret-key",
"passphrase",
false, // testMode
)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Use adapter APIs
balance, err := client.REST().Account().GetBalance(ctx)
if err != nil {
log.Fatal(err)
}
log.Printf("Total Equity: %s\n", balance.TotalEquity)
// Or access native client for full features
nativeClient := client.GetNativeClient()
// Use all native OKEx features
}Subscribe to real-time ticker updates across any exchange:
package main
import (
"context"
"fmt"
"log"
exc "github.com/djpken/go-exc"
)
func main() {
ctx := context.Background()
// Works with any exchange - just change exc.OKX to exc.BitMart, etc.
client, err := exc.NewExchange(ctx, exc.OKX, exc.Config{
APIKey: "your-api-key",
SecretKey: "your-secret-key",
Passphrase: "your-passphrase",
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Create channel for ticker updates
tickerCh := make(chan *exc.TickerUpdate, 100)
// Subscribe to symbols
symbols := []string{"BTC-USDT", "ETH-USDT"}
if err := client.SubscribeTickers(tickerCh, symbols...); err != nil {
log.Fatal(err)
}
// Process real-time ticker updates
for update := range tickerCh {
fmt.Printf("%s: %s (24h change: %s%%)\n",
update.Symbol, update.LastPrice, update.PercentChange24h)
}
}Subscribe to real-time candlestick/kline updates across any exchange:
package main
import (
"context"
"fmt"
"log"
exc "github.com/djpken/go-exc"
)
func main() {
ctx := context.Background()
// Works with any exchange - just change exc.OKX to exc.BitMart, etc.
client, err := exc.NewExchange(ctx, exc.OKX, exc.Config{
APIKey: "your-api-key",
SecretKey: "your-secret-key",
Passphrase: "your-passphrase",
})
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Create channel for candle updates
candleCh := make(chan *exc.CandleUpdate, 100)
// Subscribe to symbols with specific interval
// Intervals: "1m", "5m", "15m", "30m", "1H", "4H", "1D", etc.
symbols := []string{"BTC-USDT", "ETH-USDT"}
if err := client.SubscribeCandles(candleCh, "1m", symbols...); err != nil {
log.Fatal(err)
}
// Process real-time candle updates
for update := range candleCh {
if update.Confirmed {
fmt.Printf("%s candle closed: O=%s H=%s L=%s C=%s Vol=%s\n",
update.Symbol, update.Open, update.High, update.Low,
update.Close, update.Volume)
} else {
fmt.Printf("%s candle forming: Current=%s\n",
update.Symbol, update.Close)
}
}
}The library maintains full backward compatibility with go-okex. Simply update your import paths:
// Old
import "github.com/djpken/go-okex"
import "github.com/djpken/go-okex/api"
// New
import "github.com/djpken/go-exc/exchanges/okex"
// All APIs remain the same!Update your go.mod:
// Old
module github.com/djpken/go-okex
// New
module github.com/djpken/go-excThen update import paths throughout your codebase:
find . -type f -name "*.go" -exec sed -i '' 's|github.com/djpken/go-okex|github.com/djpken/go-exc/exchanges/okex|g' {} +go-exc/
├── exc.go # Core unified interfaces
├── config.go # Configuration types
├── errors.go # Error definitions
├── factory.go # Exchange factory
├── types/ # Common types across exchanges
│ ├── common.go # Decimal, Timestamp
│ ├── order.go # Order types
│ ├── balance.go # Balance types
│ ├── position.go # Position types
│ └── market.go # Market data types
└── exchanges/
└── okex/ # OKEx implementation
├── okex.go # Exchange adapter
├── converter.go # Type converters
├── rest_adapter.go # REST API adapter
├── ws_adapter.go # WebSocket adapter
├── client_legacy.go # Original client
├── types/ # OKEx-specific types
│ └── definitions.go
├── rest/ # REST API implementation
├── ws/ # WebSocket implementation
├── models/ # Data models
├── requests/ # Request types
├── responses/ # Response types
└── events/ # Event types
The Decimal type is used throughout go-exc for representing monetary values, prices, and quantities with precision. Unlike float64, Decimal avoids floating-point precision issues that are critical in financial applications.
import exc "github.com/djpken/go-exc"
price := exc.Decimal("45678.50")
quantity := exc.Decimal("1.5")// Basic math
sum, err := price.Add(exc.Decimal("100")) // price + 100
diff, err := price.Sub(exc.Decimal("100")) // price - 100
product, err := price.Mul(quantity) // price * quantity
quotient, err := price.Div(quantity) // price / quantity
// Unary operations
abs, err := price.Abs() // |price|
neg, err := price.Neg() // -price// Compare
cmp, err := price1.Cmp(price2) // Returns -1, 0, or 1
// Boolean comparisons
isLess, err := price1.LessThan(price2) // <
isGreater, err := price1.GreaterThan(price2) // >
isEqual, err := price1.Equal(price2) // ==
isLessOrEq, err := price1.LessThanOrEqual(price2) // <=
isGreaterOrEq, err := price1.GreaterThanOrEqual(price2) // >=// Find maximum
highest, err := price1.Max(price2)
// Find minimum
lowest, err := price1.Min(price2)
// Chain operations for multiple values
highest, _ := price1.Max(price2)
highest, _ = highest.Max(price3)// Check if positive (> 0)
if price.IsPositive() {
fmt.Println("Price is positive")
}
// Check if negative (< 0)
if pnl.IsNegative() {
fmt.Println("Position in loss")
}
// Check if zero
if balance.IsZero() {
fmt.Println("No balance")
}Find Best Execution Price Across Exchanges:
binanceBid := exc.Decimal("45678.50")
okexBid := exc.Decimal("45679.20")
// Find highest bid for selling
bestBid, _ := binanceBid.Max(okexBid)Risk Management with Stop Loss:
entryPrice := exc.Decimal("50000")
stopLossPercent := exc.Decimal("0.95") // 95% (5% loss)
stopLossPrice, _ := entryPrice.Mul(stopLossPercent)
if currentPrice.LessThan(stopLossPrice) {
// Trigger stop loss
}Portfolio Analysis:
position1Value, _ := position1Price.Mul(position1Qty)
position2Value, _ := position2Price.Mul(position2Qty)
totalValue, _ := position1Value.Add(position2Value)
// Find largest position
largest, _ := position1Value.Max(position2Value)For more examples, see examples/decimal_math/
go-exc uses type-safe constants instead of strings for position sides, margin modes, and instrument types to catch errors at compile time.
// Use typed constants instead of strings
position := &exc.Position{
Symbol: "BTC-USDT",
PosSide: exc.PositionSideLong, // Not "long" string!
}
// Available constants
exc.PositionSideLong // Long position
exc.PositionSideShort // Short position
exc.PositionSideNet // Net position (one-way mode)// Type-safe margin mode
position.MarginMode = exc.MarginModeCross // Not "cross" string!
// Available constants
exc.MarginModeCross // Cross margin
exc.MarginModeIsolated // Isolated margin// Query instruments with type-safe constants
instruments, _ := client.GetInstruments(ctx, exc.GetInstrumentsRequest{
InstrumentType: exc.InstrumentSwap, // Not "swap" string!
})
// Available constants
exc.InstrumentSpot // Spot trading
exc.InstrumentMargin // Margin trading
exc.InstrumentFutures // Futures contracts
exc.InstrumentSwap // Perpetual swaps
exc.InstrumentOption // Optionsleverage, err := client.SetLeverage(ctx, exc.SetLeverageRequest{
Symbol: "BTC-USDT",
Leverage: 10,
MarginMode: exc.MarginModeCross, // Type-safe!
PosSide: exc.PositionSideLong, // Type-safe!
})Benefits:
- ✅ Compile-time type checking (catch typos before runtime)
- ✅ IDE autocomplete support
- ✅ Self-documenting code
- ✅ Safe refactoring
For more examples, see examples/position_types/
- ✅ Trade (place/cancel/amend orders, etc.)
- ✅ Account (balance, positions, configuration)
- ✅ Funding (deposits, withdrawals, transfers)
- ✅ Market Data (tickers, order books, candles)
- ✅ Public Data (instruments, system status)
- ✅ Trading Data (volume, ratios, etc.)
- ✅ Sub-Account management
- ✅ Private Channels (account, positions, orders)
- ✅ Public Channels (tickers, order books, trades)
- ✅ Trade Operations (place/cancel orders via WS)
- ✅ Unified Ticker Subscriptions (works across all exchanges)
- ✅ Unified Candlestick Subscriptions (works across all exchanges)
- Module rename and restructuring
- Dependency updates (WebSocket v1.5.3, Go 1.23)
- Fixed circular dependencies
- Core architecture design
- Core interface definitions
- Common type system
- Error handling framework
- Factory pattern implementation
- OKEx adapter structure
- Type converters
- REST API adapters (basic operations)
- WebSocket adapter structure
- README documentation
- API usage examples
- Migration guide
- Architecture documentation
- Complete REST API coverage
- Full WebSocket event handling
- Binance integration
- Comprehensive test suite
- Performance benchmarks
See the examples/ directory for complete usage examples:
Unified Interface Examples:
examples/simple_example/- Single exchange usage with unified interfaceexamples/getconfig_example/- Handling unsupported features gracefullyexamples/get_candles/- Fetching historical candlestick/kline dataexamples/websocket_tickers/- Real-time ticker subscriptions via WebSocketexamples/websocket_candles/- Real-time candlestick/kline subscriptions via WebSocketexamples/websocket_tickers_dynamic/- Dynamic ticker subscription exampleexamples/decimal_math/- Decimal type math operations and trading scenariosexamples/position_types/- Type-safe constants for positions and trading
Native Client Examples:
examples/bitmart_rest/- BitMart REST API usageexamples/bitmart_ws/- BitMart WebSocket subscriptionsexamples/okex_rest/- OKEx REST API usageexamples/okex_ws/- OKEx WebSocket subscriptions
- Go: 1.23 or higher
- gorilla/websocket: v1.5.3
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
This project is licensed under the same terms as the original go-okex project. See LICENSE for details.
This package is provided as-is, without any express or implied warranties. The user assumes all risks associated with the use of this package. Use at your own risk.
- CHANGELOG.md - Version history and changes
- MIGRATION.md - Migration guide from go-okex
- Architecture Documentation - Detailed architecture design
- Refactoring Plan - Project refactoring implementation plan
Originally based on go-okex by amir-the-h, refactored for multi-exchange support.