Streaming Live Crypto Prices with Binance's Free API in Python
Written on
Chapter 1: Introduction to Live Crypto Price Streaming
In a previous article, I shared my experience with the Coinbase API to create historical charts similar to those from Bloomberg. This time, I wanted to elevate the project by developing charts that update in real-time, tracking price fluctuations throughout the day. However, to achieve this, we first need to establish a way to stream live prices into our environment.
In this guide, I will explain how to utilize Python to connect to the Binance API via its websocket to stream live cryptocurrency prices. A dedicated post will follow to tackle the charting aspect (which I am still working on, to be honest).
By the end of this guide, you will be able to implement my code for a live stream of BTCUSDT and ETHUSDT prices.
Importing Necessary Libraries
As always, let’s kick things off by importing the necessary libraries:
import json
import websockets
import asyncio
from datetime import datetime
Constructing the Websocket Request
Binance provides comprehensive documentation on connecting to its websocket and retrieving data from various streams, making it straightforward to create my websocket request.
First, we need to obtain a websocket URL. As outlined in the documentation, we have two choices. I opted for the highlighted option.
Next, we need to create our headers for the websocket request, which is detailed in the screenshot below:
Lastly, we should select which streams to subscribe to. While the examples in the documentation utilize btcusdt@aggTrade and btcusdt@depth, we want to focus on live price streams, which are formatted as @kline_.
For example, to get BTCUSDT prices with 1-minute intervals, our stream name would be btcusdt@kline_1m. Therefore, our websocket URL will be:
wss://fstream.binance.com/stream?streams=btcusdt@kline_1m
And our headers will look like this:
{"method": "SUBSCRIBE", "params": ["btcusdt@kline_1m"], "id": 1}
Connecting to the Binance Websocket
Bringing everything together, here’s a basic script:
import websockets
import json
import asyncio
async def run_websocket():
url = "wss://fstream.binance.com/stream?streams=btcusdt@kline_1m"
async with websockets.connect(url, ping_timeout=None, max_size=10000000) as websocket:
headers = {"method": "SUBSCRIBE", "params": ["btcusdt@kline_1m"], "id": 1}
await websocket.send(json.dumps(headers))
while True:
msg = await websocket.recv()
data = json.loads(msg)
print(data)
if __name__ == '__main__':
asyncio.run(run_websocket())
Though this may seem overwhelming, especially if asynchronous programming is new to you, don’t worry! This article provides a solid breakdown of the topic (even I revisit it occasionally).
To clarify, Python operates synchronously, meaning each step executes only after the previous one completes. In contrast, asynchronous programming allows the system to proceed to the next step without waiting for the current one to finish.
This asynchronous approach is necessary because websockets are inherently asynchronous, and the websockets module is built on Python’s asyncio package, which is essential for running asynchronous functions.
When you run this code, it will produce a live stream of BTCUSDT price updates.
Formatting Websocket Responses
Keep in mind that the raw responses from Binance may not be in a readable format. Here’s an example of what a single response looks like:
{
"stream": "btcusdt@kline_1m",
"data": {
"e": "kline",
"E": 1714226603449,
"s": "BTCUSDT",
"k": {
"t": 1714226580000,
"T": 1714226639999,
"s": "BTCUSDT",
"i": "1m",
"f": 4942154251,
"L": 4942155024,
"o": "63127.00",
"c": "63144.80",
"h": "63152.80",
"l": "63126.90",
"v": "48.194",
"n": 774,
"x": False,
"q": "3042797.35400",
"V": "35.753",
"Q": "2257302.61500",
"B": "0"
}
}
}
After some datetime and string formatting, we can convert these raw responses into more readable print statements:
async def run_websocket():
# (code from earlier)
while True:
msg = await websocket.recv()
raw_data = json.loads(msg)
if 'result' in raw_data:
continuedata = raw_data['data']
pair = data['s']
candle = data['k']
dt_format = '%Y-%m-%d %H:%M:%S:%f'
event_time = datetime.fromtimestamp(data['E'] / 1000).strftime(dt_format)
minute = datetime.fromtimestamp(candle['t'] / 1000).strftime('%H:%M')
price_stub = "{:.2f}"
col_width = 8
open_price = f"{price_stub.format(float(candle['o']))}{' ' * (col_width - len(price_stub.format(float(candle['o']))))}"
close_price = f"{price_stub.format(float(candle['c']))}{' ' * (col_width - len(price_stub.format(float(candle['c']))))}"
high_price = f"{price_stub.format(float(candle['h']))}{' ' * (col_width - len(price_stub.format(float(candle['h']))))}"
low_price = f"{price_stub.format(float(candle['l']))}{' ' * (col_width - len(price_stub.format(float(candle['l']))))}"
volume = candle['v']
print(f'[{event_time}] {pair} - minute: {minute} | open: {open_price} | close: {close_price} | '
f'high: {high_price} | low: {low_price} | volume: {volume}')
if __name__ == '__main__':
asyncio.run(run_websocket())
Streaming Prices for Multiple Cryptocurrency Pairs
If you wish to stream live prices for multiple cryptocurrency pairs, you only need to adjust the headers in your websocket request.
For example, to include both BTC and ETH prices, simply add the ETH stream name (ethusdt@kline_1m) to your params list:
{"method": "SUBSCRIBE", "params": ["btcusdt@kline_1m", "ethusdt@kline_1m"], "id": 1}
Conclusion
You have now learned how to stream live cryptocurrency prices using the Binance Websocket API and format those streamed responses into more comprehensible print statements. We also covered the concept of asynchrony, which can be tricky at first. Like any valuable skill, it requires time to master, so take it at your own pace and enjoy the learning process.
With the ability to stream live prices established, my next goal is to feed these prices into dynamic intraday price charts.
Stay curious and keep learning!
Chapter 2: Video Tutorials
In this video, you will learn how to pull real-time cryptocurrency prices using Python and the Binance API for free.
This video demonstrates how to fetch real-time crypto prices using the Binance API with JavaScript and Websockets.