Skip to content

Commit 64c4320

Browse files
committed
FEATURE: according to margin trading change log, we need to use listenToken to replace listenKey
1 parent 10d93a2 commit 64c4320

File tree

6 files changed

+501
-23
lines changed

6 files changed

+501
-23
lines changed

pkg/exchange/binance/binanceapi/create_margin_account_listen_token_request_requestgen.go

Lines changed: 230 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package binanceapi
2+
3+
import (
4+
"github.com/c9s/bbgo/pkg/types"
5+
"github.com/c9s/requestgen"
6+
)
7+
8+
// CreateMarginAccountListenTokenResponse represents the response from creating a margin account listen token
9+
type CreateMarginAccountListenTokenResponse struct {
10+
Token string `json:"token"`
11+
ExpirationTime types.MillisecondTimestamp `json:"expirationTime"`
12+
}
13+
14+
//go:generate requestgen -method POST -url "/sapi/v1/userListenToken" -type CreateMarginAccountListenTokenRequest -responseType .CreateMarginAccountListenTokenResponse
15+
type CreateMarginAccountListenTokenRequest struct {
16+
client requestgen.AuthenticatedAPIClient
17+
18+
// Trading pair symbol; required when isIsolated is true, e.g., BNBUSDT
19+
symbol *string `param:"symbol"`
20+
21+
// Whether it is isolated margin; true means isolated; default is cross margin
22+
isIsolated *bool `param:"isIsolated"`
23+
24+
// Validity in milliseconds; default 24 hours, maximum 24 hours
25+
validity *int64 `param:"validity"`
26+
}
27+
28+
func (c *RestClient) NewCreateMarginAccountListenTokenRequest() *CreateMarginAccountListenTokenRequest {
29+
return &CreateMarginAccountListenTokenRequest{client: c}
30+
}

pkg/exchange/binance/exchange.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ const TestNetWebSocketURL = "wss://testnet.binance.vision"
5050
const TestNetFuturesBaseURL = "https://testnet.binancefuture.com"
5151

5252
// New WebSocket API Endpoints
53-
// listenKey will be deprecated. Official recommendation is to use ws-api for user data stream
53+
// DEPRECATED (2025-10-06): listenKey via wss://stream.binance.com:9443 will be removed
54+
// Official recommendation is to use ws-api for user data stream or new listenToken subscription method
5455
const WsSpotWebSocketURL = "wss://ws-api.binance.com:443/ws-api/v3"
5556
const WsTestNetWebSocketURL = "wss://testnet.binance.vision/ws-api/v3"
5657

@@ -120,6 +121,11 @@ type Exchange struct {
120121

121122
ed25519authentication
122123

124+
// UseListenKey enables the deprecated listenKey method via wss://stream.binance.com:9443
125+
// This method is deprecated as of 2025-10-06 and will be removed by Binance in the future
126+
// Default behavior (false) uses the new recommended listenToken method
127+
UseListenKey bool
128+
123129
// client is used for spot & margin
124130
client *binance.Client
125131

@@ -240,6 +246,13 @@ func (e *Exchange) setServerTimeOffset(ctx context.Context) {
240246
}
241247
}
242248

249+
// EnableListenKey enables the deprecated listenKey method via wss://stream.binance.com:9443
250+
// This method is deprecated as of 2025-10-06 and will be removed by Binance in the future
251+
// By default, the new listenToken method is used
252+
func (e *Exchange) EnableListenKey() {
253+
e.UseListenKey = true
254+
}
255+
243256
func (e *Exchange) Name() types.ExchangeName {
244257
return types.ExchangeBinance
245258
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package binance
2+
3+
import (
4+
"context"
5+
"testing"
6+
)
7+
8+
func TestExchange_EnableListenKey(t *testing.T) {
9+
exchange := &Exchange{}
10+
11+
// Initially should be false (default uses new method)
12+
if exchange.UseListenKey {
13+
t.Error("UseListenKey should be false by default")
14+
}
15+
16+
// After enabling, should be true (uses deprecated method)
17+
exchange.EnableListenKey()
18+
if !exchange.UseListenKey {
19+
t.Error("UseListenKey should be true after EnableListenKey()")
20+
}
21+
}
22+
23+
func TestStream_ListenKeyConfiguration(t *testing.T) {
24+
// Test default behavior (new listenToken method)
25+
exchange1 := &Exchange{}
26+
stream1 := NewStream(exchange1, nil, nil)
27+
if stream1.useListenKey {
28+
t.Error("Stream should use listenToken method by default (useListenKey should be false)")
29+
}
30+
31+
// Test enabling deprecated listenKey method
32+
exchange2 := &Exchange{}
33+
exchange2.EnableListenKey()
34+
stream2 := NewStream(exchange2, nil, nil)
35+
if !stream2.useListenKey {
36+
t.Error("Stream should have useListenKey enabled when exchange has UseListenKey enabled")
37+
}
38+
}
39+
40+
func TestStream_FetchListenToken_ListenKeyEnabled(t *testing.T) {
41+
stream := &Stream{
42+
useListenKey: true,
43+
}
44+
45+
// Should return error when deprecated listenKey method is enabled
46+
_, _, err := stream.fetchListenToken(context.Background())
47+
if err == nil {
48+
t.Error("Expected error when listenKey method is enabled")
49+
}
50+
}
51+
52+
func TestStream_FetchListenToken_NewMethodDefault(t *testing.T) {
53+
stream := &Stream{
54+
useListenKey: false,
55+
}
56+
57+
// This would normally require a real API client, so we just test the logic check
58+
if stream.useListenKey {
59+
t.Error("useListenKey should be false for new method")
60+
}
61+
}

0 commit comments

Comments
 (0)