Skip to content

Commit

Permalink
add testnet support for rest api and websockets (adshao#212)
Browse files Browse the repository at this point in the history
Co-authored-by: adshao <tjusgj@gmail.com>
  • Loading branch information
Tom Pillot and adshao authored Feb 12, 2021
1 parent 7b1e2aa commit 9a93e48
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 20 deletions.
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,10 +311,24 @@ client.TimeOffset = 123

### Testnet

You can use the testnet (only available for futures and delivery) by enabling the corresponding flag.
You can use the testnet by enabling the corresponding flag.

> Note that you can't use your regular Api and Secret keys for the testnet. You have to create an account on
> the testnet website : [https://testnet.binancefuture.com/](https://testnet.binancefuture.com/).
> Note that you can't use your regular API and Secret keys for the testnet. You have to create an account on
> the testnet websites : [https://testnet.binancefuture.com/](https://testnet.binancefuture.com/) for futures and delivery
> or [https://testnet.binance.vision/](https://testnet.binance.vision/) for the Spot Test Network.
#### Spot

Use the `binance.UseTestnet` flag before calling the client creation and the websockets methods.

```go
import (
"github.com/adshao/go-binance/v2"
)

binance.UseTestnet = true
client := binance.NewClient(apiKey, secretKey)
```

#### Futures (usd(s)-m futures)

Expand Down
19 changes: 18 additions & 1 deletion v2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ type SideEffectType string
// FuturesTransferType define futures transfer type
type FuturesTransferType int

// Endpoints
const (
baseAPIMainURL = "https://api.binance.com"
baseAPITestnetURL = "https://testnet.binance.vision"
)

// UseTestnet switch all the API endpoints from production to the testnet
var UseTestnet = false

// Global enums
const (
SideTypeBuy SideType = "BUY"
Expand Down Expand Up @@ -153,14 +162,22 @@ func newJSON(data []byte) (j *simplejson.Json, err error) {
return j, nil
}

// getAPIEndpoint return the base endpoint of the Rest API according the UseTestnet flag
func getAPIEndpoint() string {
if UseTestnet {
return baseAPITestnetURL
}
return baseAPIMainURL
}

// NewClient initialize an API client instance with API key and secret key.
// You should always call this function before using this SDK.
// Services will be created by the form client.NewXXXService().
func NewClient(apiKey, secretKey string) *Client {
return &Client{
APIKey: apiKey,
SecretKey: secretKey,
BaseURL: "https://api.binance.com",
BaseURL: getAPIEndpoint(),
UserAgent: "Binance/golang",
HTTPClient: http.DefaultClient,
Logger: log.New(os.Stderr, "Binance-golang ", log.LstdFlags),
Expand Down
54 changes: 38 additions & 16 deletions v2/websocket_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,37 @@ import (
"time"
)

// Endpoints
const (
baseWsMainURL = "wss://stream.binance.com:9443/ws"
baseWsTestnetURL = "wss://testnet.binance.vision/ws"
baseCombinedMainURL = "wss://stream.binance.com:9443/stream?streams="
baseCombinedTestnetURL = "wss://testnet.binance.vision/stream?streams="
)

var (
baseURL = "wss://stream.binance.com:9443/ws"
combinedBaseURL = "wss://stream.binance.com:9443/stream?streams="
// WebsocketTimeout is an interval for sending ping/pong messages if WebsocketKeepalive is enabled
WebsocketTimeout = time.Second * 60
// WebsocketKeepalive enables sending ping/pong messages to check the connection stability
WebsocketKeepalive = false
)

// getWsEndpoint return the base endpoint of the WS according the UseTestnet flag
func getWsEndpoint() string {
if UseTestnet {
return baseWsTestnetURL
}
return baseWsMainURL
}

// getCombinedEndpoint return the base endpoint of the combined stream according the UseTestnet flag
func getCombinedEndpoint() string {
if UseTestnet {
return baseCombinedTestnetURL
}
return baseCombinedMainURL
}

// WsPartialDepthEvent define websocket partial depth book event
type WsPartialDepthEvent struct {
Symbol string
Expand All @@ -29,13 +51,13 @@ type WsPartialDepthHandler func(event *WsPartialDepthEvent)

// WsPartialDepthServe serve websocket partial depth handler with a symbol, using 1sec updates
func WsPartialDepthServe(symbol string, levels string, handler WsPartialDepthHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@depth%s", baseURL, strings.ToLower(symbol), levels)
endpoint := fmt.Sprintf("%s/%s@depth%s", getWsEndpoint(), strings.ToLower(symbol), levels)
return wsPartialDepthServe(endpoint, symbol, handler, errHandler)
}

// WsPartialDepthServe100Ms serve websocket partial depth handler with a symbol, using 100msec updates
func WsPartialDepthServe100Ms(symbol string, levels string, handler WsPartialDepthHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@depth%s@100ms", baseURL, strings.ToLower(symbol), levels)
endpoint := fmt.Sprintf("%s/%s@depth%s@100ms", getWsEndpoint(), strings.ToLower(symbol), levels)
return wsPartialDepthServe(endpoint, symbol, handler, errHandler)
}

Expand Down Expand Up @@ -76,7 +98,7 @@ func wsPartialDepthServe(endpoint string, symbol string, handler WsPartialDepthH

// WsCombinedPartialDepthServe is similar to WsPartialDepthServe, but it for multiple symbols
func WsCombinedPartialDepthServe(symbolLevels map[string]string, handler WsPartialDepthHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := combinedBaseURL
endpoint := getCombinedEndpoint()
for s, l := range symbolLevels {
endpoint += fmt.Sprintf("%s@depth%s", strings.ToLower(s), l) + "/"
}
Expand Down Expand Up @@ -123,13 +145,13 @@ type WsDepthHandler func(event *WsDepthEvent)

// WsDepthServe serve websocket depth handler with a symbol, using 1sec updates
func WsDepthServe(symbol string, handler WsDepthHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@depth", baseURL, strings.ToLower(symbol))
endpoint := fmt.Sprintf("%s/%s@depth", getWsEndpoint(), strings.ToLower(symbol))
return wsDepthServe(endpoint, handler, errHandler)
}

// WsDepthServe100Ms serve websocket depth handler with a symbol, using 100msec updates
func WsDepthServe100Ms(symbol string, handler WsDepthHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@depth@100ms", baseURL, strings.ToLower(symbol))
endpoint := fmt.Sprintf("%s/%s@depth@100ms", getWsEndpoint(), strings.ToLower(symbol))
return wsDepthServe(endpoint, handler, errHandler)
}

Expand Down Expand Up @@ -187,7 +209,7 @@ type WsKlineHandler func(event *WsKlineEvent)

// WsKlineServe serve websocket kline handler with a symbol and interval like 15m, 30s
func WsKlineServe(symbol string, interval string, handler WsKlineHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@kline_%s", baseURL, strings.ToLower(symbol), interval)
endpoint := fmt.Sprintf("%s/%s@kline_%s", getWsEndpoint(), strings.ToLower(symbol), interval)
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
event := new(WsKlineEvent)
Expand Down Expand Up @@ -234,7 +256,7 @@ type WsAggTradeHandler func(event *WsAggTradeEvent)

// WsAggTradeServe serve websocket aggregate handler with a symbol
func WsAggTradeServe(symbol string, handler WsAggTradeHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@aggTrade", baseURL, strings.ToLower(symbol))
endpoint := fmt.Sprintf("%s/%s@aggTrade", getWsEndpoint(), strings.ToLower(symbol))
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
event := new(WsAggTradeEvent)
Expand Down Expand Up @@ -268,7 +290,7 @@ type WsTradeHandler func(event *WsTradeEvent)

// WsTradeServe serve websocket handler with a symbol
func WsTradeServe(symbol string, handler WsTradeHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@trade", baseURL, strings.ToLower(symbol))
endpoint := fmt.Sprintf("%s/%s@trade", getWsEndpoint(), strings.ToLower(symbol))
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
event := new(WsTradeEvent)
Expand Down Expand Up @@ -299,7 +321,7 @@ type WsTradeEvent struct {

// WsUserDataServe serve user data handler with listen key
func WsUserDataServe(listenKey string, handler WsHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s", baseURL, listenKey)
endpoint := fmt.Sprintf("%s/%s", getWsEndpoint(), listenKey)
cfg := newWsConfig(endpoint)
return wsServe(cfg, handler, errHandler)
}
Expand All @@ -309,7 +331,7 @@ type WsMarketStatHandler func(event *WsMarketStatEvent)

// WsMarketStatServe serve websocket that push 24hr statistics for single market every second
func WsMarketStatServe(symbol string, handler WsMarketStatHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@ticker", baseURL, strings.ToLower(symbol))
endpoint := fmt.Sprintf("%s/%s@ticker", getWsEndpoint(), strings.ToLower(symbol))
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
var event WsMarketStatEvent
Expand All @@ -328,7 +350,7 @@ type WsAllMarketsStatHandler func(event WsAllMarketsStatEvent)

// WsAllMarketsStatServe serve websocket that push 24hr statistics for all market every second
func WsAllMarketsStatServe(handler WsAllMarketsStatHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/!ticker@arr", baseURL)
endpoint := fmt.Sprintf("%s/!ticker@arr", getWsEndpoint())
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
var event WsAllMarketsStatEvent
Expand Down Expand Up @@ -377,7 +399,7 @@ type WsAllMiniMarketsStatServeHandler func(event WsAllMiniMarketsStatEvent)

// WsAllMiniMarketsStatServe serve websocket that push mini version of 24hr statistics for all market every second
func WsAllMiniMarketsStatServe(handler WsAllMiniMarketsStatServeHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/!miniTicker@arr", baseURL)
endpoint := fmt.Sprintf("%s/!miniTicker@arr", getWsEndpoint())
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
var event WsAllMiniMarketsStatEvent
Expand Down Expand Up @@ -422,7 +444,7 @@ type WsBookTickerHandler func(event *WsBookTickerEvent)

// WsBookTickerServe serve websocket that pushes updates to the best bid or ask price or quantity in real-time for a specified symbol.
func WsBookTickerServe(symbol string, handler WsBookTickerHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/%s@bookTicker", baseURL, strings.ToLower(symbol))
endpoint := fmt.Sprintf("%s/%s@bookTicker", getWsEndpoint(), strings.ToLower(symbol))
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
event := new(WsBookTickerEvent)
Expand All @@ -438,7 +460,7 @@ func WsBookTickerServe(symbol string, handler WsBookTickerHandler, errHandler Er

// WsAllBookTickerServe serve websocket that pushes updates to the best bid or ask price or quantity in real-time for all symbols.
func WsAllBookTickerServe(handler WsBookTickerHandler, errHandler ErrHandler) (doneC, stopC chan struct{}, err error) {
endpoint := fmt.Sprintf("%s/!bookTicker", baseURL)
endpoint := fmt.Sprintf("%s/!bookTicker", getWsEndpoint())
cfg := newWsConfig(endpoint)
wsHandler := func(message []byte) {
event := new(WsBookTickerEvent)
Expand Down

0 comments on commit 9a93e48

Please sign in to comment.