We received really good feedback with our original NodeJS client and a lot of people requested a port to Python so they can continue to create advanced strategies on the Bitfinex platform in a language that is extremely friendly to data analytics.

The team at Bitfinex have been working on the bitfinex-api-py repo which can be found here: github.com/bitfinexcom/bitfinex-api-py.

The client is designed to make it easy to interact with both the REST and websocket interface.

The client handles all of the nasty parts that are associated with websockets such as subscriptions, authentication, confirmation callbacks and reconnecting when the connection is intermittent. The REST interface is as easy as ever to use, it exposes function calls such as get_active_orders() and then handles all of the authentication for you.

In this tutorial we will cover three basic examples such as subscribing to the order-book, sending an order and retrieving open orders. These examples will be a good place to start since it will show how to manage a subscription and also authenticated REST + websocket calls.

Subscribing to an order-book

Firstly we have to create an instance of the Bitfinex client. Since the order-books are public, we don’t need to worry about passing in any auth keys.

Once we have done this we can use Python decorators to call a function when a certain event occurs (for a full list of events that are available please see the github repo).

from bfxapi import Client bfx = Client(

logLevel='INFO',

manageOrderBooks=True

)

def log_update(data):

print ("Book update: {}".format(data)) @bfx .ws.on('order_book_update')def log_update(data):print ("Book update: {}".format(data))

async def start():

await bfx.ws.subscribe('book', 'tBTCUSD') @bfx .ws.on('connected')async def start():await bfx.ws.subscribe('book', 'tBTCUSD') bfx.ws.run()

Here we listen to 2 different events — the order-book update event and the ‘connected’ event which is triggered when the connection is successfully established.

Once the connection is established we call the bfx.ws.subscribe function which sends a payload to Bitfinex requesting for an order-book channel.

Note the manageOrderBooks value in the Client constructor. This value toggles the CRC32 order-book checksum system on/off. It maintains a local copy of the order-book and constantly checks its hash against the Bitfinex order-book, if the order-book has does not match then it will completely reset the subscription and retry.

This is useful because it ensures we are up to date.

Sending an new limit order

Again, we have to create a Bitfinex client instance but this time we need to pass out API keys into the constructor since creating an order requires authentication.

In order to get an API key please go to www.bitfinex.com/api log into your Bitfinex account and select “Create New Key”. For this tutorial we need both ‘Read’ and ‘Write’ permissions for ‘Orders’.

Once you have your keys you can submit an order like this:

from bfxapi import Client, Order bfx = Client(

API_KEY="YOUR_API_KEY",

API_SECRET="YOUR_API_SECRET"

)

async def on_complete(order):

print ("Order confirmed")

print (order) @bfx .ws.on('order_confirmed')async def on_complete(order):print ("Order confirmed")print (order)

async def on_auth(auth_message):

await bfx.ws.submit_order('tBTCUSD', 5000, 0.2, Order.Type.EXCHANGE_LIMIT) @bfx .ws.once('authenticated')async def on_auth(auth_message):await bfx.ws.submit_order('tBTCUSD', 5000, 0.2, Order.Type.EXCHANGE_LIMIT) bfx.ws.run()

In this example we listen for the ‘authenticated’ event to fire which is triggered when our auth credentials are accepted. Notice how in our python decorator we have used ‘once’ rather than ‘on’, this means that the function will only be triggered one time and after that it will be forgotten.

Sending an order can trigger multiple events. Firstly an ‘order_confirmed’ event is triggered when Bitfinex confirms that it has received the order. If the position is partially filled then an ‘order_update’ event is fired and finally when the position is fully closed the ‘order_closed’ event is fired.

When creating orders we recommend that you also register to the ‘error’ event which will pass any errors received from the websocket through.



def log_error(msg):

print ("Error: {}".format(msg)) @bfx .ws.on('error')def log_error(msg):print ("Error: {}".format(msg)) Also, you don't have to use python decorators to subscribe to events. If you want you can call register events directly. Like this: def log_error(msg):

print ("Error: {}".format(msg)) bfx.ws.on('error', log_error)

Retrieve open orders

For this example we are going to use the REST interface. We also need to create an asyncio event looper in order to execute the function. The reason we didnt have to do this with the websocket version is because bfx.ws.run() creates this all for us.

import asyncio

from bfxapi import Client, Order bfx = Client(

API_KEY="YOUR_API_KEY",

API_SECRET="YOUR_API_SECRET"

) async def get_orders():

orders = await bfx.rest.get_active_orders('tBTCUSD')

print ("Orders:") [ print (o) for o in orders ] t = asyncio.ensure_future(get_orders())

asyncio.get_event_loop().run_until_complete(t)

In this example create an asyncio event loop that just runs a single function and then finishes. The REST interface signs the payload with the auth credentials and POSTS to the appropriate endpoint i.e api.bitfinex.com/v2/auth/r/orders/tBTCUSD.

Once a request response is received it is parsed into Order Objects and returned.

Thanks for reading!

If you would like to contribute to the project then please just open a pull request to github.com/bitfinexcom/bitfinex-api-py.

If you would like to see more examples then please head to github.com/bitfinexcom/bitfinex-api-py/tree/master/bfxapi/examples.

Here you will find simple scripts that show how to use all of the different functions.