Маркеры должны отображаться прямо на свечах. Но в процессе построения графика свеча строится реалтайм, когда появляется маркер крупной сделки, свечка сжимается и отображается на графике слева, а маркер справа.
Python:
import matplotlib.pyplot as plt
import mplfinance as mpf
import pandas as pd
import websocket
import threading
import json
from matplotlib.animation import FuncAnimation
# Создаем пустой DataFrame для свечного графика и агрегированных сделок
df_candle = pd.DataFrame(columns=['Open', 'High', 'Low', 'Close', 't', 'T'])
df_trades = pd.DataFrame(columns=['Price', 'Quantity', 'IsBuyerMaker', 'T'])
class SocketConn(websocket.WebSocketApp):
def __init__(self, url, on_message):
super().__init__(url=url, on_open=self.on_open)
self.on_message = on_message
self.on_error = lambda ws, e: print("Error", e)
self.on_close = lambda ws: print("Closing")
self.run_forever()
def on_open(self, ws):
print("Websocket was opened")
def on_message_candle(ws, msg):
global df_candle
data = json.loads(msg) # Преобразуем сообщение в словарь Python
kline = data['k']
df_candle.loc[pd.to_datetime(kline['t'], unit='ms')] = [kline['o'], kline['h'], kline['l'], kline['c'], kline['t'], kline['T']]
# print(kline)
def on_message_trade(ws, msg):
global df_trades
data = json.loads(msg) # Преобразуем сообщение в словарь Python
if float(data['q']) > 5: # Если объем сделки больше 5
df_trades.loc[pd.to_datetime(data['T'], unit='ms')] = [data['p'], data['q'], data['m'], data['T']]
print(f"Large {'buy' if data['m'] else 'sell'} trade: Price {data['p']}, Quantity {data['q']}")
threading.Thread(target=SocketConn, args=("wss://fstream.binance.com/ws/btcusdt@kline_5m", on_message_candle)).start()
threading.Thread(target=SocketConn, args=("wss://fstream.binance.com/ws/btcusdt@aggTrade", on_message_trade)).start()
fig, ax = plt.subplots()
def update_graph(i):
if not df_candle.empty:
ax.clear()
df_tail = df_candle.tail(400).astype(float)
mpf.plot(df_tail, type='candle', ax=ax)
if not df_trades.empty:
for _, row in df_tail.iterrows():
trades_in_candle = df_trades[(df_trades['T'] >= row['t']) & (df_trades['T'] <= row['T'])]
for _, trade_row in trades_in_candle.iterrows():
color = 'green' if trade_row['IsBuyerMaker'] == True else 'red'
size = float(trade_row['Quantity']) * 5 # Увеличиваем размер маркера в 5 раз
ax.scatter(row.name, float(trade_row['Price']), color=color, s=size) # Используем время свечи для размещения маркеров
ani = FuncAnimation(fig, update_graph, interval=100, cache_frame_data=False)
plt.show()