import mplfinance as mpf import pandas as pd import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import matplotlib.animation as animation import ccxt from matplotlib.dates import date2num import threading import tkinter as tk from tkinter import ttk class ChartView: def __init__(self, exchange_ids, symbol='BTC/USDT', timeframe='1m', limit=100): self.exchange_ids = exchange_ids self.symbol = symbol self.timeframe = timeframe self.limit = limit self.running = False self.fig = None self.ax1 = None self.ax2 = None self.animation = None self.current_exchange_id = exchange_ids[0] self.root = None self.canvas = None # Create exchanges dictionary to avoid reconnecting each time self.exchanges = {} for exchange_id in exchange_ids: self.connect_to_exchange(exchange_id) def connect_to_exchange(self, exchange_id): if exchange_id in self.exchanges: self.exchange = self.exchanges[exchange_id] return try: exchange_class = getattr(ccxt, exchange_id) exchange = exchange_class({ 'enableRateLimit': True, }) exchange.load_markets() if self.symbol not in exchange.markets: raise Exception(f"Symbol {self.symbol} not found on {exchange_id}") self.exchanges[exchange_id] = exchange self.exchange = exchange except Exception as e: raise Exception(f"Failed to connect to {exchange_id}: {str(e)}") def fetch_ohlcv(self, exchange_id): try: exchange = self.exchanges[exchange_id] ohlcv = exchange.fetch_ohlcv(self.symbol, self.timeframe, limit=self.limit) df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']) df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms') df.set_index('timestamp', inplace=True) return df except Exception as e: print(f"Error fetching OHLCV data from {exchange_id}: {str(e)}") return None def update_chart(self): if not self.running: return df = self.fetch_ohlcv(self.current_exchange_id) if df is not None: self.ax1.clear() self.ax2.clear() mpf.plot(df, type='candle', ax=self.ax1, volume=self.ax2, style='yahoo', xrotation=0, ylabel='Price', ylabel_lower='Volume', show_nontrading=False) latest_price = df['close'].iloc[-1] self.ax1.set_title(f'{self.symbol} on {self.current_exchange_id} - Last: ${latest_price:.2f}') # Refresh the canvas self.canvas.draw() def on_exchange_change(self, event=None): selected_exchange = self.exchange_var.get() if selected_exchange != self.current_exchange_id: self.current_exchange_id = selected_exchange self.update_chart() def start_gui(self): self.root = tk.Tk() self.root.title("Crypto Chart Viewer") self.root.geometry("1200x800") # Create frame for controls control_frame = ttk.Frame(self.root) control_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5) # Dropdown for selecting exchange ttk.Label(control_frame, text="Exchange:").pack(side=tk.LEFT, padx=(0, 5)) self.exchange_var = tk.StringVar(value=self.current_exchange_id) exchange_dropdown = ttk.Combobox(control_frame, textvariable=self.exchange_var, values=self.exchange_ids, width=15) exchange_dropdown.pack(side=tk.LEFT, padx=(0, 10)) exchange_dropdown.bind("<>", self.on_exchange_change) # Create the figure self.fig = plt.Figure(figsize=(12, 8), dpi=100) self.ax1 = self.fig.add_subplot(6, 1, (1, 4)) self.ax2 = self.fig.add_subplot(6, 1, (5, 6), sharex=self.ax1) # Create the canvas to display the figure self.canvas = FigureCanvasTkAgg(self.fig, master=self.root) self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) # Add toolbar toolbar = NavigationToolbar2Tk(self.canvas, self.root) toolbar.update() self.canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) # Initial chart update self.running = True self.update_chart() # Set up periodic updates def update(): if self.running: self.update_chart() self.root.after(10000, update) # Update every 10 seconds self.root.after(10000, update) # Handle window close def on_closing(): self.running = False self.root.destroy() self.root.protocol("WM_DELETE_WINDOW", on_closing) # Start the Tkinter event loop self.root.mainloop()