Python Binance WebSocket: Real-Time Trading Data with Streaming API
Binance, one of the largest cryptocurrency exchanges globally, provides a powerful and easy-to-use WebSocket API for real-time trading data and order book updates. Developers can use this API to build applications that provide up-to-date information about cryptocurrencies' prices, market depth, and more. Python is an ideal language for developing such applications due to its simplicity and the availability of libraries like `websocket` and `tornado`.
In this article, we will explore how to use Binance WebSocket API with Python to stream real-time data from the exchange. We'll cover setting up a basic WebSocket connection, subscribing to different market types (spot, margin, futures), handling messages, and some practical examples of using this API in trading strategies.
Setting Up the Connection
To connect to Binance WebSocket, we first need to authenticate our requests by generating an API key and a secret key from Binance's [official website](https://www.binance.com/). The `ws_endpoint` can be customized for different market types (spot, margin, futures) as follows:
Spot Market: `wss://stream.binance.com/stream?streams=orderbook@arr&symbol=${CRYPTO_PAIR}`
Margin Market: `wss://fstream.binance.com/stream?streams=orderBook0:${LEVEL}@depth&symbol=${CRYPTO_PAIR}&binary=1`
Futures Market: `wss://dstream.binance.com/stream?streams=trade&symbol=${CRYPTO_PAIR}${CHAIN}`
Where `${CRYPTO_PAIR}` is a string in the format of "BTCUSDT", `${LEVEL}` specifies the depth level for the order book (e.g., 24 or 5), and `${CHAIN}` represents the chain type (PERPETUAL) for futures markets.
Here's how to establish a WebSocket connection in Python using `websocket` library:
```python
import websocket
def on_open(ws):
print('Connection opened')
subscribe_message = '{"event":"subMessage", "pair": "BTCUSDT"}'
ws.send(subscribe_message)
def on_message(ws, message):
print(f'Received {message}')
def on_error(ws, error):
print('Error:', error)
def on_close(ws):
print('Connection closed')
if __name__ == '__main__':
url = "wss://stream.binance.com/stream?streams=orderbook@arr&symbol=BTCUSDT"
websocket.enable_trace()
ws = websocket.WebSocketApp(url, on_open=on_open, on_message=on_message,
on_error=on_error, on_close=on_close)
ws.run_forever()
```
This code sets up a WebSocket connection to the Binance spot market for "BTCUSDT" and prints received messages. When the connection is opened, it subscribes to real-time order book updates by sending a JSON string with the `subMessage` event.
Handling Messages
When connected to the WebSocket API, you will receive binary encoded JSON data as text. The payload looks like this:
```json
{"ch":"BTCUSDT@depth@100"}
{ "event": "depthUpdate",
"payload": {
"a": [ [ 28675.29, 34.941 ],
[ 28670.29, 1.515 ],
[ 28665.29, 1.457 ] },
"seqNum": 15495307,
"timeStamp": 1631671377218
}
```
You can parse this JSON data to extract useful information like the price levels and quantities in the order book. Here's a simplified version of how to decode and use the received messages:
```python
def on_message(ws, message):
data = json.loads(websocket.json_dumps(ws, message)) # Decode JSON data
for stream in data['payload']:
pair = stream[0]
asks = [(price, qty) for price, qty in stream[1]]
bids = [(price, qty) for price, qty in reversed(stream[2])]
print('Symbol:', pair)
print('Bids:')
for bid in bids:
print(bid)
print('Asks:')
for ask in asks:
print(ask)
```
This code snippet extracts the symbol from the message and prints out the best 50 levels of the order book for each side (bids and asks).
Advanced Features with Tornado WebSocket
While `websocket` library is straightforward, using `tornado` can provide more control over asynchronous operations. Here's an example of a simple server-side application that accepts connections from clients:
```python
import tornado.ioloop
import tornado.websocket
import tornado.httpserver
import tornado.web
class MyWebSocket(tornado.websocket.WebSocketHandler):
def open(self):
print('WebSocket opened')
def on_message(self, message):
if 'subscribe' in message:
Send order book update messages to the client
pass
def on_close(self):
print('WebSocket closed')
def make_app():
return tornado.web.Application([
tornado.web.StaticRoute('/ws', 'ws', MyWebSocket),
])
if __name__ == "__main__":
app = make_app()
http_server = tornado.httpserver.HTTPServer(app)
http_server.add_socket(tornado.ioloop.IOLoop.current().add_handler(8765, websocket_handler))
print('Server running at http://localhost:8888/ws')
tornado.ioloop.IOLoop.instance().start()
```
This application sets up a WebSocket server on port 8765 and handles incoming `subscribe` messages by sending order book updates to the connected clients. This example can be extended to handle more complex operations like trading algorithms, market making strategies, or portfolio management services.
Conclusion
Binance's WebSocket API allows Python developers to easily access real-time cryptocurrency trading data with high precision and low latency. By leveraging this powerful feature, you can build sophisticated applications for price analysis, automated trading systems, or even custom charting tools. Whether you are a beginner or an experienced developer, Binance WebSocket provides ample opportunities to explore the world of algorithmic trading in cryptocurrencies.