Skip to content

feat: migrate USDⓈ-M futures WS to /public, /market, /private base URLs#809

Merged
carlosmiei merged 4 commits intoccxt:masterfrom
pcriadoperez:ws-endpoitns
Apr 7, 2026
Merged

feat: migrate USDⓈ-M futures WS to /public, /market, /private base URLs#809
carlosmiei merged 4 commits intoccxt:masterfrom
pcriadoperez:ws-endpoitns

Conversation

@pcriadoperez
Copy link
Copy Markdown
Collaborator

  • Split futures WebSocket base URLs into /public (bookTicker, depth), /market (aggTrade, markPrice, kline, ticker, etc.), and /private (user data/listenKey) per Binance announcement 2026-03-06
  • All stream functions now route to the correct dedicated endpoint; legacy getWsEndpoint()/getCombinedEndpoint() kept for backward compatibility
  • Legacy URLs will be decommissioned on 2026-04-23

Split WebSocket endpoints per Binance announcement (2026-03-06):
- Public (bookTicker, depth) → /public
- Market (aggTrade, markPrice, kline, ticker, etc.) → /market
- Private (user data/listenKey) → /private

Legacy URLs retired 2026-04-23.
@pcriadoperez
Copy link
Copy Markdown
Collaborator Author

WS Endpoint Integration Test Results (v3 — Full Coverage)

All 42 tests pass across demo and testnet, now covering every stream from the Binance migration notice including the newly implemented !contractInfo, assetIndex, and private query-param/stream modes.

New implementations added

  1. WsContractInfoServe!contractInfo market stream
  2. WsAssetIndexServe<symbol>@assetIndex market stream
  3. WsAllAssetIndexServe!assetIndex@arr market stream
  4. WsUserDataServeWithEvents — private ws mode: ?listenKey=<key>&events=EVENT1/EVENT2
  5. WsUserDataServeMultiple — private stream mode: multiple listenKeys + events
  6. WsCompositeIndexEvent.BaseAssetType field — fixes pre-existing JSON unmarshal bug (Go case-insensitive "C" colliding with "c")
  7. WsComposition.QuoteAsset / IndexPrice fields — missing from server payload

Bugfix: WsCompositeIndexEvent JSON unmarshal error

The server sends both "C": "baseAsset" and "c": [...]. Go's case-insensitive JSON matching caused "C" to match the json:"c" tag, producing cannot unmarshal string into []WsComposition. Fixed by adding explicit BaseAssetType string \json:"C"`` field.

How to run

BINANCE_APIKEY="..." BINANCE_SECRET="..." \
  go test -v -run 'TestWsEndpoints_' -count=1 -timeout 300s ./futures/

Full coverage matrix

Endpoint Function Params Demo Testnet
/market WsAggTradeServe symbol
/market WsCombinedAggTradeServe symbols[]
/market WsKlineServe symbol, interval
/market WsCombinedKlineServe symbol:interval map
/market WsCombinedKlineServeMultiInterval symbol:intervals[]
/market WsMarkPriceServe symbol
/market WsMarkPriceServeWithRate symbol, rate=3s
/market WsAllMarkPriceServe (none)
/market WsAllMarkPriceServeWithRate rate=3s
/market WsCombinedMarkPriceServe symbols[]
/market WsCombinedMarkPriceServeWithRate symbol:rate map
/market WsMarketTickerServe symbol
/market WsAllMarketTickerServe (none)
/market WsMiniMarketTickerServe symbol
/market WsAllMiniMarketTickerServe (none)
/market WsContinuousKlineServe pair, contractType, interval
/market WsCombinedContinuousKlineServe subscribeArgs[]
/market WsLiquidationOrderServe symbol
/market WsAllLiquidationOrderServe (none)
/market WsCompositiveIndexServe symbol
/market WsContractInfoServe 🆕 (none)
/market WsAssetIndexServe 🆕 symbol
/market WsAllAssetIndexServe 🆕 (none)
/public WsBookTickerServe symbol
/public WsCombinedBookTickerServe symbols[]
/public WsAllBookTickerServe (none)
/public WsPartialDepthServe symbol, levels=5
/public WsPartialDepthServeWithRate symbol, levels=10, rate=500ms
/public WsDiffDepthServe symbol
/public WsDiffDepthServeWithRate symbol, rate=500ms
/public WsCombinedDepthServe symbol:level map
/public WsCombinedDiffDepthServe symbols[]
/private WsUserDataServe listenKey (path)
/private WsUserDataServeWithEvents 🆕 listenKey, events[] (query)
/private WsUserDataServeMultiple 🆕 configs[] (stream mode)

Output

=== RUN   TestWsEndpoints_Demo_Market_AggTrade
  [demo/market] aggTrade symbol=BTCUSDT price=69094.50 qty=0.0020
--- PASS: TestWsEndpoints_Demo_Market_AggTrade (2.84s)
=== RUN   TestWsEndpoints_Demo_Market_Kline
  [demo/market] kline symbol=BTCUSDT open=69094.50 close=69094.50
--- PASS: TestWsEndpoints_Demo_Market_Kline (2.31s)
=== RUN   TestWsEndpoints_Demo_Market_MarkPrice
  [demo/market] markPrice symbol=BTCUSDT price=69055.70000000 funding=0.00005595
--- PASS: TestWsEndpoints_Demo_Market_MarkPrice (3.30s)
=== RUN   TestWsEndpoints_Demo_Market_Ticker
  [demo/market] ticker symbol=BTCUSDT last=69092.40
--- PASS: TestWsEndpoints_Demo_Market_Ticker (2.02s)
=== RUN   TestWsEndpoints_Demo_Market_MiniTicker
  [demo/market] miniTicker symbol=BTCUSDT close=69097.20
--- PASS: TestWsEndpoints_Demo_Market_MiniTicker (2.06s)
=== RUN   TestWsEndpoints_Demo_Market_CombinedAggTrade
  [demo/market] combined aggTrade symbol=ETHUSDT price=2121.35
--- PASS: TestWsEndpoints_Demo_Market_CombinedAggTrade (1.61s)
=== RUN   TestWsEndpoints_Demo_Market_CombinedKline
  [demo/market] combined kline symbol=BTCUSDT
--- PASS: TestWsEndpoints_Demo_Market_CombinedKline (1.30s)
=== RUN   TestWsEndpoints_Demo_Public_BookTicker
  [demo/public] bookTicker symbol=BTCUSDT bid=69092.40 ask=69097.20
--- PASS: TestWsEndpoints_Demo_Public_BookTicker (1.18s)
=== RUN   TestWsEndpoints_Demo_Public_Depth
  [demo/public] depth bids=5 asks=5
--- PASS: TestWsEndpoints_Demo_Public_Depth (1.98s)
=== RUN   TestWsEndpoints_Demo_Public_DiffDepth
  [demo/public] diffDepth bids=4 asks=2
--- PASS: TestWsEndpoints_Demo_Public_DiffDepth (1.02s)
=== RUN   TestWsEndpoints_Demo_Public_CombinedBookTicker
  [demo/public] combined bookTicker symbol=BTCUSDT
--- PASS: TestWsEndpoints_Demo_Public_CombinedBookTicker (1.00s)
=== RUN   TestWsEndpoints_Demo_Public_CombinedDepth
  [demo/public] combined depth bids=5
--- PASS: TestWsEndpoints_Demo_Public_CombinedDepth (1.24s)
=== RUN   TestWsEndpoints_Demo_Public_CombinedDiffDepth
  [demo/public] combined diffDepth bids=3
--- PASS: TestWsEndpoints_Demo_Public_CombinedDiffDepth (1.18s)
=== RUN   TestWsEndpoints_Demo_Private_UserData
    listen key: e9QQlkJ0...
--- PASS: TestWsEndpoints_Demo_Private_UserData (4.23s)
=== RUN   TestWsEndpoints_Demo_Market_MarkPriceWithRate
  [demo/market] markPrice@1s symbol=BTCUSDT price=69051.90000000
--- PASS: TestWsEndpoints_Demo_Market_MarkPriceWithRate (2.15s)
=== RUN   TestWsEndpoints_Demo_Market_AllMarkPrice
  [demo/market] !markPrice@arr count=692 first=BTCUSDT
--- PASS: TestWsEndpoints_Demo_Market_AllMarkPrice (3.28s)
=== RUN   TestWsEndpoints_Demo_Market_AllMarkPriceWithRate
  [demo/market] !markPrice@arr@1s count=692
--- PASS: TestWsEndpoints_Demo_Market_AllMarkPriceWithRate (2.99s)
=== RUN   TestWsEndpoints_Demo_Market_CombinedMarkPriceWithRate
  [demo/market] combined markPrice@1s symbol=BTCUSDT
--- PASS: TestWsEndpoints_Demo_Market_CombinedMarkPriceWithRate (2.73s)
=== RUN   TestWsEndpoints_Demo_Market_CombinedKlineMultiInterval
  [demo/market] combined kline multi symbol=BTCUSDT interval=1m
--- PASS: TestWsEndpoints_Demo_Market_CombinedKlineMultiInterval (1.47s)
=== RUN   TestWsEndpoints_Demo_Market_ContinuousKline
  [demo/market] continuousKline pair=BTCUSDT interval=1m
--- PASS: TestWsEndpoints_Demo_Market_ContinuousKline (1.40s)
=== RUN   TestWsEndpoints_Demo_Market_CombinedContinuousKline
  [demo/market] combined continuousKline pair=BTCUSDT
--- PASS: TestWsEndpoints_Demo_Market_CombinedContinuousKline (1.23s)
=== RUN   TestWsEndpoints_Demo_Market_AllMiniTicker
  [demo/market] !miniTicker@arr count=335
--- PASS: TestWsEndpoints_Demo_Market_AllMiniTicker (1.67s)
=== RUN   TestWsEndpoints_Demo_Market_AllTicker
  [demo/market] !ticker@arr count=302
--- PASS: TestWsEndpoints_Demo_Market_AllTicker (2.05s)
=== RUN   TestWsEndpoints_Demo_Public_AllBookTicker
  [demo/public] !bookTicker symbol=FLUXUSDT
--- PASS: TestWsEndpoints_Demo_Public_AllBookTicker (1.00s)
=== RUN   TestWsEndpoints_Demo_Public_PartialDepthWithRate
  [demo/public] depth@10@500ms bids=10 asks=10
--- PASS: TestWsEndpoints_Demo_Public_PartialDepthWithRate (1.12s)
=== RUN   TestWsEndpoints_Demo_Public_DiffDepthWithRate
  [demo/public] diffDepth@500ms bids=6 asks=1
--- PASS: TestWsEndpoints_Demo_Public_DiffDepthWithRate (1.24s)
=== RUN   TestWsEndpoints_Demo_Market_LiquidationOrder
--- PASS: TestWsEndpoints_Demo_Market_LiquidationOrder (3.98s)
=== RUN   TestWsEndpoints_Demo_Market_AllLiquidationOrder
--- PASS: TestWsEndpoints_Demo_Market_AllLiquidationOrder (3.97s)
=== RUN   TestWsEndpoints_Demo_Market_CompositeIndex
  [demo/market] compositeIndex symbol=DEFIUSDT price=305.44541868 baseAssetType=baseAsset compositions=30
    first: base=1INCH quote=USDT weight=0.02500900 indexPrice=0.08936811
--- PASS: TestWsEndpoints_Demo_Market_CompositeIndex (1.85s)
=== RUN   TestWsEndpoints_Testnet_Market_AggTrade
  [testnet/market] aggTrade symbol=BTCUSDT price=69086.70
--- PASS: TestWsEndpoints_Testnet_Market_AggTrade (1.67s)
=== RUN   TestWsEndpoints_Testnet_Market_CombinedMarkPrice
  [testnet/market] combined markPrice symbol=BTCUSDT
--- PASS: TestWsEndpoints_Testnet_Market_CombinedMarkPrice (1.34s)
=== RUN   TestWsEndpoints_Testnet_Public_BookTicker
  [testnet/public] bookTicker symbol=BTCUSDT bid=69086.60 ask=69097.30
--- PASS: TestWsEndpoints_Testnet_Public_BookTicker (1.48s)
=== RUN   TestWsEndpoints_Testnet_Public_CombinedDepth
  [testnet/public] combined depth bids=5
--- PASS: TestWsEndpoints_Testnet_Public_CombinedDepth (1.32s)
=== RUN   TestWsEndpoints_Testnet_Private_UserData
    listen key: e9QQlkJ0...
--- PASS: TestWsEndpoints_Testnet_Private_UserData (4.20s)
=== RUN   TestWsEndpoints_Demo_Market_ContractInfo
--- PASS: TestWsEndpoints_Demo_Market_ContractInfo (3.97s)
=== RUN   TestWsEndpoints_Demo_Market_AssetIndex
  [demo/market] assetIndex symbol=BTCUSD index=69095.84120655 bidRate=65641.04914622 askRate=72550.63326687
--- PASS: TestWsEndpoints_Demo_Market_AssetIndex (1.99s)
=== RUN   TestWsEndpoints_Demo_Market_AllAssetIndex
  [demo/market] !assetIndex@arr count=10 first=BNFCRUSD index=1.00000000
--- PASS: TestWsEndpoints_Demo_Market_AllAssetIndex (2.00s)
=== RUN   TestWsEndpoints_Demo_Private_UserDataWithEvents
    listen key: e9QQlkJ0...
--- PASS: TestWsEndpoints_Demo_Private_UserDataWithEvents (4.20s)
=== RUN   TestWsEndpoints_Demo_Private_UserDataMultiple
    listen key: e9QQlkJ0...
--- PASS: TestWsEndpoints_Demo_Private_UserDataMultiple (4.20s)
=== RUN   TestWsEndpoints_Testnet_Market_AssetIndex
  [testnet/market] assetIndex symbol=BTCUSD index=69062.36559668
--- PASS: TestWsEndpoints_Testnet_Market_AssetIndex (1.59s)
=== RUN   TestWsEndpoints_Testnet_Private_UserDataWithEvents
    listen key: e9QQlkJ0...
--- PASS: TestWsEndpoints_Testnet_Private_UserDataWithEvents (4.20s)
PASS
ok      github.com/adshao/go-binance/v2/futures   92.009s

…ry-param support

- Fix testnet/demo URLs to use /public, /market, /private path segments
  (verified working on both environments)
- Add WsContractInfoServe for !contractInfo market stream
- Add WsAssetIndexServe and WsAllAssetIndexServe for assetIndex streams
- Add WsUserDataServeWithEvents for private ws mode with event filtering
  (?listenKey=<key>&events=EVENT1/EVENT2)
- Add WsUserDataServeMultiple for private stream mode with multiple
  listenKeys (/private/stream?listenKey=...&events=...&listenKey=...)
- Fix WsCompositeIndexEvent JSON unmarshal error caused by Go's
  case-insensitive matching of "C" field colliding with "c" tag
- Add missing QuoteAsset and IndexPrice fields to WsComposition
- Add comprehensive integration test suite (46 tests) covering all
  /public, /market, /private streams on demo and testnet
@pcriadoperez pcriadoperez marked this pull request as ready for review April 6, 2026 01:32
@carlosmiei carlosmiei merged commit 0e30464 into ccxt:master Apr 7, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants