Building a Real-Time Binance BTC/USDT Spot and Futures Data Dashboard using Tkinter and WebSockets
When working with financial applications, it’s critical to have a user interface that updates in real-time with market data. Python’s tkinter library, combined with websocket, allows us to achieve just that. In this article, we’ll explore how to create a GUI-based application to display live Binance BTC/USDT Spot and Futures data. This application shows the best bid and ask prices, calculates the difference between Spot and Futures markets, and tracks the maximum and minimum price differences.
Introduction to Tkinter
Tkinter is Python’s standard GUI library. It’s easy to use and works across all major platforms, making it a great choice for building desktop applications. In our project, tkinter handles the interface design, while websocket connects to Binance’s real-time WebSocket data feed to fetch price information.
Overview of the Project
Our application will:
Step-by-Step Code Explanation
1. Imports
import tkinter as tk
import websocket
import json
import threading
from datetime import datetime, timezone
We import the necessary modules for building the GUI (tkinter), handling WebSocket communication (websocket), parsing data (json), running WebSocket connections on separate threads (threading), and managing timestamps (datetime).
2. Global Variables
spot_ask_price = None
futures_bid_price = None
difference_list = [] # Store price differences
These global variables are used to store the latest Spot Ask price, Futures Bid price, and a list of all differences between the two. These values will be updated dynamically as the application receives new data.
3. Utility Functions
Formatting Timestamps:
def format_timestamp(ts):
return datetime.fromtimestamp(ts / 1000, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S')
Binance provides timestamps in milliseconds. This function converts those timestamps into human-readable format (e.g., “YYYY-MM-DD HH:MM“).
Formatting Prices:
def format_price(price):
return f"{float(price):.2f}"
Prices are formatted to two decimal places for clarity.
4. Calculating and Displaying Price Differences
def update_price_difference():
global difference_list
if spot_ask_price is not None and futures_bid_price is not None:
difference = float(spot_ask_price) - float(futures_bid_price)
difference_label_value.config(text=f"{difference:.2f}")
difference_list.append(difference)
max_difference_label_value.config(text=f"{max(difference_list):.2f}")
min_difference_label_value.config(text=f"{min(difference_list):.2f}")
This function calculates the price difference between the Spot Ask and Futures Bid prices. It updates the corresponding label with the difference and tracks the maximum and minimum recorded differences in the difference_list.
5. WebSocket Handlers
WebSocket handlers process incoming messages from Binance and update the relevant price labels in the GUI.
Spot WebSocket Message Handler:
def on_message_binance_spot(ws, message):
global spot_ask_price
data = json.loads(message)
spot_ask_price = format_price(data.get("a", "N/A")) # Best ask price
update_price_difference()
This handler listens for messages from Binance’s Spot market WebSocket, extracts the Spot Ask price, and updates the price difference calculation.
Futures WebSocket Message Handler:
def on_message_binance_futures(ws, message):
global futures_bid_price
data = json.loads(message)
futures_bid_price = format_price(data.get("b", "N/A")) # Best bid price
update_price_difference()
Similarly, this handler listens for messages from Binance’s Futures market WebSocket and updates the Futures Bid price.
领英推荐
6. Connecting to WebSockets
Each WebSocket connection runs on its own thread so that the GUI remains responsive while receiving real-time data.
def run_websocket_binance_spot():
socket = "wss://stream.binance.com/ws/btcusdt@bookTicker"
ws = websocket.WebSocketApp(socket, on_message=on_message_binance_spot)
ws.run_forever()
def run_websocket_binance_futures():
socket = "wss://fstream.binance.com/ws/btcusdt@bookTicker"
ws = websocket.WebSocketApp(socket, on_message=on_message_binance_futures)
ws.run_forever()
The run_forever() method ensures that the WebSocket stays open and listens continuously for new data.
7. GUI Design with Tkinter
Now let’s dive into the core part of the interface, where tkinter helps to display real-time data.
Main Window Setup:
window = tk.Tk()
window.title("BTC/USDT Real-Time Data from Binance Spot & Futures")
window.geometry("1200x600")
window.config(bg="#1f1f1f")
The Tk() function initializes the main application window, sets its title and dimensions, and applies a dark background color for a modern aesthetic.
8. Creating Dynamic Labels for Displaying Data
Here, various labels are created to display trading information like the symbol, best bid price, best ask price, and quantities. These labels are updated dynamically with incoming data from Binance.
symbol_label_spot_value = tk.Label(table_frame_binance_spot, text="Loading...", font=font_sub, fg=last_color, bg=bg_color)
best_bid_price_label_spot_value = tk.Label(table_frame_binance_spot, text="Loading...", font=font_sub, fg=bid_color, bg=bg_color)
best_bid_qty_label_spot_value = tk.Label(table_frame_binance_spot, text="Loading...", font=font_sub, fg=bid_color, bg=bg_color)
best_ask_price_label_spot_value = tk.Label(table_frame_binance_spot, text="Loading...", font=font_sub, fg=ask_color, bg=bg_color)
best_ask_qty_label_spot_value = tk.Label(table_frame_binance_spot, text="Loading...", font=font_sub, fg=ask_color, bg=bg_color)
Initially, each label shows “Loading…” until the WebSocket receives data. Once data is received, the labels are dynamically updated to display the latest values.
For example:
These labels help users visualize real-time market conditions without refreshing the window or waiting for manual updates.
9. Displaying the Price Difference
difference_label_value = tk.Label(window, text="Loading...", font=font_main, fg=last_color, bg=bg_color)
This label displays the real-time difference between the Spot Ask and Futures Bid prices. It will update every time new data is received from either WebSocket feed.
10. Maximum and Minimum Price Difference Tracking
max_difference_label_value = tk.Label(window, text="Loading...", font=font_main, fg=last_color, bg=bg_color)
min_difference_label_value = tk.Label(window, text="Loading...", font=font_main, fg=last_color, bg=bg_color)
These labels display the maximum and minimum recorded differences between the Spot and Futures markets since the application started running.
11. Running the Application
The WebSocket threads are started, and the Tkinter event loop begins, ensuring the application continuously updates with live data:
websocket_thread_binance_spot = threading.Thread(target=run_websocket_binance_spot)
websocket_thread_binance_spot.daemon = True
websocket_thread_binance_spot.start()
websocket_thread_binance_futures = threading.Thread(target=run_websocket_binance_futures)
websocket_thread_binance_futures.daemon = True
websocket_thread_binance_futures.start()
window.mainloop()
This keeps the interface active and responsive while the WebSocket streams bring in new data in the background.
Conclusion
With Python’s tkinter and websocket, you can create a real-time financial dashboard that displays crucial trading information. By combining a GUI with live WebSocket data feeds from Binance, the application can update dynamically, showing bid and ask prices, calculating price differences, and tracking market trends. This project offers a solid foundation for building more complex trading systems or financial visualizations.
Full Code at Medium