Python Lightweight Charts多子图(25+)币安Websocket价格更新延迟问题求助
Python Lightweight Charts多子图(25+)币安Websocket价格更新延迟问题求助
大家好,我最近碰到一个特别头疼的问题:我用Python的lightweight-charts库,通过create_sub_chart创建多个子图表,同时对接币安的Websocket来实时更新K线价格。但当我创建25个甚至更多子图时,价格更新变得异常缓慢,图表上的价格总是滞后很久,完全没法实现实时显示的需求。
我把自己的代码贴在下面,麻烦各位帮忙看看问题出在哪,有没有优化的方向可以推荐?
import threading import time from time import sleep import ccxt import pandas as pd import json import websocket from lightweight_charts import Chart import asyncio from binance.streams import BinanceSocketManager from binance.client import Client import tkinter as tk from tkinter import messagebox from datetime import datetime, timedelta import numpy as np api_key = "your_api_key_here" api_secret = "your_secret_key_here" client = Client(api_key, api_secret) PreviousPositionList = [] def calculate_percentage_change(price1, price2): try: return ((price2 - price1) / price1) * 100 except ZeroDivisionError: return 0 def create_tool_window(chart): window = tk.Tk() window.title("Chart Tools") label = tk.Label(window, text="Price Percentage: ", font=("Arial", 12)) label.pack(pady=10) draw_button = tk.Button(window, text="Enable Drawing Tool", command=lambda: enable_drawing_tool(chart)) draw_button.pack(pady=5) entry1_label = tk.Label(window, text="Enter price 1:", font=("Arial", 10)) entry1_label.pack(pady=5) price1_entry = tk.Entry(window) price1_entry.pack(pady=5) entry2_label = tk.Label(window, text="Enter price 2:", font=("Arial", 10)) entry2_label.pack(pady=5) price2_entry = tk.Entry(window) price2_entry.pack(pady=5) def calculate_percentage(): try: price1 = float(price1_entry.get()) price2 = float(price2_entry.get()) percentage_change = calculate_percentage_change(price1, price2) label.config(text=f"Price Percentage: {percentage_change:.2f}%") except ValueError: messagebox.showerror("Invalid Input", "Please enter valid numeric prices.") calculate_button = tk.Button(window, text="Calculate Percentage", command=calculate_percentage) calculate_button.pack(pady=5) window.mainloop() def BigSMAUpdater(ClosesDF, chart, sma_data, RayLines, FunctionRunning): time.sleep(1) def calculate_sma(closes, window=7): closes = pd.to_numeric(closes, errors='coerce') # This will convert non-numeric values to NaN closes = closes[~np.isnan(closes)] if len(closes) < window: return None return np.mean(closes[-window:]) ClosesDF['SMA_7'] = ClosesDF['Closes'].apply(lambda x: calculate_sma(x, window=7)) ClosesDF['SMA_25'] = ClosesDF['Closes'].apply(lambda x: calculate_sma(x, window=25)) ClosesDF['SMA_99'] = ClosesDF['Closes'].apply(lambda x: calculate_sma(x, window=99)) if len(RayLines) != 0: for TimeFrame, SMA7, SMA25, SMA99 in zip(ClosesDF['Timeframe'], ClosesDF['SMA_7'], ClosesDF['SMA_25'], ClosesDF['SMA_99']): if len(RayLines) != 0: RayDataFrame = pd.DataFrame(RayLines, columns=['Ray', 'TimeFrame', 'Type']) for Ray, RayTimeFrame, RayType in zip(RayDataFrame['Ray'], RayDataFrame['TimeFrame'], RayDataFrame['Type']): if RayTimeFrame == TimeFrame: if RayType == 'SMA_7': Ray.delete() RayLines.remove([Ray, RayTimeFrame, "SMA_7"]) Ray = chart.ray_line(sma_data[-5]['time'], value=SMA7, color="#ffff00") RayLines.append([Ray, RayTimeFrame, "SMA_7"]) elif RayType == 'SMA_25': Ray.delete() RayLines.remove([Ray, RayTimeFrame, "SMA_25"]) Ray = chart.ray_line(sma_data[-5]['time'], value=SMA25, color="#ff3399") RayLines.append([Ray, RayTimeFrame, "SMA_25"]) elif RayType == 'SMA_99': Ray.delete() RayLines.remove([Ray, RayTimeFrame, "SMA_99"]) Ray = chart.ray_line(sma_data[-5]['time'], value=SMA99, color="#00ccff") RayLines.append([Ray, RayTimeFrame, "SMA_99"]) else: for TimeFrame, SMA7, SMA25, SMA99 in zip(ClosesDF['Timeframe'], ClosesDF['SMA_7'], ClosesDF['SMA_25'], ClosesDF['SMA_99']): Ray = chart.ray_line(sma_data[-5]['time'], value=SMA7, color="#ffff00") RayLines.append([Ray, TimeFrame, "SMA_7"]) Ray = chart.ray_line(sma_data[-5]['time'], value=SMA25, color="#ff3399") RayLines.append([Ray, TimeFrame, "SMA_25"]) Ray = chart.ray_line(sma_data[-5]['time'], value=SMA99, color="#00ccff") RayLines.append([Ray, TimeFrame, "SMA_99"]) FunctionRunning.append(False) def binance_kline_stream(symbol, interval, line, line2, line3, chart, sma_data, RayLines): FunctionRunning = [] async def process_kline_data(coin, line, line2, line3, chart, sma_data, RayLines): bm = BinanceSocketManager(client) ts = bm.kline_futures_socket(symbol=coin, interval=interval) async with ts as tscm: while True: res = await tscm.recv() if res: candle = res['k'] close = candle['c'] open = candle['o'] high = candle['h'] low = candle['l'] time = pd.to_datetime(candle['t'], unit='ms') print(symbol, candle) if time != sma_data[-1]['time']: sma_data.append({'time': time, 'open': open, 'high': high, 'low': low, 'close': close}) else: sma_data[-1] = {'time': time, 'open': open, 'high': high, 'low': low, 'close': close} DataFrame = pd.DataFrame([{ 'time': pd.to_datetime(candle['t'], unit='ms'), 'open': float(open), 'high': float(high), 'low': float(low), 'close': float(close), }]) DataFrame['price'] = DataFrame['close'] if len(sma_data) >= 99: sma_df = pd.DataFrame(sma_data) sma99 = sma_df['close'].rolling(window=99).mean() sma25 = sma_df['close'].rolling(window=25).mean() sma7 = sma_df['close'].rolling(window=7).mean() sma_df['SMA 99'] = sma99 sma_df['SMA 25'] = sma25 sma_df['SMA 7'] = sma7 sma_df['price'] = sma_df['close'] sma_df['price'] = pd.to_numeric(sma_df['price'], errors='coerce') sma_df['SMA 99'] = pd.to_numeric(sma_df['SMA 99'], errors='coerce') sma_df['SMA 25'] = pd.to_numeric(sma_df['SMA 25'], errors='coerce') sma_df['SMA 7'] = pd.to_numeric(sma_df['SMA 7'], errors='coerce') DataFrame = sma_df.tail(1) for i, tick in DataFrame.iterrows(): chart.update(tick,_from_tick=True) line.update(tick) line2.update(tick) line3.update(tick) async def main(coin, line, line2, line3, chart, sma_data, RayLines): await process_kline_data(coin, line, line2, line3, chart, sma_data, RayLines) asyncio.run(main(symbol, line, line2, line3, chart, sma_data, RayLines)) def calculate_sma(df, period: int = 99): return pd.DataFrame({ 'time': df['time'], f'SMA {period}': df['close'].rolling(window=period).mean() }).dropna() def ChartCreater(Coin, chart): Data = ccxt.binanceusdm().fetch_ohlcv(symbol=Coin, timeframe="5m", limit=1000) DataFrame = pd.DataFrame(Data, columns=['Timestamp', 'open', 'high', 'low', 'close', 'volume']) DataFrame['Timestamp'] = pd.to_datetime(DataFrame['Timestamp'], unit='ms') DataFrame['time'] = DataFrame['Timestamp'] DataToPlot = DataFrame[['time', 'open', 'high', 'low', 'close']] if PreviousPositionList[-1] == 'left': chart2 = chart.create_subchart(position="right", width=0.45, height=0.3, CountDown=300) PreviousPositionList.append('right') else: chart2 = chart.create_subchart(position="left", width=0.45, height=0.3, CountDown=300) PreviousPositionList.append('left') chart2.set(DataToPlot) chart2.watermark(f'{Coin}', color='rgba(180, 180, 240, 1)', horzAlign='center', vertAlign='top') line = chart2.create_line('SMA 7', color='rgba(255, 255, 0,1)', width=0.5, price_label=False, price_line=False) sma7_data = calculate_sma(DataToPlot, period=7) line.set(sma7_data) line2 = chart2.create_line('SMA 25', color='rgba(255, 51, 204,1)', width=0.5, price_label=False, price_line=False) sma25_data = calculate_sma(DataToPlot, period=25) line2.set(sma25_data) line3 = chart2.create_line('SMA 99', color='rgba(0, 102, 255,1)', width=0.5, price_label=False, price_line=False) sma99_data = calculate_sma(DataToPlot, period=99) line3.set(sma99_data)
我自己初步排查了一下,怀疑是不是每个子图都单独开启了Websocket连接导致资源占用过高?或者是SMA计算的逻辑太耗时?但不确定具体是哪个环节拖慢了整体速度,希望大家能给点思路,谢谢!
备注:内容来源于stack exchange,提问作者Pasha Pasha




