Skip to content

Commit bbf04cd

Browse files
authored
feat: upgrade margin socket to use websocket api (#1670)
1 parent 6e4364d commit bbf04cd

File tree

3 files changed

+271
-9
lines changed

3 files changed

+271
-9
lines changed

binance/async_client.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import Any, Dict, List, Optional, Union
44
from urllib.parse import urlencode, quote
55
import time
6+
import warnings
67
import aiohttp
78
import yarl
89

@@ -1417,6 +1418,14 @@ async def get_open_margin_oco_orders(self, **params):
14171418
get_open_margin_oco_orders.__doc__ = Client.get_open_margin_oco_orders.__doc__
14181419

14191420
async def margin_stream_get_listen_key(self):
1421+
warnings.warn(
1422+
"POST /sapi/v1/userDataStream is deprecated and will be removed on 2026-02-20. "
1423+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken, "
1424+
"then subscribe with userDataStream.subscribe.listenToken). "
1425+
"The margin_socket() method now uses WebSocket API by default.",
1426+
DeprecationWarning,
1427+
stacklevel=2
1428+
)
14201429
res = await self._request_margin_api(
14211430
"post", "userDataStream", signed=False, data={}
14221431
)
@@ -1425,6 +1434,14 @@ async def margin_stream_get_listen_key(self):
14251434
margin_stream_get_listen_key.__doc__ = Client.margin_stream_get_listen_key.__doc__
14261435

14271436
async def margin_stream_keepalive(self, listenKey):
1437+
warnings.warn(
1438+
"PUT /sapi/v1/userDataStream is deprecated and will be removed on 2026-02-20. "
1439+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken, "
1440+
"then subscribe with userDataStream.subscribe.listenToken). "
1441+
"The margin_socket() method now uses WebSocket API by default.",
1442+
DeprecationWarning,
1443+
stacklevel=2
1444+
)
14281445
params = {"listenKey": listenKey}
14291446
return await self._request_margin_api(
14301447
"put", "userDataStream", signed=False, data=params
@@ -1433,16 +1450,65 @@ async def margin_stream_keepalive(self, listenKey):
14331450
margin_stream_keepalive.__doc__ = Client.margin_stream_keepalive.__doc__
14341451

14351452
async def margin_stream_close(self, listenKey):
1453+
warnings.warn(
1454+
"DELETE /sapi/v1/userDataStream is deprecated and will be removed on 2026-02-20. "
1455+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken, "
1456+
"then subscribe with userDataStream.subscribe.listenToken). "
1457+
"The margin_socket() method now uses WebSocket API by default.",
1458+
DeprecationWarning,
1459+
stacklevel=2
1460+
)
14361461
params = {"listenKey": listenKey}
14371462
return await self._request_margin_api(
14381463
"delete", "userDataStream", signed=False, data=params
14391464
)
14401465

1466+
async def margin_create_listen_token(self, symbol: Optional[str] = None, is_isolated: bool = False, validity: Optional[int] = None):
1467+
"""Create a listenToken for margin account user data stream
1468+
1469+
https://developers.binance.com/docs/margin_trading/trade-data-stream/Create-Margin-Account-listenToken
1470+
1471+
:param symbol: Trading pair symbol (required when is_isolated=True)
1472+
:type symbol: str
1473+
:param is_isolated: Whether it is isolated margin (default: False for cross-margin)
1474+
:type is_isolated: bool
1475+
:param validity: Validity in milliseconds (default: 24 hours, max: 24 hours)
1476+
:type validity: int
1477+
:returns: API response with token and expirationTime
1478+
1479+
.. code-block:: python
1480+
1481+
{
1482+
"token": "6xXxePXwZRjVSHKhzUCCGnmN3fkvMTXru+pYJS8RwijXk9Vcyr3rkwfVOTcP2OkONqciYA",
1483+
"expirationTime": 1758792204196
1484+
}
1485+
"""
1486+
params = {}
1487+
if is_isolated:
1488+
if not symbol:
1489+
raise ValueError("symbol is required when is_isolated=True")
1490+
params["symbol"] = symbol
1491+
params["isIsolated"] = "true"
1492+
if validity is not None:
1493+
params["validity"] = validity
1494+
1495+
return await self._request_margin_api(
1496+
"post", "userListenToken", signed=True, data=params
1497+
)
1498+
14411499
# Isolated margin
14421500

14431501
margin_stream_close.__doc__ = Client.margin_stream_close.__doc__
14441502

14451503
async def isolated_margin_stream_get_listen_key(self, symbol):
1504+
warnings.warn(
1505+
"POST /sapi/v1/userDataStream/isolated is deprecated and will be removed on 2026-02-20. "
1506+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken "
1507+
"with isIsolated=true, then subscribe with userDataStream.subscribe.listenToken). "
1508+
"The isolated_margin_socket() method now uses WebSocket API by default.",
1509+
DeprecationWarning,
1510+
stacklevel=2
1511+
)
14461512
params = {"symbol": symbol}
14471513
res = await self._request_margin_api(
14481514
"post", "userDataStream/isolated", signed=False, data=params
@@ -1452,6 +1518,14 @@ async def isolated_margin_stream_get_listen_key(self, symbol):
14521518
isolated_margin_stream_get_listen_key.__doc__ = Client.isolated_margin_stream_get_listen_key.__doc__
14531519

14541520
async def isolated_margin_stream_keepalive(self, symbol, listenKey):
1521+
warnings.warn(
1522+
"PUT /sapi/v1/userDataStream/isolated is deprecated and will be removed on 2026-02-20. "
1523+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken "
1524+
"with isIsolated=true, then subscribe with userDataStream.subscribe.listenToken). "
1525+
"The isolated_margin_socket() method now uses WebSocket API by default.",
1526+
DeprecationWarning,
1527+
stacklevel=2
1528+
)
14551529
params = {"symbol": symbol, "listenKey": listenKey}
14561530
return await self._request_margin_api(
14571531
"put", "userDataStream/isolated", signed=False, data=params
@@ -1460,6 +1534,14 @@ async def isolated_margin_stream_keepalive(self, symbol, listenKey):
14601534
isolated_margin_stream_keepalive.__doc__ = Client.isolated_margin_stream_keepalive.__doc__
14611535

14621536
async def isolated_margin_stream_close(self, symbol, listenKey):
1537+
warnings.warn(
1538+
"DELETE /sapi/v1/userDataStream/isolated is deprecated and will be removed on 2026-02-20. "
1539+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken "
1540+
"with isIsolated=true, then subscribe with userDataStream.subscribe.listenToken). "
1541+
"The isolated_margin_socket() method now uses WebSocket API by default.",
1542+
DeprecationWarning,
1543+
stacklevel=2
1544+
)
14631545
params = {"symbol": symbol, "listenKey": listenKey}
14641546
return await self._request_margin_api(
14651547
"delete", "userDataStream/isolated", signed=False, data=params

binance/client.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
import requests
55
import time
6+
import warnings
67
from urllib.parse import urlencode, quote
78

89
from .base_client import BaseClient
@@ -5667,6 +5668,14 @@ def margin_stream_get_listen_key(self):
56675668
:raises: BinanceRequestException, BinanceAPIException
56685669

56695670
"""
5671+
warnings.warn(
5672+
"POST /sapi/v1/userDataStream is deprecated and will be removed on 2026-02-20. "
5673+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken, "
5674+
"then subscribe with userDataStream.subscribe.listenToken). "
5675+
"The margin_socket() method now uses WebSocket API by default.",
5676+
DeprecationWarning,
5677+
stacklevel=2
5678+
)
56705679
res = self._request_margin_api("post", "userDataStream", signed=False, data={})
56715680
return res["listenKey"]
56725681

@@ -5687,6 +5696,14 @@ def margin_stream_keepalive(self, listenKey):
56875696
:raises: BinanceRequestException, BinanceAPIException
56885697

56895698
"""
5699+
warnings.warn(
5700+
"PUT /sapi/v1/userDataStream is deprecated and will be removed on 2026-02-20. "
5701+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken, "
5702+
"then subscribe with userDataStream.subscribe.listenToken). "
5703+
"The margin_socket() method now uses WebSocket API by default.",
5704+
DeprecationWarning,
5705+
stacklevel=2
5706+
)
56905707
params = {"listenKey": listenKey}
56915708
return self._request_margin_api(
56925709
"put", "userDataStream", signed=False, data=params
@@ -5709,11 +5726,54 @@ def margin_stream_close(self, listenKey):
57095726
:raises: BinanceRequestException, BinanceAPIException
57105727

57115728
"""
5729+
warnings.warn(
5730+
"DELETE /sapi/v1/userDataStream is deprecated and will be removed on 2026-02-20. "
5731+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken, "
5732+
"then subscribe with userDataStream.subscribe.listenToken). "
5733+
"The margin_socket() method now uses WebSocket API by default.",
5734+
DeprecationWarning,
5735+
stacklevel=2
5736+
)
57125737
params = {"listenKey": listenKey}
57135738
return self._request_margin_api(
57145739
"delete", "userDataStream", signed=False, data=params
57155740
)
57165741

5742+
def margin_create_listen_token(self, symbol: Optional[str] = None, is_isolated: bool = False, validity: Optional[int] = None):
5743+
"""Create a listenToken for margin account user data stream
5744+
5745+
https://developers.binance.com/docs/margin_trading/trade-data-stream/Create-Margin-Account-listenToken
5746+
5747+
:param symbol: Trading pair symbol (required when is_isolated=True)
5748+
:type symbol: str
5749+
:param is_isolated: Whether it is isolated margin (default: False for cross-margin)
5750+
:type is_isolated: bool
5751+
:param validity: Validity in milliseconds (default: 24 hours, max: 24 hours)
5752+
:type validity: int
5753+
:returns: API response with token and expirationTime
5754+
5755+
.. code-block:: python
5756+
5757+
{
5758+
"token": "6xXxePXwZRjVSHKhzUCCGnmN3fkvMTXru+pYJS8RwijXk9Vcyr3rkwfVOTcP2OkONqciYA",
5759+
"expirationTime": 1758792204196
5760+
}
5761+
5762+
:raises: BinanceRequestException, BinanceAPIException
5763+
"""
5764+
params = {}
5765+
if is_isolated:
5766+
if not symbol:
5767+
raise ValueError("symbol is required when is_isolated=True")
5768+
params["symbol"] = symbol
5769+
params["isIsolated"] = "true"
5770+
if validity is not None:
5771+
params["validity"] = validity
5772+
5773+
return self._request_margin_api(
5774+
"post", "userListenToken", signed=True, data=params
5775+
)
5776+
57175777
# Isolated margin
57185778

57195779
def isolated_margin_stream_get_listen_key(self, symbol):
@@ -5739,6 +5799,14 @@ def isolated_margin_stream_get_listen_key(self, symbol):
57395799
:raises: BinanceRequestException, BinanceAPIException
57405800

57415801
"""
5802+
warnings.warn(
5803+
"POST /sapi/v1/userDataStream/isolated is deprecated and will be removed on 2026-02-20. "
5804+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken "
5805+
"with isIsolated=true, then subscribe with userDataStream.subscribe.listenToken). "
5806+
"The isolated_margin_socket() method now uses WebSocket API by default.",
5807+
DeprecationWarning,
5808+
stacklevel=2
5809+
)
57425810
params = {"symbol": symbol}
57435811
res = self._request_margin_api(
57445812
"post", "userDataStream/isolated", signed=False, data=params
@@ -5764,6 +5832,14 @@ def isolated_margin_stream_keepalive(self, symbol, listenKey):
57645832
:raises: BinanceRequestException, BinanceAPIException
57655833

57665834
"""
5835+
warnings.warn(
5836+
"PUT /sapi/v1/userDataStream/isolated is deprecated and will be removed on 2026-02-20. "
5837+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken "
5838+
"with isIsolated=true, then subscribe with userDataStream.subscribe.listenToken). "
5839+
"The isolated_margin_socket() method now uses WebSocket API by default.",
5840+
DeprecationWarning,
5841+
stacklevel=2
5842+
)
57675843
params = {"symbol": symbol, "listenKey": listenKey}
57685844
return self._request_margin_api(
57695845
"put", "userDataStream/isolated", signed=False, data=params
@@ -5788,6 +5864,14 @@ def isolated_margin_stream_close(self, symbol, listenKey):
57885864
:raises: BinanceRequestException, BinanceAPIException
57895865

57905866
"""
5867+
warnings.warn(
5868+
"DELETE /sapi/v1/userDataStream/isolated is deprecated and will be removed on 2026-02-20. "
5869+
"Use the WebSocket API subscription method instead (create listenToken via POST /sapi/v1/userListenToken "
5870+
"with isIsolated=true, then subscribe with userDataStream.subscribe.listenToken). "
5871+
"The isolated_margin_socket() method now uses WebSocket API by default.",
5872+
DeprecationWarning,
5873+
stacklevel=2
5874+
)
57915875
params = {"symbol": symbol, "listenKey": listenKey}
57925876
return self._request_margin_api(
57935877
"delete", "userDataStream/isolated", signed=False, data=params

0 commit comments

Comments
 (0)