diff --git a/CHANGELOG.md b/CHANGELOG.md index e05652b..31e58a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ # Changelog -## [1.5.0] - 2024-AUG-21 +## [1.6.0] - 2024-SEP-05 + +### Added +- Support for WSUserClient to connect to the Coinbase Advanced Trade WebSocket user channel and futures_balance_summary channel + +## [1.5.0] - 2024-AUG-21 ### Added - `get_all_products` parameter to `get_products` and `get_public_products` diff --git a/README.md b/README.md index 929748f..5d8d1c6 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,22 @@ def on_open(): client = WSClient(api_key=api_key, api_secret=api_secret, on_message=on_message, on_open=on_open) ``` +### WebSocket User API Client +We offer a WebSocket User API client that allows you to connect to the Coinbase Advanced Trade WebSocket [user channel](https://docs.cdp.coinbase.com/advanced-trade/docs/ws-channels#user-channel) and [futures_balance_summary channel](https://docs.cdp.coinbase.com/advanced-trade/docs/ws-channels#futures-balance-summary-channel). + +In your code, import the WSUserClient class instead of WSClient. + +```python +from coinbase.websocket import WSUserClient + +api_key = "organizations/{org_id}/apiKeys/{key_id}" +api_secret = "-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n" + +def on_message(msg): + print(msg) + +client = WSUserClient(api_key=api_key, api_secret=api_secret, on_message=on_message) +``` ### Using the WebSocket Client Once you have instantiated the client, you can connect to the WebSocket API by calling the `open` method, and disconnect by calling the `close` method. diff --git a/coinbase/__version__.py b/coinbase/__version__.py index 5b60188..e4adfb8 100644 --- a/coinbase/__version__.py +++ b/coinbase/__version__.py @@ -1 +1 @@ -__version__ = "1.5.0" +__version__ = "1.6.0" diff --git a/coinbase/constants.py b/coinbase/constants.py index a2d99e4..de5217b 100644 --- a/coinbase/constants.py +++ b/coinbase/constants.py @@ -10,6 +10,7 @@ # Websocket Constants WS_BASE_URL = "wss://advanced-trade-ws.coinbase.com" +WS_USER_BASE_URL = "wss://advanced-trade-ws-user.coinbase.com" WS_RETRY_MAX = 5 WS_RETRY_BASE = 5 diff --git a/coinbase/websocket/__init__.py b/coinbase/websocket/__init__.py index d717a94..5e27849 100644 --- a/coinbase/websocket/__init__.py +++ b/coinbase/websocket/__init__.py @@ -1,3 +1,8 @@ +import os +from typing import IO, Callable, Optional, Union + +from coinbase.constants import API_ENV_KEY, API_SECRET_ENV_KEY, WS_USER_BASE_URL + from .websocket_base import WSBase, WSClientConnectionClosedException, WSClientException @@ -65,3 +70,73 @@ class WSClient(WSBase): user_unsubscribe, user_unsubscribe_async, ) + + +class WSUserClient(WSBase): + """ + **WSUserClient** + _____________________________ + + Initialize using WSUserClient + + __________ + + **Parameters**: + + - **api_key | Optional (str)** - The API key + - **api_secret | Optional (str)** - The API key secret + - **key_file | Optional (IO | str)** - Path to API key file or file-like object + - **base_url | (str)** - The websocket base url. Default set to "wss://advanced-trade-ws.coinbase.com" + - **timeout | Optional (int)** - Set timeout in seconds for REST requests + - **max_size | Optional (int)** - Max size in bytes for messages received. Default set to (10 * 1024 * 1024) + - **on_message | Optional (Callable[[str], None])** - Function called when a message is received + - **on_open | Optional ([Callable[[], None]])** - Function called when a connection is opened + - **on_close | Optional ([Callable[[], None]])** - Function called when a connection is closed + - **retry | Optional (bool)** - Enables automatic reconnections. Default set to True + - **verbose | Optional (bool)** - Enables debug logging. Default set to False + + + """ + + from .channels import ( + futures_balance_summary, + futures_balance_summary_async, + futures_balance_summary_unsubscribe, + futures_balance_summary_unsubscribe_async, + heartbeats, + heartbeats_async, + heartbeats_unsubscribe, + heartbeats_unsubscribe_async, + user, + user_async, + user_unsubscribe, + user_unsubscribe_async, + ) + + def __init__( + self, + api_key: Optional[str] = os.getenv(API_ENV_KEY), + api_secret: Optional[str] = os.getenv(API_SECRET_ENV_KEY), + key_file: Optional[Union[IO, str]] = None, + base_url=WS_USER_BASE_URL, + timeout: Optional[int] = None, + max_size: Optional[int] = 10 * 1024 * 1024, + on_message: Optional[Callable[[str], None]] = None, + on_open: Optional[Callable[[], None]] = None, + on_close: Optional[Callable[[], None]] = None, + retry: Optional[bool] = True, + verbose: Optional[bool] = False, + ): + super().__init__( + api_key=api_key, + api_secret=api_secret, + key_file=key_file, + base_url=base_url, + timeout=timeout, + max_size=max_size, + on_message=on_message, + on_open=on_open, + on_close=on_close, + retry=retry, + verbose=verbose, + ) diff --git a/docs/coinbase.rest.rst b/docs/coinbase.rest.rst index c2c7941..4510a81 100644 --- a/docs/coinbase.rest.rst +++ b/docs/coinbase.rest.rst @@ -166,4 +166,4 @@ Payments Data API ------------------------------- -.. autofunction:: coinbase.rest.RESTClient.get_api_key_permissions +.. autofunction:: coinbase.rest.RESTClient.get_api_key_permissions \ No newline at end of file diff --git a/docs/coinbase.websocket.user.rst b/docs/coinbase.websocket.user.rst new file mode 100644 index 0000000..38ce1d5 --- /dev/null +++ b/docs/coinbase.websocket.user.rst @@ -0,0 +1,44 @@ +Websocket User API Client +===================== + +WSUserClient Constructor +--------------------------- + +.. autoclass:: coinbase.websocket.WSUserClient + +WebSocket Utils +--------------------------- + +.. autofunction:: coinbase.websocket.WSUserClient.open +.. autofunction:: coinbase.websocket.WSUserClient.open_async +.. autofunction:: coinbase.websocket.WSUserClient.close +.. autofunction:: coinbase.websocket.WSUserClient.close_async +.. autofunction:: coinbase.websocket.WSUserClient.subscribe +.. autofunction:: coinbase.websocket.WSUserClient.subscribe_async +.. autofunction:: coinbase.websocket.WSUserClient.unsubscribe +.. autofunction:: coinbase.websocket.WSUserClient.unsubscribe_async +.. autofunction:: coinbase.websocket.WSUserClient.unsubscribe_all +.. autofunction:: coinbase.websocket.WSUserClient.unsubscribe_all_async +.. autofunction:: coinbase.websocket.WSUserClient.sleep_with_exception_check +.. autofunction:: coinbase.websocket.WSUserClient.sleep_with_exception_check_async +.. autofunction:: coinbase.websocket.WSUserClient.run_forever_with_exception_check +.. autofunction:: coinbase.websocket.WSUserClient.run_forever_with_exception_check_async +.. autofunction:: coinbase.websocket.WSUserClient.raise_background_exception + +Channels +----------------------------- + +.. autofunction:: coinbase.websocket.WSUserClient.heartbeats +.. autofunction:: coinbase.websocket.WSUserClient.heartbeats_async +.. autofunction:: coinbase.websocket.WSUserClient.heartbeats_unsubscribe +.. autofunction:: coinbase.websocket.WSUserClient.heartbeats_unsubscribe_async +.. autofunction:: coinbase.websocket.WSUserClient.user +.. autofunction:: coinbase.websocket.WSUserClient.user_async +.. autofunction:: coinbase.websocket.WSUserClient.user_unsubscribe +.. autofunction:: coinbase.websocket.WSUserClient.user_unsubscribe_async + +Exceptions +--------------------------- + +.. autofunction:: coinbase.websocket.WSUserClientException +.. autofunction:: coinbase.websocket.WSUserClientConnectionClosedException