mirror of
https://github.com/aljazceru/bitfinex-api-py.git
synced 2025-12-20 15:24:21 +01:00
272 lines
10 KiB
Markdown
272 lines
10 KiB
Markdown
# bitfinex-api-py (v3-beta)
|
|
|
|
Official implementation of the [Bitfinex APIs (V2)](https://docs.bitfinex.com/docs) for `Python 3.8+`.
|
|
|
|
> **DISCLAIMER:** \
|
|
Production use of v3.0.0b1 (and all future beta versions) is HIGHLY discouraged. \
|
|
Beta versions should not be used in applications which require user authentication. \
|
|
Provide your API-KEY/API-SECRET, and manage your account and funds at your own risk.
|
|
|
|
### 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: 
|
|
|
|
---
|
|
|
|
## Installation
|
|
|
|
To install the latest beta release of `bitfinex-api-py`:
|
|
```bash
|
|
python3 -m pip install --pre bitfinex-api-py
|
|
```
|
|
To install a specific beta version:
|
|
```bash
|
|
python3 -m pip install bitfinex-api-py==3.0.0b1
|
|
```
|
|
|
|
## Basic usage
|
|
|
|
---
|
|
|
|
### Index
|
|
|
|
* [WebSocket Client documentation](#websocket-client-documentation)
|
|
* [Building the source code](#building-the-source-code)
|
|
* [How to contribute](#how-to-contribute)
|
|
|
|
---
|
|
|
|
# WebSocket Client documentation
|
|
|
|
1. [Instantiating the client](#instantiating-the-client)
|
|
* [Authentication](#authentication)
|
|
* [Configuring the logger](#configuring-the-logger)
|
|
2. [Running the client](#running-the-client)
|
|
* [Closing the connection](#closing-the-connection)
|
|
3. [Subscribing to public channels](#subscribing-to-public-channels)
|
|
* [Setting a custom `sub_id`](#setting-a-custom-sub_id)
|
|
4. [Listening to events](#listening-to-events)
|
|
5. [Advanced Features](#advanced-features)
|
|
* [Connection multiplexing](#connection-multiplexing)
|
|
* [Sending custom notifications](#sending-custom-notifications)
|
|
* [Handling reconnections in case of network failure](#handling-reconnections-in-case-of-network-failure)
|
|
|
|
## Instantiating the client
|
|
|
|
```python
|
|
bfx = Client(wss_host=PUB_WSS_HOST)
|
|
```
|
|
|
|
`Client::wss` contains an instance of `BfxWebSocketClient` (core implementation of the WebSocket client). \
|
|
The `wss_host` argument is used to indicate the URL to which the WebSocket client should connect. \
|
|
The `bfxapi` package exports 2 constants to quickly set this URL:
|
|
|
|
Constant | URL | When to use
|
|
--- | --- | ---
|
|
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 is recommended over WSS_HOST for applications that don't require authentication.
|
|
|
|
> **NOTE:** The `wss_host` parameter is optional, and the default value is WSS_HOST.
|
|
|
|
### Authentication
|
|
|
|
### Configuring the logger
|
|
|
|
`log_filename` (`Optional[str]`, default: `None`): \
|
|
Relative path of the file where to save the logs the client will emit. \
|
|
If not given, the client will emit logs on `stdout` (`stderr` for errors and warnings).
|
|
|
|
`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
|
|
bfx = Client(
|
|
[...],
|
|
log_filename="2023-03-26.log",
|
|
log_level="WARNING"
|
|
)
|
|
```
|
|
|
|
## Running the client
|
|
|
|
The client can be run using `BfxWebSocketClient::run`:
|
|
```python
|
|
bfx.wss.run()
|
|
```
|
|
|
|
If an event loop is already running, users can start the client with `BfxWebSocketClient::start`:
|
|
```python
|
|
await bfx.wss.start()
|
|
```
|
|
|
|
If the client succeeds in connecting to the server, it will emit the `open` event. \
|
|
This is the right place for all bootstrap activities, such as subscribing to public channels. \
|
|
To learn more about events and public channels, see [Listening to events](#listening-to-events) and [Subscribing to public channels](#subscribing-to-public-channels).
|
|
|
|
```python
|
|
@bfx.wss.on("open")
|
|
async def on_open():
|
|
await bfx.wss.subscribe(Channel.TICKER, symbol="tBTCUSD")
|
|
```
|
|
|
|
### Closing the connection
|
|
|
|
Users can close the connection with the WebSocket server using `BfxWebSocketClient::close`:
|
|
```python
|
|
await bfx.wss.close()
|
|
```
|
|
|
|
A custom [close code number](https://www.iana.org/assignments/websocket/websocket.xhtml#close-code-number), along with a verbose reason, can be given as parameters:
|
|
```python
|
|
await bfx.wss.close(code=1001, reason="Going Away")
|
|
```
|
|
|
|
After closing the connection, the client will emit the `disconnection` event:
|
|
```python
|
|
@bfx.wss.on("disconnection")
|
|
def on_disconnection(code: int, reason: str):
|
|
print(f"Closing connection with code: <{code}>. Reason: {reason}.")
|
|
```
|
|
|
|
## Subscribing to public channels
|
|
|
|
Users can subscribe to public channels using `BfxWebSocketClient::subscribe`:
|
|
```python
|
|
await bfx.wss.subscribe("ticker", symbol="tBTCUSD")
|
|
```
|
|
|
|
On each successful subscription, the client will emit the `subscribed` event:
|
|
```python
|
|
@bfx.wss.on("subscribed")
|
|
def on_subscribed(subscription: subscriptions.Subscription):
|
|
if subscription["channel"] == "ticker":
|
|
print(f"{subscription['symbol']}: {subscription['subId']}") # tBTCUSD: f2757df2-7e11-4244-9bb7-a53b7343bef8
|
|
```
|
|
|
|
### Setting a custom `sub_id`
|
|
|
|
The client generates a random `sub_id` for each subscription. \
|
|
These values must be unique, as the client uses them to identify subscriptions. \
|
|
However, it is possible to force this value by passing a custom `sub_id` to `BfxWebSocketClient::subscribe`:
|
|
|
|
```python
|
|
await bfx.wss.subscribe("candles", key="trade:1m:tBTCUSD", sub_id="507f1f77bcf86cd799439011")
|
|
```
|
|
|
|
## Listening to events
|
|
|
|
Whenever the WebSocket client receives data, it will emit a specific event. \
|
|
Users can either ignore those events or listen for them by registering callback functions. \
|
|
These callback functions can also be asynchronous; in fact the client fully supports coroutines ([`asyncio`](https://docs.python.org/3/library/asyncio.html)).
|
|
|
|
To add a listener for a specific event, users can use the decorator `BfxWebSocketClient::on`:
|
|
```python
|
|
@bfx.wss.on("candles_update")
|
|
def on_candles_update(sub: subscriptions.Candles, candle: Candle):
|
|
print(f"Candle update for key <{sub['key']}>: {candle}")
|
|
```
|
|
|
|
The same can be done without using decorators:
|
|
```python
|
|
bfx.wss.on("candles_update", callback=on_candles_update)
|
|
```
|
|
|
|
You can pass any number of events to register for the same callback function:
|
|
```python
|
|
bfx.wss.on("t_ticker_update", "f_ticker_update", callback=on_ticker_update)
|
|
```
|
|
|
|
## Advanced features
|
|
|
|
### Connection multiplexing
|
|
|
|
`BfxWebSocketClient::run` and `BfxWebSocketClient::start` accept a `connections` argument:
|
|
```python
|
|
bfx.wss.run(connections=3)
|
|
```
|
|
|
|
`connections` indicates the number of connections to run concurrently (through connection multiplexing).
|
|
|
|
Each of these connections can handle up to 25 subscriptions to public channels. \
|
|
So, using `N` connections will allow the client to handle at most `N * 25` subscriptions. \
|
|
You should always use the minimum number of connections necessary to handle all the subscriptions that will be made.
|
|
|
|
For example, if you know that your application will subscribe to 75 public channels, 75 / 25 = 3 connections will be enough to handle all the subscriptions.
|
|
|
|
The default number of connections is 5; therefore, if the `connections` argument is not given, the client will be able to handle a maximum of 25 * 5 = 125 subscriptions.
|
|
|
|
Keep in mind that using a large number of connections could slow down the client performance.
|
|
|
|
The use of more than 20 connections is not recommended.
|
|
|
|
### Sending custom notifications
|
|
|
|
**Sending 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 }
|
|
```
|
|
|
|
### 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
|
|
|
|
## License
|
|
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.
|