Go client for the OKX v5 API. Covers 335 REST endpoints and 53 WebSocket channels.
Package: pkg.go.dev/github.com/tigusigalpa/okx-go
go get github.com/tigusigalpa/okx-go- 335 REST endpoints across 16 categories
- 53 WebSocket channels (public, private, business)
- Demo trading mode (
x-simulated-trading: 1) context.Contexteverywhere- Typed request/response structs with generics
- Rate limiter (token bucket, configurable per category)
- WebSocket reconnect with exponential backoff
- Goroutine-safe
- Dependencies: stdlib +
gorilla/websocket
package main
import (
"context"
"fmt"
"log"
"github.com/tigusigalpa/okx-go"
)
func main() {
client := okx.NewRestClient(
"your-api-key",
"your-secret-key",
"your-passphrase",
okx.WithDemoTrading(),
)
ctx := context.Background()
balances, err := client.Account.GetBalance(ctx, nil)
if err != nil {
log.Fatal(err)
}
for _, b := range balances {
fmt.Printf("Total Equity: %s\n", *b.TotalEq)
}
// Place a limit order
px := "30000"
order := models.PlaceOrderRequest{
InstID: "BTC-USDT",
TdMode: "cash",
Side: "buy",
OrdType: "limit",
Px: &px,
Sz: "0.01",
}
result, err := client.Trade.PlaceOrder(ctx, order)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Order ID: %s\n", result[0].OrdID)
}ws := okx.NewWSClient("", "", "", okx.WSPublicURL)
ctx := context.Background()
if err := ws.Connect(ctx); err != nil {
log.Fatal(err)
}
defer ws.Close()
ch, err := ws.Subscribe(ctx, "tickers", map[string]interface{}{
"instId": "BTC-USDT",
})
if err != nil {
log.Fatal(err)
}
for msg := range ch {
fmt.Printf("%s\n", msg)
}ws := okx.NewWSClient(
"your-api-key",
"your-secret-key",
"your-passphrase",
okx.WSPrivateURL,
)
ctx := context.Background()
if err := ws.Connect(ctx); err != nil {
log.Fatal(err)
}
defer ws.Close()
if err := ws.Login(ctx); err != nil {
log.Fatal(err)
}
ch, err := ws.Subscribe(ctx, "account", map[string]interface{}{
"ccy": "BTC",
})
if err != nil {
log.Fatal(err)
}
for msg := range ch {
fmt.Printf("%s\n", msg)
}| Option | Description | Default |
|---|---|---|
WithHTTPClient(c) |
Custom *http.Client |
&http.Client{Timeout: 30s} |
WithBaseURL(url) |
Override base URL | https://www.okx.com |
WithDemoTrading() |
Demo mode | off |
WithTimeout(d) |
Request timeout | 30s |
WithRateLimiter(true) |
Rate limiter | off |
WithLogger(l) |
Custom Logger |
no-op |
| Category | Count | Docs |
|---|---|---|
| Account | 53 | link |
| Trade | 32 | link |
| Market Data | 24 | link |
| Public Data | 24 | link |
| Asset | 26 | link |
| Sub-account | 8 | link |
| Trading Bot | 44 | link |
| Copy Trading | 26 | link |
| Block Trading | 20 | link |
| Spread Trading | 13 | link |
| Financial Products | 33 | link |
| Fiat | 13 | link |
| Trading Statistics | 15 | link |
| System | 1 | link |
| Announcement | 2 | link |
| Affiliate | 1 | link |
| Total | 335 |
Public (31):
tickers, candle1D, candle1H, candle30m, trades, books, books5, bbo-tbt, opt-summary,
estimated-price, mark-price, mark-price-candle1D, price-limit, open-interest, funding-rate,
index-candle30m, index-tickers, status, public-struc-block-trades, block-tickers, block-trades,
liquidation-orders, sprd-tickers, sprd-books5, sprd-books-l2-tbt, sprd-public-trades, sprd-candle1D,
economic-calendar, call-auction-details, instruments, trades-all
Private (22):
account, positions, balance_and_position, orders, orders-algo, algo-advance, liquidation-warning,
account-greeks, rfqs, quotes, sprd-orders, sprd-trades, adl-warning, fills, deposit-info,
withdrawal-info, grid-orders-spot, grid-orders-contract, grid-positions, grid-sub-orders,
algo-recurring-buy, copytrading-lead-notification
REST — pass okx.WithDemoTrading():
client := okx.NewRestClient(apiKey, secret, passphrase, okx.WithDemoTrading())WebSocket — use demo URLs:
okx.WSDemoPublicURLokx.WSDemoPrivateURLokx.WSDemoBusinessURL
balances, err := client.Account.GetBalance(ctx, nil)
if err != nil {
if errors.Is(err, okx.ErrUnauthorized) {
// bad credentials
} else if errors.Is(err, okx.ErrRateLimited) {
// slow down
} else if okxErr, ok := err.(*okx.OKXError); ok {
fmt.Printf("code=%s msg=%s\n", okxErr.Code, okxErr.Message)
}
}OKX uses cursor-based pagination (before/after). There's a generic Paginator[T] helper:
paginator := models.NewPaginator(func(after string) ([]models.Order, string, error) {
orders, err := client.Trade.GetOrdersHistory(ctx, "SPOT", nil, nil, nil, nil, nil, nil, &after, nil, nil, nil, nil)
if err != nil {
return nil, "", err
}
var next string
if len(orders) > 0 {
next = orders[len(orders)-1].OrdID
}
return orders, next, nil
})
allOrders, err := paginator.All()# unit
go test ./...
# integration (demo env)
OKX_API_KEY=... OKX_SECRET_KEY=... OKX_PASSPHRASE=... go test -tags=integration ./...Fork, branch, PR. Make sure go test ./... passes and new code has tests. See CONTRIBUTING.md.
MIT. See LICENSE.
Igor Sazonov — @tigusigalpa — sovletig@gmail.com
Not affiliated with OKX. Test on demo before going live. Golang library.
