Skip to content

Commit

Permalink
Rc 3.5.0 (#272)
Browse files Browse the repository at this point in the history
* Added method for /sapi/v1/asset/wallet/balance endpoint (#268)

* fix: incorrect anchors (#265)

* Add websocket timeout execption handler (#228)

* Add websocket timeout execption handler

* Remove redundant timeout field in BinanceSocketManager

* Add a dedicated websocket error handler

---------

Co-authored-by: Jeremy <[email protected]>

* updates the timeout implementation

---------

Co-authored-by: Akshat Gadhwal <[email protected]>
Co-authored-by: Igor Shadurin <[email protected]>
Co-authored-by: Riyum <[email protected]>
  • Loading branch information
4 people authored Oct 26, 2023
1 parent 3367d18 commit 75c5d53
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 23 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 3.5.0 - 2023-10-26
### Changed
- Add timeout parameter to Websocket clients
- Add method for `GET /sapi/v1/asset/wallet/balance`

## 3.4.0 - 2023-10-07
### Added
- Portfolio endpoints:
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Following these guidelines helps to communicate that you respect the time of the

## Using the issue tracker

The [issue tracker](https://github.com/binance/binance-connector-python/issues) is the preferred channel for [bug reports](#bugs), [features requests](#features) and [submitting pull requests](#pull-requests).
The [issue tracker](https://github.com/binance/binance-connector-python/issues) is the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests) and [submitting pull requests](#pull-requests).

<a name="bugs"></a>

Expand Down Expand Up @@ -98,4 +98,4 @@ Adhering to the following process is the best way to get your work included in t
8. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description.

**IMPORTANT**: By submitting a patch, you agree to allow the project
owners to license your work under the terms of the MIT License.
owners to license your work under the terms of the MIT License.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def message_handler(_, message):

proxies = { 'http': 'http://1.2.3.4:8080' }

my_client = SpotWebsocketAPIClient(on_message=message_handler, proxies=proxies)
my_client = SpotWebsocketAPIClient(on_message=message_handler, proxies=proxies, timeout=10)

my_client.ticker(symbol="BNBBUSD", type="FULL")

Expand All @@ -322,7 +322,7 @@ def message_handler(_, message):

proxies = { 'http': 'http://1.2.3.4:8080' }

my_client = SpotWebsocketStreamClient(on_message=message_handler, proxies=proxies)
my_client = SpotWebsocketStreamClient(on_message=message_handler, proxies=proxies, timeout=10)

# Subscribe to a single symbol stream
my_client.agg_trade(symbol="bnbusdt")
Expand Down
2 changes: 1 addition & 1 deletion binance/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "3.4.0"
__version__ = "3.5.0"
1 change: 1 addition & 0 deletions binance/lib/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
WEBSOCKET_TIMEOUT_IN_SECONDS = 5
1 change: 1 addition & 0 deletions binance/spot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ def __init__(self, api_key=None, api_secret=None, **kwargs):
from binance.spot._wallet import convert_transfer
from binance.spot._wallet import convert_history
from binance.spot._wallet import one_click_arrival_deposit_apply
from binance.spot._wallet import balance

# MINING
from binance.spot._mining import mining_algo_list
Expand Down
17 changes: 17 additions & 0 deletions binance/spot/_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,3 +548,20 @@ def one_click_arrival_deposit_apply(self, **kwargs):

url_path = "/sapi/v1/capital/deposit/credit-apply"
return self.sign_request("POST", url_path, {**kwargs})


def balance(self, **kwargs):
"""Query User Wallet Balance (USER_DATA)
Weight(IP): 60
GET /sapi/v1/asset/wallet/balance
https://binance-docs.github.io/apidocs/spot/en/#query-user-wallet-balance-user_data
Keyword Args:
recvWindow (LONG, optional)
"""

url_path = "/sapi/v1/asset/wallet/balance"
return self.sign_request("GET", url_path, {**kwargs})
44 changes: 28 additions & 16 deletions binance/websocket/binance_socket_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
create_connection,
WebSocketException,
WebSocketConnectionClosedException,
WebSocketTimeoutException,
)
from binance.lib.utils import parse_proxies

Expand All @@ -22,6 +23,7 @@ def __init__(
on_ping=None,
on_pong=None,
logger=None,
timeout=None,
proxies: Optional[dict] = None,
):
threading.Thread.__init__(self)
Expand All @@ -35,19 +37,22 @@ def __init__(
self.on_ping = on_ping
self.on_pong = on_pong
self.on_error = on_error
self.proxies = proxies
self.timeout = timeout

self._proxy_params = parse_proxies(proxies) if proxies else {}

self.create_ws_connection()

def create_ws_connection(self):
self.logger.debug(
f"Creating connection with WebSocket Server: {self.stream_url}, proxies: {self.proxies}",
f"Creating connection with WebSocket Server: {self.stream_url}, proxies: {self._proxy_params}",
)

self.ws = create_connection(
self.stream_url, timeout=self.timeout, **self._proxy_params
)
self.ws = create_connection(self.stream_url, **self._proxy_params)
self.logger.debug(
f"WebSocket connection has been established: {self.stream_url}, proxies: {self.proxies}",
f"WebSocket connection has been established: {self.stream_url}, proxies: {self._proxy_params}",
)
self._callback(self.on_open)

Expand All @@ -69,31 +74,38 @@ def read_data(self):
except WebSocketException as e:
if isinstance(e, WebSocketConnectionClosedException):
self.logger.error("Lost websocket connection")
elif isinstance(e, WebSocketTimeoutException):
self.logger.error("Websocket connection timeout")
else:
self.logger.error("Websocket exception: {}".format(e))
raise e
except Exception as e:
self.logger.error("Exception in read_data: {}".format(e))
raise e

self._handle_data(op_code, frame, data)
self._handle_heartbeat(op_code, frame)

if op_code == ABNF.OPCODE_CLOSE:
self.logger.warning(
"CLOSE frame received, closing websocket connection"
)
self._callback(self.on_close)
break
elif op_code == ABNF.OPCODE_PING:
self._callback(self.on_ping, frame.data)
self.ws.pong("")
self.logger.debug("Received Ping; PONG frame sent back")
elif op_code == ABNF.OPCODE_PONG:
self.logger.debug("Received PONG frame")
self._callback(self.on_pong)
else:
data = frame.data
if op_code == ABNF.OPCODE_TEXT:
data = data.decode("utf-8")
self._callback(self.on_message, data)

def _handle_heartbeat(self, op_code, frame):
if op_code == ABNF.OPCODE_PING:
self._callback(self.on_ping, frame.data)
self.ws.pong("")
self.logger.debug("Received Ping; PONG frame sent back")
elif op_code == ABNF.OPCODE_PONG:
self.logger.debug("Received PONG frame")
self._callback(self.on_pong)

def _handle_data(self, op_code, frame, data):
if op_code == ABNF.OPCODE_TEXT:
data = frame.data.decode("utf-8")
self._callback(self.on_message, data)

def close(self):
if not self.ws.connected:
Expand Down
3 changes: 3 additions & 0 deletions binance/websocket/spot/websocket_api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Optional

from binance.websocket.websocket_client import BinanceWebsocketClient
from binance.lib.constants import WEBSOCKET_TIMEOUT_IN_SECONDS


class SpotWebsocketAPIClient(BinanceWebsocketClient):
Expand All @@ -15,6 +16,7 @@ def __init__(
on_error=None,
on_ping=None,
on_pong=None,
timeout=WEBSOCKET_TIMEOUT_IN_SECONDS,
logger=None,
proxies: Optional[dict] = None,
):
Expand All @@ -30,6 +32,7 @@ def __init__(
on_ping=on_ping,
on_pong=on_pong,
logger=logger,
timeout=timeout,
proxies=proxies,
)

Expand Down
5 changes: 4 additions & 1 deletion binance/websocket/spot/websocket_stream.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from typing import Optional

from binance.websocket.websocket_client import BinanceWebsocketClient
from binance.lib.constants import WEBSOCKET_TIMEOUT_IN_SECONDS


class SpotWebsocketStreamClient(BinanceWebsocketClient):
Expand All @@ -13,8 +14,9 @@ def __init__(
on_error=None,
on_ping=None,
on_pong=None,
logger=None,
is_combined=False,
timeout=WEBSOCKET_TIMEOUT_IN_SECONDS,
logger=None,
proxies: Optional[dict] = None,
):
if is_combined:
Expand All @@ -29,6 +31,7 @@ def __init__(
on_error=on_error,
on_ping=on_ping,
on_pong=on_pong,
timeout=timeout,
logger=logger,
proxies=proxies,
)
Expand Down
4 changes: 4 additions & 0 deletions binance/websocket/websocket_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def __init__(
on_ping=None,
on_pong=None,
logger=None,
timeout=None,
proxies: Optional[dict] = None,
):
if not logger:
Expand All @@ -34,6 +35,7 @@ def __init__(
on_ping,
on_pong,
logger,
timeout,
proxies,
)

Expand All @@ -51,6 +53,7 @@ def _initialize_socket(
on_ping,
on_pong,
logger,
timeout,
proxies,
):
return BinanceSocketManager(
Expand All @@ -62,6 +65,7 @@ def _initialize_socket(
on_ping=on_ping,
on_pong=on_pong,
logger=logger,
timeout=timeout,
proxies=proxies,
)

Expand Down
9 changes: 9 additions & 0 deletions docs/source/CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
Changelog
=========

3.5.0 - 2023-10-26
------------------

Changed
^^^^^^^

* Add timeout parameter to Websocket clients
* Add method for ``GET /sapi/v1/asset/wallet/balance``


3.4.0 - 2023-10-07
------------------
Expand Down
4 changes: 4 additions & 0 deletions docs/source/binance.spot.wallet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,7 @@ BUSD Convert History (USER_DATA)
One click arrival deposit apply (USER_DATA)
-------------------------------------------
.. autofunction:: binance.spot.Spot.one_click_arrival_deposit_apply

Query User Wallet Balance (USER_DATA)
-------------------------------------
.. autofunction:: binance.spot.Spot.balance
13 changes: 13 additions & 0 deletions examples/spot/wallet/balance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python

import logging
from binance.spot import Spot as Client
from binance.lib.utils import config_logging
from examples.utils.prepare_env import get_api_key

config_logging(logging, logging.DEBUG)

api_key, api_secret = get_api_key()

spot_client = Client(api_key, api_secret)
logging.info(spot_client.balance())
7 changes: 6 additions & 1 deletion examples/websocket/spot/websocket_stream/symbol_kline.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ def message_handler(_, message):
logging.info(message)


my_client = SpotWebsocketStreamClient(on_message=message_handler, is_combined=True)
my_client = SpotWebsocketStreamClient(
on_message=message_handler,
is_combined=True,
timeout=2,
proxies={"https": "http://1.2.3.4:8080"},
)


# subscribe btcusdt 1m kline
Expand Down
17 changes: 17 additions & 0 deletions tests/spot/wallet/test_balance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import responses
from binance.spot import Spot as Client
from tests.util import mock_http_response
from tests.util import random_str

mock_item = [{"key_1": "value_1", "key_2": "value_2"}]
key = random_str()
secret = random_str()


@mock_http_response(responses.GET, "/sapi/v1/asset/wallet/balance", mock_item, 200)
def test_balance():
"""Tests the API endpoint to get balance"""

client = Client(key, secret)
response = client.balance()
response.should.equal(mock_item)

0 comments on commit 75c5d53

Please sign in to comment.