Merge pull request #220 from Davi0kProgramsThings/feature/documentation

Merge branch `Davi0kProgramsThings:feature/documentation` into branch `bitfinexcom:v3-beta`.
This commit is contained in:
Vigan Abdurrahmani
2023-04-26 17:08:40 +02:00
committed by GitHub
2 changed files with 236 additions and 94 deletions

328
README.md
View File

@@ -8,56 +8,99 @@ Beta versions should not be used in applications which require user authenticati
Provide your API-KEY/API-SECRET, and manage your account and funds at your own risk. Provide your API-KEY/API-SECRET, and manage your account and funds at your own risk.
### Features ### Features
- User-friendly implementations for 75+ public and authenticated REST endpoints.
* A complete list of available REST endpoints can be found [here](https://docs.bitfinex.com/reference).
- New WebSocket client to ensure fast, secure and persistent connections.
* Support for all public channels + authenticated events and inputs (a list can be found [here](https://docs.bitfinex.com/docs/ws-public)).
* Automatic reconnection system in case of network failure (both client and server side).
- The WebSocket client logs every reconnection failure, success and attempt (as well as other events).
* Connection multiplexing to allow subscribing to a large number of public channels (without affecting performances).
- The WebSocket server sets a limit of 25 subscriptions per connection, connection multiplexing allows the WebSocket client to bypass this limit.
- Full type-hinting and type-checking support with [`mypy`](https://github.com/python/mypy).
* This allow text editors to show helpful hints about the value of a variable: ![example](https://i.imgur.com/aDjapcN.png "Type-hinting example on a random code snippet")
--- * Support for 75+ REST endpoints (a list of available endpoints can be found [here](https://docs.bitfinex.com/reference))
* New WebSocket client to ensure fast, secure and persistent connections
* Full support for Bitfinex notifications (including custom notifications)
* Native support for type hinting and type checking with [`mypy`](https://github.com/python/mypy)
## Installation ## Installation
To install the latest beta release of `bitfinex-api-py`: ```console
```bash
python3 -m pip install --pre bitfinex-api-py python3 -m pip install --pre bitfinex-api-py
``` ```
To install a specific beta version:
```bash ### Selecting and installing a specific beta version
It's also possible to select and install a specific beta version:
```console
python3 -m pip install bitfinex-api-py==3.0.0b1 python3 -m pip install bitfinex-api-py==3.0.0b1
``` ```
## Basic usage
--- ---
### Index # Quickstart
* [WebSocket Client documentation](#websocket-client-documentation) ```python
* [Building the source code](#building-the-source-code) from bfxapi import Client, REST_HOST
from bfxapi.types import Notification, Order
bfx = Client(
rest_host=REST_HOST,
api_key="<YOUR BFX API-KEY>",
api_secret="<YOUR BFX API-SECRET>"
)
notification: Notification[Order] = bfx.rest.auth.submit_order(
type="EXCHANGE LIMIT", symbol="tBTCUSD", amount=0.165212, price=30264.0)
order: Order = notification.data
if notification.status == "SUCCESS":
print(f"Successful new order for {order.symbol} at {order.price}$.")
if notification.status == "ERROR":
raise Exception(f"Something went wrong: {notification.text}")
```
## Authenticating in your account
To authenticate in your account, you must provide a valid API-KEY and API-SECRET:
```python
bfx = Client(
[...],
api_key=os.getenv("BFX_API_KEY"),
api_secret=os.getenv("BFX_API_SECRET")
)
```
### Warning
Remember to not share your API-KEYs and API-SECRETs with anyone. \
Everyone who owns one of your API-KEYs and API-SECRETs will have full access to your account. \
We suggest saving your credentials in a local `.env` file and accessing them as environment variables.
_Revoke your API-KEYs and API-SECRETs immediately if you think they might have been stolen._
> **NOTE:** A guide on how to create, edit and revoke API-KEYs and API-SECRETs can be found [here](https://support.bitfinex.com/hc/en-us/articles/115003363429-How-to-create-and-revoke-a-Bitfinex-API-Key).
## Next
* [WebSocket client documentation](#websocket-client-documentation)
- [Advanced features](#advanced-features)
- [Examples](#examples)
* [How to contribute](#how-to-contribute) * [How to contribute](#how-to-contribute)
--- ---
# WebSocket Client documentation # WebSocket client documentation
1. [Instantiating the client](#instantiating-the-client) 1. [Instantiating the client](#instantiating-the-client)
* [Authentication](#authentication) * [Authentication](#authentication)
* [Configuring the logger](#configuring-the-logger)
2. [Running the client](#running-the-client) 2. [Running the client](#running-the-client)
* [Closing the connection](#closing-the-connection) * [Closing the connection](#closing-the-connection)
3. [Subscribing to public channels](#subscribing-to-public-channels) 3. [Subscribing to public channels](#subscribing-to-public-channels)
* [Unsubscribing from a public channel](#unsubscribing-from-a-public-channel)
* [Setting a custom `sub_id`](#setting-a-custom-sub_id) * [Setting a custom `sub_id`](#setting-a-custom-sub_id)
4. [Listening to events](#listening-to-events) 4. [Listening to events](#listening-to-events)
5. [Advanced Features](#advanced-features)
* [Connection multiplexing](#connection-multiplexing) ### Advanced features
* [Sending custom notifications](#sending-custom-notifications) * [Using custom notifications](#using-custom-notifications)
* [Handling reconnections in case of network failure](#handling-reconnections-in-case-of-network-failure) * [Setting up connection multiplexing](#setting-up-connection-multiplexing)
### Examples
* [Creating a new order](#creating-a-new-order)
## Instantiating the client ## Instantiating the client
@@ -70,7 +113,7 @@ The `wss_host` argument is used to indicate the URL to which the WebSocket clien
The `bfxapi` package exports 2 constants to quickly set this URL: The `bfxapi` package exports 2 constants to quickly set this URL:
Constant | URL | When to use Constant | URL | When to use
--- | --- | --- :--- | :--- | :---
WSS_HOST | wss://api.bitfinex.com/ws/2 | Suitable for all situations, supports authentication. WSS_HOST | wss://api.bitfinex.com/ws/2 | Suitable for all situations, supports authentication.
PUB_WSS_HOST | wss://api-pub.bitfinex.com/ws/2 | For public uses only, doesn't support authentication. PUB_WSS_HOST | wss://api-pub.bitfinex.com/ws/2 | For public uses only, doesn't support authentication.
@@ -80,23 +123,28 @@ PUB_WSS_HOST is recommended over WSS_HOST for applications that don't require au
### Authentication ### Authentication
### Configuring the logger To learn how to authenticate in your account, have a look at [Authenticating in your account](#authenticating-in-your-account).
`log_filename` (`Optional[str]`, default: `None`): \ If authentication is successful, the client will emit the `authenticated` event. \
Relative path of the file where to save the logs the client will emit. \ All operations that require authentication will fail if run before the emission of this event. \
If not given, the client will emit logs on `stdout` (`stderr` for errors and warnings). The `data` argument contains information about the authentication, such as the `userId`, the `auth_id`, etc...
`log_level` (`str`, default: `"INFO"`): \
Available log levels are (in order): `ERROR`, `WARNING`, `INFO` and `DEBUG`. \
The client will only log messages whose level is lower than or equal to `log_level`. \
For example, if `log_level=WARNING`, the client will only log errors and warnings.
```python ```python
bfx = Client( @bfx.wss.on("authenticated")
[...], def on_authenticated(data: Dict[str, Any]):
log_filename="2023-03-26.log", print(f"Successful login for user <{data['userId']}>.")
log_level="WARNING" ```
)
`data` can also be useful for checking if an API-KEY has certain permissions:
```python
@bfx.wss.on("authenticated")
def on_authenticated(data: Dict[str, Any]):
if not data["caps"]["orders"]["read"]:
raise Exception("This application requires read permissions on orders.")
if not data["caps"]["positions"]["write"]:
raise Exception("This application requires write permissions on positions.")
``` ```
## Running the client ## Running the client
@@ -118,7 +166,7 @@ To learn more about events and public channels, see [Listening to events](#liste
```python ```python
@bfx.wss.on("open") @bfx.wss.on("open")
async def on_open(): async def on_open():
await bfx.wss.subscribe(Channel.TICKER, symbol="tBTCUSD") await bfx.wss.subscribe("ticker", symbol="tBTCUSD")
``` ```
### Closing the connection ### Closing the connection
@@ -137,7 +185,8 @@ After closing the connection, the client will emit the `disconnection` event:
```python ```python
@bfx.wss.on("disconnection") @bfx.wss.on("disconnection")
def on_disconnection(code: int, reason: str): def on_disconnection(code: int, reason: str):
print(f"Closing connection with code: <{code}>. Reason: {reason}.") if code == 1000 or code == 1001:
print("Closing the connection without errors!")
``` ```
## Subscribing to public channels ## Subscribing to public channels
@@ -155,6 +204,16 @@ def on_subscribed(subscription: subscriptions.Subscription):
print(f"{subscription['symbol']}: {subscription['subId']}") # tBTCUSD: f2757df2-7e11-4244-9bb7-a53b7343bef8 print(f"{subscription['symbol']}: {subscription['subId']}") # tBTCUSD: f2757df2-7e11-4244-9bb7-a53b7343bef8
``` ```
### Unsubscribing from a public channel
It is possible to unsubscribe from a public channel at any time. \
Unsubscribing from a public channel prevents the client from receiving any more data from it. \
This can be done using `BfxWebSocketClient::unsubscribe`, and passing the `sub_id` of the public channel you want to unsubscribe from:
```python
await bfx.wss.unsubscribe(sub_id="f2757df2-7e11-4244-9bb7-a53b7343bef8")
```
### Setting a custom `sub_id` ### Setting a custom `sub_id`
The client generates a random `sub_id` for each subscription. \ The client generates a random `sub_id` for each subscription. \
@@ -188,9 +247,29 @@ You can pass any number of events to register for the same callback function:
bfx.wss.on("t_ticker_update", "f_ticker_update", callback=on_ticker_update) bfx.wss.on("t_ticker_update", "f_ticker_update", callback=on_ticker_update)
``` ```
## Advanced features # Advanced features
### Connection multiplexing ## Using custom notifications
**Using custom notifications requires user authentication.**
Users can send custom notifications using `BfxWebSocketClient::notify`:
```python
await bfx.wss.notify({ "foo": 1 })
```
Any data can be sent along with a custom notification.
Custom notifications are broadcast by the server on all user's open connections. \
So, each custom notification will be sent to every online client of the current user. \
Whenever a client receives a custom notification, it will emit the `notification` event:
```python
@bfx.wss.on("notification")
def on_notification(notification: Notification[Any]):
print(notification.data) # { "foo": 1 }
```
## Setting up connection multiplexing
`BfxWebSocketClient::run` and `BfxWebSocketClient::start` accept a `connections` argument: `BfxWebSocketClient::run` and `BfxWebSocketClient::start` accept a `connections` argument:
```python ```python
@@ -211,61 +290,124 @@ Keep in mind that using a large number of connections could slow down the client
The use of more than 20 connections is not recommended. The use of more than 20 connections is not recommended.
### Sending custom notifications # Examples
**Sending custom notifications requires user authentication.** ## Creating a new order
Users can send custom notifications using `BfxWebSocketClient::notify`:
```python ```python
await bfx.wss.notify({ "foo": 1 }) import os
from bfxapi import Client, WSS_HOST
from bfxapi.types import Notification, Order
bfx = Client(
wss_host=WSS_HOST,
api_key=os.getenv("BFX_API_KEY"),
api_secret=os.getenv("BFX_API_SECRET")
)
@bfx.wss.on("authenticated")
async def on_authenticated(_):
await bfx.wss.inputs.submit_order(
type="EXCHANGE LIMIT", symbol="tBTCUSD", amount=0.165212, price=30264.0)
@bfx.wss.on("order_new")
def on_order_new(order: Order):
print(f"Successful new order for {order.symbol} at {order.price}$.")
@bfx.wss.on("on-req-notification")
def on_notification(notification: Notification[Order]):
if notification.status == "ERROR":
raise Exception(f"Something went wrong: {notification.text}")
bfx.wss.run()
``` ```
Any data can be sent along with a custom notification.
Custom notifications are broadcast by the server on all user's open connections. \
So, each custom notification will be sent to every online client of the current user. \
Whenever a client receives a custom notification, it will emit the `notification` event:
```python
@bfx.wss.on("notification")
def on_notification(notification: Notification[Any]):
print(notification.data) # { "foo": 1 }
```
### Handling reconnections in case of network failure
In case of network failure, the client will keep waiting until it is able to restore the connection with the server.
The client will try to reconnect with exponential backoff; the backoff delay starts at three seconds and increases up to one minute.
After a successful reconnection attempt, the client will emit the `reconnection` event.
This event accepts two arguments: \
`attemps` (`int`) which is the number of reconnection attempts (including the successful one), \
`timedelta` (`datetime.timedelta`) which contains the amount of time the client has been down.
Users can use this event for a variety of things, such as sending a notification if the client has been down for too long:
```python
@bfx.wss.on("reconnection")
async def on_reconnection(attempts: int, timedelta: datetime.timedelta):
if timedelta.total_seconds() >= 60 * 60: # 60s * 60s = 3600s = 1h
await bfx.wss.notify(f"The client has been down for {timedelta}.")
```
---
# Building the source code
## Testing (with unittest)
## Linting the project with pylint
## Using mypy to ensure correct type-hinting
--- ---
# How to contribute # How to contribute
## License All contributions are welcome! :D
This project is released under the `Apache License 2.0`.
The complete license can be found here: https://www.apache.org/licenses/LICENSE-2.0. A guide on how to install and set up `bitfinex-api-py`'s source code can be found [here](#installation-and-setup). \
Before opening any pull requests, please have a look at [Before Opening a PR](#before-opening-a-pr). \
Contributors must uphold the [Contributor Covenant code of conduct](https://github.com/bitfinexcom/bitfinex-api-py/blob/v3-beta/CODE_OF_CONDUCT.md).
### Index
1. [Installation and setup](#installation-and-setup)
* [Cloning the repository](#cloning-the-repository)
* [Installing the dependencies](#installing-the-dependencies)
2. [Before opening a PR](#before-opening-a-pr)
* [Running the unit tests](#running-the-unit-tests)
3. [License](#license)
## Installation and setup
A brief guide on how to install and set up the project in your Python 3.8+ environment.
### Cloning the repository
The following command will only clone the `v3-beta` branch (excluding all others):
```console
git clone --branch v3-beta --single-branch https://github.com/bitfinexcom/bitfinex-api-py.git
```
### Installing the dependencies
```console
python3 -m pip install -r dev-requirements.txt
```
Make sure to install `dev-requirements.txt` instead of `requirements.txt`. \
`dev-requirements.txt` will install all dependencies in `requirements.txt` plus any development dependencies. \
This will also install the versions in use of [`pylint`](https://github.com/pylint-dev/pylint) and [`mypy`](https://github.com/python/mypy), which you should both use before opening your PRs.
All done, your Python 3.8+ environment should now be able to run `bitfinex-api-py`'s source code.
## Before opening a PR
**We won't accept your PR or we will request changes if the following requirements aren't met.**
Wheter you're submitting a bug fix, a new feature or a documentation change, you should first discuss it in an issue.
All PRs must follow this [PULL_REQUEST_TEMPLATE](https://github.com/bitfinexcom/bitfinex-api-py/blob/v3-beta/.github/PULL_REQUEST_TEMPLATE.md) and include an exhaustive description.
Before opening a pull request, you should also make sure that:
- [ ] all unit tests pass (see [Running the unit tests](#running-the-unit-tests)).
- [ ] [`pylint`](https://github.com/pylint-dev/pylint) returns a score of 10.00/10.00 when run against your code.
- [ ] [`mypy`](https://github.com/python/mypy) doesn't throw any error code when run on the project (excluding notes).
### Running the unit tests
`bitfinex-api-py` comes with a set of unit tests (written using the [`unittest`](https://docs.python.org/3.8/library/unittest.html) unit testing framework). \
Contributors must ensure that each unit test passes before opening a pull request. \
You can run all project's unit tests by calling `unittest` on `bfxapi.tests`:
```console
python3 -m unittest -v bfxapi.tests
```
A single unit test can be run as follows:
```console
python3 -m unittest -v bfxapi.tests.test_notification
```
## License
```
Copyright 2023 Bitfinex
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```

View File

@@ -1 +1 @@
__version__ = "3.0.0b1" __version__ = "3.0.0b2"