python-binance 1.0.28__tar.gz → 1.0.30__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {python_binance-1.0.28/python_binance.egg-info → python-binance-1.0.30}/PKG-INFO +4 -3
  2. {python_binance-1.0.28 → python-binance-1.0.30}/README.rst +3 -2
  3. {python_binance-1.0.28 → python-binance-1.0.30}/binance/__init__.py +1 -1
  4. {python_binance-1.0.28 → python-binance-1.0.30}/binance/async_client.py +114 -19
  5. {python_binance-1.0.28 → python-binance-1.0.30}/binance/base_client.py +32 -8
  6. {python_binance-1.0.28 → python-binance-1.0.30}/binance/client.py +1309 -526
  7. {python_binance-1.0.28 → python-binance-1.0.30}/binance/exceptions.py +4 -0
  8. {python_binance-1.0.28 → python-binance-1.0.30}/binance/helpers.py +2 -2
  9. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/depthcache.py +8 -7
  10. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/keepalive_websocket.py +45 -6
  11. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/reconnecting_websocket.py +17 -4
  12. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/streams.py +46 -5
  13. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/threaded_stream.py +23 -9
  14. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/websocket_api.py +20 -7
  15. {python_binance-1.0.28 → python-binance-1.0.30}/pyproject.toml +3 -2
  16. {python_binance-1.0.28 → python-binance-1.0.30/python_binance.egg-info}/PKG-INFO +4 -3
  17. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client.py +107 -85
  18. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client_futures.py +12 -116
  19. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client_margin.py +0 -144
  20. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client_options.py +2 -28
  21. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client_ws_api.py +2 -30
  22. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client_ws_futures_requests.py +24 -8
  23. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client.py +55 -3
  24. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client_futures.py +14 -12
  25. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client_options.py +2 -1
  26. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client_ws_api.py +3 -0
  27. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client_ws_futures_requests.py +13 -2
  28. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_get_order_book.py +2 -0
  29. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_reconnecting_websocket.py +21 -3
  30. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_socket_manager.py +2 -1
  31. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_streams_options.py +45 -4
  32. python-binance-1.0.30/tests/test_threaded_socket_manager.py +191 -0
  33. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_threaded_stream.py +3 -1
  34. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_ws_api.py +58 -35
  35. python_binance-1.0.28/tests/test_threaded_socket_manager.py +0 -34
  36. {python_binance-1.0.28 → python-binance-1.0.30}/LICENSE +0 -0
  37. {python_binance-1.0.28 → python-binance-1.0.30}/binance/enums.py +0 -0
  38. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/__init__.py +0 -0
  39. {python_binance-1.0.28 → python-binance-1.0.30}/binance/ws/constants.py +0 -0
  40. {python_binance-1.0.28 → python-binance-1.0.30}/python_binance.egg-info/SOURCES.txt +0 -0
  41. {python_binance-1.0.28 → python-binance-1.0.30}/python_binance.egg-info/dependency_links.txt +0 -0
  42. {python_binance-1.0.28 → python-binance-1.0.30}/python_binance.egg-info/requires.txt +0 -0
  43. {python_binance-1.0.28 → python-binance-1.0.30}/python_binance.egg-info/top_level.txt +0 -0
  44. {python_binance-1.0.28 → python-binance-1.0.30}/setup.cfg +0 -0
  45. {python_binance-1.0.28 → python-binance-1.0.30}/setup.py +0 -0
  46. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_api_request.py +0 -0
  47. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client_gift_card copy.py +0 -0
  48. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_async_client_portfolio.py +0 -0
  49. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client_gift_card.py +0 -0
  50. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client_margin.py +0 -0
  51. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_client_portfolio.py +0 -0
  52. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_cryptography.py +0 -0
  53. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_depth_cache.py +0 -0
  54. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_futures.py +0 -0
  55. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_headers.py +0 -0
  56. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_historical_klines.py +0 -0
  57. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_ids.py +0 -0
  58. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_init.py +0 -0
  59. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_order.py +0 -0
  60. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_ping.py +0 -0
  61. {python_binance-1.0.28 → python-binance-1.0.30}/tests/test_streams.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-binance
3
- Version: 1.0.28
3
+ Version: 1.0.30
4
4
  Summary: Binance REST API python implementation
5
5
  Home-page: https://github.com/sammchardy/python-binance
6
6
  Author: Sam McHardy
@@ -31,7 +31,7 @@ Requires-Dist: websockets
31
31
  Requires-Dist: pycryptodome
32
32
 
33
33
  =================================
34
- Welcome to python-binance v1.0.28
34
+ Welcome to python-binance v1.0.30
35
35
  =================================
36
36
 
37
37
  .. image:: https://img.shields.io/pypi/v/python-binance.svg
@@ -95,7 +95,8 @@ Features
95
95
 
96
96
  - Implementation of all General, Market Data and Account endpoints.
97
97
  - Asyncio implementation
98
- - Testnet support for Spot, Futures and Vanilla Options
98
+ - Demo trading support (by providing demo=True)
99
+ - Testnet support for Spot, Futures and Vanilla Options (deprecated)
99
100
  - Simple handling of authentication include RSA and EDDSA keys
100
101
  - No need to generate timestamps yourself, the wrapper does it for you
101
102
  - RecvWindow sent by default
@@ -1,5 +1,5 @@
1
1
  =================================
2
- Welcome to python-binance v1.0.28
2
+ Welcome to python-binance v1.0.30
3
3
  =================================
4
4
 
5
5
  .. image:: https://img.shields.io/pypi/v/python-binance.svg
@@ -63,7 +63,8 @@ Features
63
63
 
64
64
  - Implementation of all General, Market Data and Account endpoints.
65
65
  - Asyncio implementation
66
- - Testnet support for Spot, Futures and Vanilla Options
66
+ - Demo trading support (by providing demo=True)
67
+ - Testnet support for Spot, Futures and Vanilla Options (deprecated)
67
68
  - Simple handling of authentication include RSA and EDDSA keys
68
69
  - No need to generate timestamps yourself, the wrapper does it for you
69
70
  - RecvWindow sent by default
@@ -4,7 +4,7 @@
4
4
 
5
5
  """
6
6
 
7
- __version__ = "1.0.28"
7
+ __version__ = "1.0.30"
8
8
 
9
9
  from binance.async_client import AsyncClient # noqa
10
10
  from binance.client import Client # noqa
@@ -31,6 +31,7 @@ class AsyncClient(BaseClient):
31
31
  tld: str = "com",
32
32
  base_endpoint: str = BaseClient.BASE_ENDPOINT_DEFAULT,
33
33
  testnet: bool = False,
34
+ demo: bool = False,
34
35
  loop=None,
35
36
  session_params: Optional[Dict[str, Any]] = None,
36
37
  private_key: Optional[Union[str, Path]] = None,
@@ -41,6 +42,15 @@ class AsyncClient(BaseClient):
41
42
  self.https_proxy = https_proxy
42
43
  self.loop = loop or get_loop()
43
44
  self._session_params: Dict[str, Any] = session_params or {}
45
+
46
+ # Convert https_proxy to requests_params format for BaseClient
47
+ if https_proxy and requests_params is None:
48
+ requests_params = {'proxies': {'http': https_proxy, 'https': https_proxy}}
49
+ elif https_proxy and requests_params is not None:
50
+ if 'proxies' not in requests_params:
51
+ requests_params['proxies'] = {}
52
+ requests_params['proxies'].update({'http': https_proxy, 'https': https_proxy})
53
+
44
54
  super().__init__(
45
55
  api_key,
46
56
  api_secret,
@@ -48,6 +58,7 @@ class AsyncClient(BaseClient):
48
58
  tld,
49
59
  base_endpoint,
50
60
  testnet,
61
+ demo,
51
62
  private_key,
52
63
  private_key_pass,
53
64
  time_unit=time_unit,
@@ -62,9 +73,13 @@ class AsyncClient(BaseClient):
62
73
  tld: str = "com",
63
74
  base_endpoint: str = BaseClient.BASE_ENDPOINT_DEFAULT,
64
75
  testnet: bool = False,
76
+ demo: bool = False,
65
77
  loop=None,
66
78
  session_params: Optional[Dict[str, Any]] = None,
79
+ private_key: Optional[Union[str, Path]] = None,
80
+ private_key_pass: Optional[str] = None,
67
81
  https_proxy: Optional[str] = None,
82
+ time_unit: Optional[str] = None,
68
83
  ):
69
84
  self = cls(
70
85
  api_key,
@@ -73,8 +88,13 @@ class AsyncClient(BaseClient):
73
88
  tld,
74
89
  base_endpoint,
75
90
  testnet,
91
+ demo,
76
92
  loop,
77
93
  session_params,
94
+ private_key,
95
+ private_key_pass,
96
+ https_proxy,
97
+ time_unit
78
98
  )
79
99
  self.https_proxy = https_proxy # move this to the constructor
80
100
 
@@ -144,6 +164,9 @@ class AsyncClient(BaseClient):
144
164
  url_encoded_data = urlencode(dict_data)
145
165
  data = f"{url_encoded_data}&signature={signature}"
146
166
 
167
+ # Remove proxies from kwargs since aiohttp uses 'proxy' parameter instead
168
+ kwargs.pop('proxies', None)
169
+
147
170
  async with getattr(self.session, method)(
148
171
  yarl.URL(uri, encoded=True),
149
172
  proxy=self.https_proxy,
@@ -162,7 +185,8 @@ class AsyncClient(BaseClient):
162
185
  if not str(response.status).startswith("2"):
163
186
  raise BinanceAPIException(response, response.status, await response.text())
164
187
 
165
- if response.text == "":
188
+ text = await response.text()
189
+ if text == "":
166
190
  return {}
167
191
 
168
192
  try:
@@ -275,7 +299,7 @@ class AsyncClient(BaseClient):
275
299
  get_products.__doc__ = Client.get_products.__doc__
276
300
 
277
301
  async def get_exchange_info(self) -> Dict:
278
- return await self._get("exchangeInfo", version=self.PRIVATE_API_VERSION)
302
+ return await self._get("exchangeInfo")
279
303
 
280
304
  get_exchange_info.__doc__ = Client.get_exchange_info.__doc__
281
305
 
@@ -293,12 +317,12 @@ class AsyncClient(BaseClient):
293
317
  # General Endpoints
294
318
 
295
319
  async def ping(self) -> Dict:
296
- return await self._get("ping", version=self.PRIVATE_API_VERSION)
320
+ return await self._get("ping")
297
321
 
298
322
  ping.__doc__ = Client.ping.__doc__
299
323
 
300
324
  async def get_server_time(self) -> Dict:
301
- return await self._get("time", version=self.PRIVATE_API_VERSION)
325
+ return await self._get("time")
302
326
 
303
327
  get_server_time.__doc__ = Client.get_server_time.__doc__
304
328
 
@@ -311,7 +335,7 @@ class AsyncClient(BaseClient):
311
335
  if symbol:
312
336
  params["symbol"] = symbol
313
337
  response = await self._get(
314
- "ticker/price", version=self.PRIVATE_API_VERSION, data=params
338
+ "ticker/price", data=params
315
339
  )
316
340
  if isinstance(response, list) and all(isinstance(item, dict) for item in response):
317
341
  return response
@@ -326,13 +350,13 @@ class AsyncClient(BaseClient):
326
350
  elif "symbols" in params:
327
351
  data["symbols"] = params["symbols"]
328
352
  return await self._get(
329
- "ticker/bookTicker", data=data, version=self.PRIVATE_API_VERSION
353
+ "ticker/bookTicker", data=data
330
354
  )
331
355
 
332
356
  get_orderbook_tickers.__doc__ = Client.get_orderbook_tickers.__doc__
333
357
 
334
358
  async def get_order_book(self, **params) -> Dict:
335
- return await self._get("depth", data=params, version=self.PRIVATE_API_VERSION)
359
+ return await self._get("depth", data=params)
336
360
 
337
361
  get_order_book.__doc__ = Client.get_order_book.__doc__
338
362
 
@@ -343,14 +367,14 @@ class AsyncClient(BaseClient):
343
367
 
344
368
  async def get_historical_trades(self, **params) -> Dict:
345
369
  return await self._get(
346
- "historicalTrades", data=params, version=self.PRIVATE_API_VERSION
370
+ "historicalTrades", data=params
347
371
  )
348
372
 
349
373
  get_historical_trades.__doc__ = Client.get_historical_trades.__doc__
350
374
 
351
375
  async def get_aggregate_trades(self, **params) -> Dict:
352
376
  return await self._get(
353
- "aggTrades", data=params, version=self.PRIVATE_API_VERSION
377
+ "aggTrades", data=params
354
378
  )
355
379
 
356
380
  get_aggregate_trades.__doc__ = Client.get_aggregate_trades.__doc__
@@ -411,12 +435,12 @@ class AsyncClient(BaseClient):
411
435
  aggregate_trade_iter.__doc__ = Client.aggregate_trade_iter.__doc__
412
436
 
413
437
  async def get_ui_klines(self, **params) -> Dict:
414
- return await self._get("uiKlines", data=params, version=self.PRIVATE_API_VERSION)
438
+ return await self._get("uiKlines", data=params)
415
439
 
416
440
  get_ui_klines.__doc__ = Client.get_ui_klines.__doc__
417
441
 
418
442
  async def get_klines(self, **params) -> Dict:
419
- return await self._get("klines", data=params, version=self.PRIVATE_API_VERSION)
443
+ return await self._get("klines", data=params)
420
444
 
421
445
  get_klines.__doc__ = Client.get_klines.__doc__
422
446
 
@@ -647,33 +671,33 @@ class AsyncClient(BaseClient):
647
671
 
648
672
  async def get_avg_price(self, **params):
649
673
  return await self._get(
650
- "avgPrice", data=params, version=self.PRIVATE_API_VERSION
674
+ "avgPrice", data=params
651
675
  )
652
676
 
653
677
  get_avg_price.__doc__ = Client.get_avg_price.__doc__
654
678
 
655
679
  async def get_ticker(self, **params):
656
680
  return await self._get(
657
- "ticker/24hr", data=params, version=self.PRIVATE_API_VERSION
681
+ "ticker/24hr", data=params
658
682
  )
659
683
 
660
684
  get_ticker.__doc__ = Client.get_ticker.__doc__
661
685
 
662
686
  async def get_symbol_ticker(self, **params):
663
687
  return await self._get(
664
- "ticker/price", data=params, version=self.PRIVATE_API_VERSION
688
+ "ticker/price", data=params
665
689
  )
666
690
 
667
691
  get_symbol_ticker.__doc__ = Client.get_symbol_ticker.__doc__
668
692
 
669
693
  async def get_symbol_ticker_window(self, **params):
670
- return await self._get("ticker", data=params, version=self.PRIVATE_API_VERSION)
694
+ return await self._get("ticker", data=params)
671
695
 
672
696
  get_symbol_ticker_window.__doc__ = Client.get_symbol_ticker_window.__doc__
673
697
 
674
698
  async def get_orderbook_ticker(self, **params):
675
699
  return await self._get(
676
- "ticker/bookTicker", data=params, version=self.PRIVATE_API_VERSION
700
+ "ticker/bookTicker", data=params
677
701
  )
678
702
 
679
703
  get_orderbook_ticker.__doc__ = Client.get_orderbook_ticker.__doc__
@@ -1719,11 +1743,11 @@ class AsyncClient(BaseClient):
1719
1743
 
1720
1744
  futures_premium_index_klines.__doc__ = Client.futures_index_price_klines.__doc__
1721
1745
 
1722
- async def futures_continous_klines(self, **params):
1746
+ async def futures_continuous_klines(self, **params):
1723
1747
  return await self._request_futures_api("get", "continuousKlines", data=params)
1724
1748
 
1725
1749
  async def futures_historical_klines(
1726
- self, symbol, interval, start_str, end_str=None, limit=500
1750
+ self, symbol: str, interval: str, start_str, end_str=None, limit=None
1727
1751
  ):
1728
1752
  return await self._historical_klines(
1729
1753
  symbol,
@@ -1868,6 +1892,77 @@ class AsyncClient(BaseClient):
1868
1892
  params["newClientOrderId"] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1869
1893
  return await self._request_futures_api("post", "order", True, data=params)
1870
1894
 
1895
+ async def futures_limit_order(self, **params):
1896
+ """Send in a new futures limit order.
1897
+
1898
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api
1899
+
1900
+ """
1901
+ if "newClientOrderId" not in params:
1902
+ params["newClientOrderId"] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1903
+ params["type"] = "LIMIT"
1904
+ return await self._request_futures_api("post", "order", True, data=params)
1905
+
1906
+ async def futures_market_order(self, **params):
1907
+ """Send in a new futures market order.
1908
+
1909
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api
1910
+
1911
+ """
1912
+ if "newClientOrderId" not in params:
1913
+ params["newClientOrderId"] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1914
+ params["type"] = "MARKET"
1915
+ return await self._request_futures_api("post", "order", True, data=params)
1916
+
1917
+
1918
+ async def futures_limit_buy_order(self, **params):
1919
+ """Send in a new futures limit buy order.
1920
+
1921
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api
1922
+
1923
+ """
1924
+ if "newClientOrderId" not in params:
1925
+ params["newClientOrderId"] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1926
+ params["side"] = "BUY"
1927
+ params["type"] = "LIMIT"
1928
+ return await self._request_futures_api("post", "order", True, data=params)
1929
+
1930
+ async def futures_limit_sell_order(self, **params):
1931
+ """Send in a new futures limit sell order.
1932
+
1933
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api
1934
+
1935
+ """
1936
+ if "newClientOrderId" not in params:
1937
+ params["newClientOrderId"] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1938
+ params["side"] = "SELL"
1939
+ params["type"] = "LIMIT"
1940
+ return await self._request_futures_api("post", "order", True, data=params)
1941
+
1942
+ async def futures_market_buy_order(self, **params):
1943
+ """Send in a new futures market buy order.
1944
+
1945
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api
1946
+
1947
+ """
1948
+ if "newClientOrderId" not in params:
1949
+ params["newClientOrderId"] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1950
+ params["side"] = "BUY"
1951
+ params["type"] = "MARKET"
1952
+ return await self._request_futures_api("post", "order", True, data=params)
1953
+
1954
+ async def futures_market_sell_order(self, **params):
1955
+ """Send in a new futures market sell order.
1956
+
1957
+ https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api
1958
+
1959
+ """
1960
+ if "newClientOrderId" not in params:
1961
+ params["newClientOrderId"] = self.CONTRACT_ORDER_PREFIX + self.uuid22()
1962
+ params["side"] = "SELL"
1963
+ params["type"] = "MARKET"
1964
+ return await self._request_futures_api("post", "order", True, data=params)
1965
+
1871
1966
  async def futures_modify_order(self, **params):
1872
1967
  """Modify an existing order. Currently only LIMIT order modification is supported.
1873
1968
 
@@ -5355,4 +5450,4 @@ class AsyncClient(BaseClient):
5355
5450
  return await self._request_futures_api("get", "convert/orderStatus", signed=True, data=params, version=1)
5356
5451
 
5357
5452
  futures_v1_get_convert_order_status.__doc__ = Client.futures_v1_get_convert_order_status.__doc__
5358
-
5453
+
@@ -22,24 +22,29 @@ from .helpers import get_loop
22
22
  class BaseClient:
23
23
  API_URL = "https://api{}.binance.{}/api"
24
24
  API_TESTNET_URL = "https://testnet.binance.vision/api"
25
+ API_DEMO_URL = "https://demo-api.binance.com/api"
25
26
  MARGIN_API_URL = "https://api{}.binance.{}/sapi"
26
27
  WEBSITE_URL = "https://www.binance.{}"
27
28
  FUTURES_URL = "https://fapi.binance.{}/fapi"
28
29
  FUTURES_TESTNET_URL = "https://testnet.binancefuture.com/fapi"
30
+ FUTURES_DEMO_URL = "https://demo-fapi.binance.com/fapi"
29
31
  FUTURES_DATA_URL = "https://fapi.binance.{}/futures/data"
30
32
  FUTURES_DATA_TESTNET_URL = "https://testnet.binancefuture.com/futures/data"
31
33
  FUTURES_COIN_URL = "https://dapi.binance.{}/dapi"
32
34
  FUTURES_COIN_TESTNET_URL = "https://testnet.binancefuture.com/dapi"
35
+ FUTURES_COIN_DEMO_URL = "https://demo-dapi.binance.com/dapi"
33
36
  FUTURES_COIN_DATA_URL = "https://dapi.binance.{}/futures/data"
34
37
  FUTURES_COIN_DATA_TESTNET_URL = "https://testnet.binancefuture.com/futures/data"
35
38
  OPTIONS_URL = "https://eapi.binance.{}/eapi"
36
39
  OPTIONS_TESTNET_URL = "https://testnet.binanceops.{}/eapi"
37
40
  PAPI_URL = "https://papi.binance.{}/papi"
38
41
  WS_API_URL = "wss://ws-api.binance.{}/ws-api/v3"
39
- WS_API_TESTNET_URL = "wss://testnet.binance.vision/ws-api/v3"
42
+ WS_API_TESTNET_URL = "wss://ws-api.testnet.binance.vision/ws-api/v3"
43
+ WS_API_DEMO_URL = "wss://demo-ws-api.binance.com/ws-api/v3"
40
44
  WS_FUTURES_URL = "wss://ws-fapi.binance.{}/ws-fapi/v1"
41
45
  WS_FUTURES_TESTNET_URL = "wss://testnet.binancefuture.com/ws-fapi/v1"
42
- PUBLIC_API_VERSION = "v1"
46
+ WS_FUTURES_DEMO_URL = "wss://testnet.binancefuture.com/ws-fapi/v1"
47
+ PUBLIC_API_VERSION = "v3"
43
48
  PRIVATE_API_VERSION = "v3"
44
49
  MARGIN_API_VERSION = "v1"
45
50
  MARGIN_API_VERSION2 = "v2"
@@ -157,6 +162,7 @@ class BaseClient:
157
162
  tld: str = "com",
158
163
  base_endpoint: str = BASE_ENDPOINT_DEFAULT,
159
164
  testnet: bool = False,
165
+ demo: bool = False,
160
166
  private_key: Optional[Union[str, Path]] = None,
161
167
  private_key_pass: Optional[str] = None,
162
168
  loop: Optional[asyncio.AbstractEventLoop] = None,
@@ -201,15 +207,27 @@ class BaseClient:
201
207
  self._requests_params = requests_params
202
208
  self.response = None
203
209
  self.testnet = testnet
210
+ self.demo = demo
204
211
  self.timestamp_offset = 0
205
- ws_api_url = self.WS_API_TESTNET_URL if testnet else self.WS_API_URL.format(tld)
212
+ ws_api_url = self.WS_API_URL.format(tld)
213
+ if testnet:
214
+ ws_api_url = self.WS_API_TESTNET_URL
215
+ elif demo:
216
+ ws_api_url = self.WS_API_DEMO_URL
206
217
  if self.TIME_UNIT:
207
218
  ws_api_url += f"?timeUnit={self.TIME_UNIT}"
208
- self.ws_api = WebsocketAPI(url=ws_api_url, tld=tld)
209
- ws_future_url = (
210
- self.WS_FUTURES_TESTNET_URL if testnet else self.WS_FUTURES_URL.format(tld)
211
- )
212
- self.ws_future = WebsocketAPI(url=ws_future_url, tld=tld)
219
+ # Extract proxy from requests_params for WebSocket connections
220
+ https_proxy = None
221
+ if requests_params and 'proxies' in requests_params:
222
+ https_proxy = requests_params['proxies'].get('https') or requests_params['proxies'].get('http')
223
+
224
+ self.ws_api = WebsocketAPI(url=ws_api_url, tld=tld, https_proxy=https_proxy)
225
+ ws_future_url = self.WS_FUTURES_URL.format(tld)
226
+ if testnet:
227
+ ws_future_url = self.WS_FUTURES_TESTNET_URL
228
+ elif demo:
229
+ ws_future_url = self.WS_FUTURES_DEMO_URL
230
+ self.ws_future = WebsocketAPI(url=ws_future_url, tld=tld, https_proxy=https_proxy)
213
231
  self.loop = loop or get_loop()
214
232
 
215
233
  def _get_headers(self) -> Dict:
@@ -250,6 +268,8 @@ class BaseClient:
250
268
  url = self.API_URL
251
269
  if self.testnet:
252
270
  url = self.API_TESTNET_URL
271
+ elif self.demo:
272
+ url = self.API_DEMO_URL
253
273
  v = self.PRIVATE_API_VERSION if signed else version
254
274
  return url + "/" + v + "/" + path
255
275
 
@@ -273,6 +293,8 @@ class BaseClient:
273
293
  url = self.FUTURES_URL
274
294
  if self.testnet:
275
295
  url = self.FUTURES_TESTNET_URL
296
+ elif self.demo:
297
+ url = self.FUTURES_DEMO_URL
276
298
  options = {
277
299
  1: self.FUTURES_API_VERSION,
278
300
  2: self.FUTURES_API_VERSION2,
@@ -290,6 +312,8 @@ class BaseClient:
290
312
  url = self.FUTURES_COIN_URL
291
313
  if self.testnet:
292
314
  url = self.FUTURES_COIN_TESTNET_URL
315
+ elif self.demo:
316
+ url = self.FUTURES_COIN_DEMO_URL
293
317
  options = {
294
318
  1: self.FUTURES_API_VERSION,
295
319
  2: self.FUTURES_API_VERSION2,