Introducing Python websockets and asyncio with a worked example
Tags: Programming, Websocket, Bitcoin, Python, Cryptocurrency

A quick beginner’s tutorial into Python websockets with a Deribit cryptocurrency example.

Photo by Stefan Gall on Unsplash

In this note, we’re going to run through some basics on running Python websockets, along with an example where we use websockets to receive live cryptocurrency data from one the largest Bitcoin futures trading platform Deribit.

Firstly, you need to install websockets.

Installing Python websockets

Installing websockets:

pip install websockets

Websockets requires Python 3.6.1 or greater. Perhaps you can create a new virtual environment and install websockets into this environment. This way, you don’t mess around with your base environment.

conda create --name myNewEnv python=3.7

conda install -n myNewEnv websockets

In the code above, we’ve created an new Python virtual environment called “myNewEnv” in which we install Python version 3.7. We have also installed websockets into this version.

What is websockets?

Websockets is a standard protocol for two way data transfer between a client and a server. Websockets does not run over HTTP, it has a separate implementation on top of TCP. This is the key difference to REST (representational state transfer) which uses HTTP.

It is a persistent connection between the client and the server — both parties can send data to each other at any time.

The best way to learn is to learn by an example. Let’s learn by the following example, where we open up a connection with the cryptocurrency exchange deribit and take some current market prices.

A simple example using the Deribit API

We are going to use Python websockets to get the market price of Bitcoin futures on Deribit. Some details on the Deribit API is in the link below, but for now you don’t need to read it. I will go though one single example in great detail so hopefully you get the hang of it.

Here is the code supplied by Deribit to access market data. We will go through this code line-by-line.

import asyncio

import websockets

import json msg = {"jsonrpc": "2.0",

"method": "public/get_index_price",

"id": 42,

"params": {"index_name": "btc_usd"}} async def call_api(msg):

async with websockets.connect('wss://test.deribit.com/ws/api/v2') as websocket:

await websocket.send(msg)

response = await websocket.recv()

print(response)

asyncio.get_event_loop().run_until_complete(call_api(json.dumps(msg)))

Firstly you will notice the use of asyncio, so very quickly, let’s go a brief explain what asyncio is all about.

What is asyncio?

Asyncio is a programming design that achieves concurrency without multi-threading.

It is a single-threaded, single-process design. It uses cooperative multitasking, i.e., it gives a sense of concurrency despite using a single thread in a single process.

Basic asyncio commands

async — used to introduce a new native coroutine.

await — passes control back up the chain. Basically, I’m waiting for a result which is taking some time, so in the meantime, run something else.

The syntax for a coroutine:

async def call_api(x):

y = await receive(x)

return(y)

A simple example of using the async/await function that illustrates concurrency:

import asyncio

import time async def count():

print('one')

await asyncio.sleep(1)

print('two') async def main():

await asyncio.gather(count(), count(), count()) if __name__ == "__main__":

s = time.perf_counter()

asyncio.run(main())

elapsed = time.perf_counter() - s

print(f"{__file__} executed in {elapsed:0.2f} seconds.")

The output of the code above is:

Notice how all the ‘one’s are printed first before the ‘two’s. In a normal synchronous for loop this would not occur.

The Deribit API code is built upon the same syntax as the simple coroutine above.

async def call_api(msg):

async with websockets.connect('wss://test.deribit.com/ws/api/v2') as websocket:

await websocket.send(msg)

response = await websocket.recv()

print(response)

Here is what it is doing:

We create a coroutine called “call_api”. This coroutine allows for a variable msg to be parsed into it. msg is a JSON-RPC.

msg = {"jsonrpc": "2.0",

"method": "public/get_index_price",

"id": 42,

"params": {"index_name": "btc_usd"}}

We can create a websockets connection with the following syntax.

async with websockets.connect(websocketResourceUrl) as ws:

In our case the websocket resource url is ‘wss://test.deribit.com/ws/api/v2’. Websocket resource urls always start with ‘ws’ or ‘wss’ (if secure).

Once we have created our websocket, we can sent through a message.

await websocket.send(msg)

In this case, it is to retrieve the index price of Bitcoin futures trading on Deribit. (Please note we’re retrieving it from Deribit’s testnet.)

We then proceed to print the response.

response = await websocket.recv()

print(response)

Output: Bitcoin futures price

And there we have it, the BTC price from Deribit.