File vizualization.py of Package fint-bot

import matplotlib.pyplot as plt
from datetime import datetime
import warnings


class Visualizer:
    def __init__(self, ticker, currency):
        self.ticker = ticker
        self.currency = currency
        self.buys = []
        self.sells = []
        self.prices = {}
        self._setup_plot()
        
    def _setup_plot(self):
        """Настройка графика с обработкой ошибок"""
        try:
            # Пробуем интерактивный режим
            plt.ion()
            self.fig = plt.figure(figsize=(12, 6))
            self.ax = self.fig.add_subplot(111)
            self.gui_available = True
            print(f"Визуализатор инициализирован для {self.ticker}")
        except Exception as e:
            # Если GUI недоступен, отключаем визуализацию
            self.fig = None
            self.ax = None
            self.gui_available = False
            print(f"Визуализация отключена: {e}")
            warnings.warn(f"GUI недоступен. Визуализация отключена для {self.ticker}")

    def add_price(self, time, price: float):
        """Добавление новой цены"""
        # Сохраняем цену
        if hasattr(time, 'isoformat'):
            time_key = time
        else:
            time_key = time
            
        self.prices[time_key] = price
        
        # Обновляем график если GUI доступен
        if self.gui_available:
            self.update_plot()

    def add_buy(self, time):
        """Добавление точки покупки"""
        if hasattr(time, 'isoformat'):
            time_key = time
        else:
            time_key = time
            
        self.buys.append(time_key)
        
        if self.gui_available:
            # Обновляем график, чтобы показать покупку
            self.update_plot()

    def add_sell(self, time):
        """Добавление точки продажи"""
        if hasattr(time, 'isoformat'):
            time_key = time
        else:
            time_key = time
            
        self.sells.append(time_key)
        
        if self.gui_available:
            # Обновляем график, чтобы показать продажу
            self.update_plot()

    def update_plot(self):
        """Обновление графика"""
        if not self.gui_available or not self.fig or not self.ax:
            return
            
        if not self.prices:  # Нет данных для отображения
            return
            
        try:
            self.ax.clear()
            
            # Сортируем цены по времени
            sorted_times = sorted(self.prices.keys())
            sorted_prices = [self.prices[t] for t in sorted_times]
            
            # Берем последние 50 точек или все, если меньше
            if len(sorted_times) > 50:
                x = sorted_times[-50:]
                y = sorted_prices[-50:]
            else:
                x = sorted_times
                y = sorted_prices

            if not x:  # Проверка на случай пустого списка
                return
                
            # Рисуем график цены
            self.ax.plot(x, y, 'b-', linewidth=1.5, label='Price')
            self.ax.set_title(f'{self.ticker} - Price Chart')
            self.ax.set_xlabel('Time')
            self.ax.set_ylabel(f'Price ({self.currency})')
            self.ax.grid(True, alpha=0.3)
            self.ax.legend()
            
            # Отображаем точки покупок и продаж на видимом интервале
            if y:
                min_y = min(y)
                max_y = max(y)
                visible_min_time = x[0]
                
                # Покупки (зеленые линии)
                buys_in_range = [buy for buy in self.buys if buy >= visible_min_time]
                if buys_in_range:
                    self.ax.vlines(buys_in_range, ymin=min_y, ymax=max_y, 
                                   color='g', linewidth=1.2, alpha=0.6, 
                                   label='Buy', linestyle='--')
                
                # Продажи (красные линии)
                sells_in_range = [sell for sell in self.sells if sell >= visible_min_time]
                if sells_in_range:
                    self.ax.vlines(sells_in_range, ymin=min_y, ymax=max_y, 
                                   color='r', linewidth=1.2, alpha=0.6, 
                                   label='Sell', linestyle='--')
            
            # Автоматическая настройка меток времени
            if x:
                self.ax.tick_params(axis='x', rotation=45)
                plt.tight_layout()
            
            # Обновляем график
            self.fig.canvas.draw()
            self.fig.canvas.flush_events()
            plt.pause(0.01)  # Короткая пауза для обновления
            
        except Exception as e:
            print(f"Ошибка при обновлении графика: {e}")
            self.gui_available = False

    def save_plot(self, filename=None):
        """Сохранение графика в файл"""
        if not self.gui_available:
            print("Невозможно сохранить график: GUI недоступен")
            return
            
        if filename is None:
            filename = f"{self.ticker}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
            
        try:
            self.fig.savefig(filename, dpi=150, bbox_inches='tight')
            print(f"График сохранен в {filename}")
        except Exception as e:
            print(f"Ошибка при сохранении графика: {e}")

    def close(self):
        """Закрытие графика"""
        if self.gui_available and self.fig:
            try:
                plt.close(self.fig)
            except:
                pass

    def __del__(self):
        """Деструктор для закрытия графика"""
        self.close()
openSUSE Build Service is sponsored by