Skip to content
5 changes: 4 additions & 1 deletion check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,14 @@ function lint() {
golint -set_exit_status ./...
}

# There is a bug if we define the same json tag in the struct.
# Disable structtag temporarily.
# see: https://github.com/golang/go/issues/40102
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not a bug, is a feature

Duplicate json tags, making the intent of the code unclear.

think this

func TestSameJsonTag(t *testing.T) {
	data := []byte(`{
	"i":"1"
	}`)

	type V struct {
		Ii int    `json:"i"`
		S  string `json:"i"`
	}

	var v V
	if err := json.Unmarshal(data, &v); err != nil {
		t.Fatal(err)
	}
	if v.Ii != 0 {
		t.Errorf("i expected %d, got %d", 0, v.Ii)
	}
	if v.S != "1" {
		t.Errorf("i expected %s, got %s", "1", v.S)
	}
}

function vet() {
echo "Running go vet ..."
(
cd v2
go vet ./...
go vet -structtag=false ./...
)
}

Expand Down
7 changes: 7 additions & 0 deletions examples/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ type Config struct {
APIKey string
SecretKey string
UseTestnet bool
UseDemo bool
}

// Global configuration instance
var AppConfig = &Config{
APIKey: getEnvOrDefault("BINANCE_API_KEY", ""),
SecretKey: getEnvOrDefault("BINANCE_SECRET_KEY", ""),
UseTestnet: getEnvOrDefault("BINANCE_USE_TESTNET", "true") == "true",
UseDemo: getEnvOrDefault("BINANCE_USE_DEMO", "true") == "true",
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value for UseDemo is set to "true", which means the demo environment will be used by default when BINANCE_USE_DEMO is not set. This is likely unintended as most users would expect the production environment by default. Consider changing the default to "false".

Suggested change
UseDemo: getEnvOrDefault("BINANCE_USE_DEMO", "true") == "true",
UseDemo: getEnvOrDefault("BINANCE_USE_DEMO", "false") == "true",

Copilot uses AI. Check for mistakes.
}

// getEnvOrDefault returns the environment variable value or a default if not set
Expand All @@ -40,6 +42,11 @@ func (c *Config) SetupTestnet() {
binance.UseTestnet = c.UseTestnet
}

// SetupDemo configures demo usage based on the config
func (c *Config) SetupDemo() {
binance.UseDemo = c.UseDemo
}

// Validate checks if the configuration is valid
func (c *Config) Validate() error {
if strings.TrimSpace(c.APIKey) == "" {
Expand Down
9 changes: 7 additions & 2 deletions examples/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ func main() {
}

// Setup testnet
AppConfig.SetupTestnet()
// AppConfig.SetupTestnet()

// Setup demo
// AppConfig.SetupDemo()

fmt.Println("=== Binance API Examples ===")
fmt.Printf("Using testnet: %v\n", AppConfig.UseTestnet)
fmt.Printf("Using demo: %v\n", AppConfig.UseDemo)
fmt.Println()

// Run examples
Expand All @@ -27,6 +31,7 @@ func main() {
// FuturesOrder()
// DeliveryOrder()
// WalletBalance()
WatchMiniMarketsStat()
// WatchMiniMarketsStat()
// RunOrderListExamples()
WatchFuturesUserDataStream()
}
51 changes: 51 additions & 0 deletions examples/watcher_futures.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package main

import (
"context"
"fmt"
"os"
"os/signal"

"github.com/adshao/go-binance/v2"
"github.com/adshao/go-binance/v2/futures"
)

func WatchFuturesUserDataStream() {
futures.UseDemo = true
apiKey := ""
secret := ""
client := binance.NewFuturesClient(apiKey, secret)

listenKey, err := client.NewStartUserStreamService().Do(context.Background())
if err != nil {
panic(err)
}

userDataHandler := func(event *futures.WsUserDataEvent) {
fmt.Printf("Event: %s, Time: %d\n", event.Event, event.Time)

switch event.Event {
case futures.UserDataEventTypeAlgoUpdate:
fmt.Printf("ALGO update: %+v\n", event.AlgoUpdate)
case futures.UserDataEventTypeTradeLite:
fmt.Printf("Trade lite: %+v\n", event)
}
}

errHandler := func(err error) {
panic(err)
}

doneC, stopC, err := futures.WsUserDataServe(listenKey, userDataHandler, errHandler)
if err != nil {
fmt.Println(err)
return
}
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
select {
case <-c:
stopC <- struct{}{}
}
<-doneC
}
9 changes: 8 additions & 1 deletion v2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ type FuturesAlgoOrderStatusType string
var (
BaseAPIMainURL = "https://api.binance.com"
BaseAPITestnetURL = "https://testnet.binance.vision"
BaseAPIDemoURL = "https://demo-api.binance.com"
)

// SelfTradePreventionMode define self trade prevention strategy
Expand All @@ -139,6 +140,9 @@ type MarginAccountBorrowRepayType string
// UseTestnet switch all the API endpoints from production to the testnet
var UseTestnet = false

// UseDemo switch all the API endpoints from production to the demo
var UseDemo = false

// Global enums
const (
SideTypeBuy SideType = "BUY"
Expand Down Expand Up @@ -361,6 +365,9 @@ func getAPIEndpoint() string {
if UseTestnet {
return BaseAPITestnetURL
}
if UseDemo {
return BaseAPIDemoURL
}
return BaseAPIMainURL
Comment on lines 365 to 371
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The endpoint selection logic has a potential issue: if both UseTestnet and UseDemo are set to true, UseTestnet takes precedence and UseDemo is ignored. Consider adding validation to ensure only one environment flag is active at a time, or document this priority explicitly.

Copilot uses AI. Check for mistakes.
}

Expand Down Expand Up @@ -436,7 +443,7 @@ type Client struct {
OrderCount common.OrderCount
}

func (c *Client) debug(format string, v ...interface{}) {
func (c *Client) debug(format string, v ...any) {
if c.Debug {
c.Logger.Printf(format, v...)
}
Expand Down
4 changes: 2 additions & 2 deletions v2/common/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func ToJSONList(v []byte) []byte {
return v
}

func ToInt(digit interface{}) (i int, err error) {
func ToInt(digit any) (i int, err error) {
if intVal, ok := digit.(int); ok {
return int(intVal), nil
}
Expand All @@ -44,7 +44,7 @@ func ToInt(digit interface{}) (i int, err error) {
return 0, fmt.Errorf("unexpected digit: %v", digit)
}

func ToInt64(digit interface{}) (i int64, err error) {
func ToInt64(digit any) (i int64, err error) {
if intVal, ok := digit.(int); ok {
return int64(intVal), nil
}
Expand Down
2 changes: 1 addition & 1 deletion v2/common/websocket/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ type client struct {
reconnectCount int64
}

func (c *client) debug(format string, v ...interface{}) {
func (c *client) debug(format string, v ...any) {
if c.Debug {
c.logger.Println(fmt.Sprintf(format, v...))
}
Expand Down
16 changes: 8 additions & 8 deletions v2/common/websocket/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import (
)

type testApiRequest struct {
Id string `json:"id"`
Method string `json:"method"`
Params map[string]interface{} `json:"params"`
Id string `json:"id"`
Method string `json:"method"`
Params map[string]any `json:"params"`
}

func (s *clientTestSuite) SetupTest() {
Expand Down Expand Up @@ -81,7 +81,7 @@ func (s *clientTestSuite) TestReadWriteSync() {
req := testApiRequest{
Id: requestID,
Method: "some-method",
Params: map[string]interface{}{},
Params: map[string]any{},
}
reqRaw, err := json.Marshal(req)
s.Require().NoError(err)
Expand All @@ -101,7 +101,7 @@ func (s *clientTestSuite) TestReadWriteSync() {
req := testApiRequest{
Id: "some-other-request-id",
Method: "some-method",
Params: map[string]interface{}{},
Params: map[string]any{},
}
reqRaw, err := json.Marshal(req)
s.Require().NoError(err)
Expand All @@ -112,7 +112,7 @@ func (s *clientTestSuite) TestReadWriteSync() {
req = testApiRequest{
Id: requestID,
Method: "some-method",
Params: map[string]interface{}{},
Params: map[string]any{},
}
reqRaw, err = json.Marshal(req)
s.Require().NoError(err)
Expand All @@ -132,7 +132,7 @@ func (s *clientTestSuite) TestReadWriteSync() {
req := testApiRequest{
Id: requestID,
Method: "some-method",
Params: map[string]interface{}{
Params: map[string]any{
"timeout": "true",
},
}
Expand All @@ -154,7 +154,7 @@ func (s *clientTestSuite) TestReadWriteSync() {
req := testApiRequest{
Id: requestID,
Method: "some-method",
Params: map[string]interface{}{},
Params: map[string]any{},
}
reqRaw, err := json.Marshal(req)
s.Require().NoError(err)
Expand Down
8 changes: 4 additions & 4 deletions v2/common/websocket/mock/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions v2/common/websocket/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ type WsApiMethodType string

// WsApiRequest define common websocket API request
type WsApiRequest struct {
Id string `json:"id"`
Method WsApiMethodType `json:"method"`
Params map[string]interface{} `json:"params"`
Id string `json:"id"`
Method WsApiMethodType `json:"method"`
Params map[string]any `json:"params"`
}

var (
Expand Down Expand Up @@ -112,7 +112,7 @@ type RequestData struct {
}

// CreateRequest creates signed ws request
func CreateRequest(reqData RequestData, method WsApiMethodType, params map[string]interface{}) ([]byte, error) {
func CreateRequest(reqData RequestData, method WsApiMethodType, params map[string]any) ([]byte, error) {
if reqData.requestID == "" {
return nil, ErrorRequestIDNotSet
}
Expand Down Expand Up @@ -153,7 +153,7 @@ func CreateRequest(reqData RequestData, method WsApiMethodType, params map[strin
}

// encode encodes the parameters to a URL encoded string
func encodeParams(p map[string]interface{}) string {
func encodeParams(p map[string]any) string {
queryValues := url.Values{}
for key, value := range p {
queryValues.Add(key, fmt.Sprintf("%v", value))
Expand Down
6 changes: 5 additions & 1 deletion v2/delivery/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type UserDataEventReasonType string
var (
BaseApiMainUrl = "https://dapi.binance.com"
BaseApiTestnetUrl = "https://testnet.binancefuture.com"
BaseApiDemoURL = "https://demo-dapi.binance.com"
)

// Global enums
Expand Down Expand Up @@ -180,6 +181,9 @@ func getApiEndpoint() string {
if UseTestnet {
return BaseApiTestnetUrl
}
if UseDemo {
return BaseApiDemoURL
}
return BaseApiMainUrl
Comment on lines 181 to 187
Copy link

Copilot AI Jan 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The endpoint selection logic has a potential issue: if both UseTestnet and UseDemo are set to true, UseTestnet takes precedence and UseDemo is ignored. Consider adding validation to ensure only one environment flag is active at a time, or document this priority explicitly.

Copilot uses AI. Check for mistakes.
}

Expand Down Expand Up @@ -239,7 +243,7 @@ type Client struct {
OrderCount common.OrderCount
}

func (c *Client) debug(format string, v ...interface{}) {
func (c *Client) debug(format string, v ...any) {
if c.Debug {
c.Logger.Printf(format, v...)
}
Expand Down
Loading
Loading