import sys
from datetime import datetime

from PyQt5.QtWidgets import (
    QApplication, QWidget, QLabel, QPushButton, QVBoxLayout,
    QComboBox, QHBoxLayout, QLineEdit, QDoubleSpinBox, QSpinBox, QTableWidgetItem, QTableWidget
)
from PyQt5.QtCore import QThread, pyqtSignal

import BestDvg_opt
import BestDvg_fut
import DataFromBB_BTC
import DataFromBB_ETH
import POST

class DataUpdater(QThread):
    data_updated = pyqtSignal(tuple)

    def __init__(self, data_source):
        super().__init__()
        self.data_source = data_source  # Добавляем атрибут для источника данных

    def run(self):
        start_time = datetime.now()
        print(f"Программа запущена в: {start_time.strftime('%Y-%m-%d %H:%M:%S')}")

        while True:
            try:
                # Получаем данные в зависимости от источника
                if self.data_source == "BTC":
                    options_data, futures_data, usdt_perp_data, usdc_perp_data, spot = DataFromBB_BTC.process_tickers()
                else:
                    options_data, futures_data, usdt_perp_data, usdc_perp_data, spot = DataFromBB_ETH.process_tickers()

                self.data_updated.emit((options_data, futures_data, usdt_perp_data, usdc_perp_data, spot))
                print(f"Данные обновлены в: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
                self.sleep(3)
            except Exception as e:
                print(f"Ошибка: {e}")
                if "Rate Limit" in str(e):
                    print("Превышен лимит API, ждем перед повторной попыткой...")
                    self.sleep(10)
                else:
                    self.sleep(3)


class DataUpdaterDvg(QThread):
    data_updated_dvg = pyqtSignal(dict)

    def __init__(self, data_source):
        super().__init__()
        self.data_source = data_source  # Добавляем атрибут для источника данных

    def run(self):
        while True:
            try:
                if self.data_source == "BTC":
                    data = BestDvg_opt.get_BTC_dvg()
                    print("BTC")
                else:
                    data = BestDvg_opt.get_ETH_dvg()
                    print("ETH")

                self.data_updated_dvg.emit(data)  # Отправляем данные через сигнал
                self.sleep(3)
            except Exception as e:
                print(f"Ошибка: {e}")
                if "Rate Limit" in str(e):
                    print("Превышен лимит API, ждем перед повторной попыткой...")
                    self.sleep(10)
                else:
                    self.sleep(3)

class DataUpdaterDvgFut(QThread):
    data_updated_dvg_fut = pyqtSignal(dict)

    def __init__(self, data_source):
        super().__init__()
        self.data_source = data_source  # Добавляем атрибут для источника данных

    def run(self):
        while True:
            try:
                if self.data_source == "BTC":
                    data = BestDvg_fut.get_BTC_dvg()
                    print("BTC")
                else:
                    data = BestDvg_fut.get_ETH_dvg()
                    print("ETH")

                self.data_updated_dvg_fut.emit(data)  # Отправляем данные через сигнал
                self.sleep(3)
            except Exception as e:
                print(f"Ошибка: {e}")
                if "Rate Limit" in str(e):
                    print("Превышен лимит API, ждем перед повторной попыткой...")
                    self.sleep(10)
                else:
                    self.sleep(3)

class PositionWidget(QWidget):
    def __init__(self, remove_callback, option_data):
        """
        remove_callback — функция, вызываемая для удаления этой позиции из родительского виджета.
        """
        super().__init__()
        # Инициализация параметров позиции
        self.position_name = "Бессрочный USDT"   # Выбор из списка 4 позиций
        self.leverage = 10                 # Кредитное плечо
        self.expiration = "1 неделя"       # Срок действия
        self.strike_price = 100            # Страйк-цена
        self.option_type = "Call"          # Тип (применяется для позиции 4)
        self.direction = "Купить"          # Направление
        self.demand_size = 100             # Размер спроса
        self.demand_price = 10             # Цена спроса
        self.order_price = 10              # Цена ордера/IV (пересчитывается)
        self.quantity = 0.1                # Количество
        self.offer_size = 150              # Размер предложения
        self.offer_price = 12              # Цена предложения/IV
        self.fee = 1                       # Размер комиссии

        self.remove_callback = remove_callback
        self.option_data = option_data  # Хранит общий option_data
        # Переменная для фиксации цены ордера
        self.is_order_price_fixed = False

        # -------------------------------
        # 1. Наименование позиции
        self.position_name_combo = QComboBox(self)
        self.position_name_combo.addItems(["Бессрочный USDT", "Бессрочный USDC", "USDC фьючерсы", "USDC опционы", "Спот"])
        self.position_name_combo.setCurrentText(self.position_name)
        self.position_name_combo.currentTextChanged.connect(self.update_position_name)
        layout_name = QVBoxLayout()
        layout_name.addWidget(QLabel("Наименование"))
        layout_name.addWidget(self.position_name_combo)

        # -------------------------------
        # 2. Кредитное плечо
        self.leverage_input = QSpinBox(self)
        self.leverage_input.setRange(1, 100)
        self.leverage_input.setValue(self.leverage)
        self.leverage_input.valueChanged.connect(self.update_leverage)
        self.leverage_label = QLabel("——", self)
        self.leverage_label.hide()  # По умолчанию скрыта
        layout_leverage = QVBoxLayout()
        layout_leverage.addWidget(QLabel("Кред. плечо"))
        layout_leverage.addWidget(self.leverage_input)
        layout_leverage.addWidget(self.leverage_label)

        # -------------------------------
        # 3. Срок действия
        self.expiration_combo = QComboBox(self)
        self.expiration_combo.addItems(["1 неделя", "1 месяц", "3 месяца"])
        self.expiration_combo.setCurrentText(self.expiration)
        self.expiration_combo.currentTextChanged.connect(self.update_expiration)
        self.expiration_label = QLabel("——", self)
        self.expiration_label.hide()
        layout_expiration = QVBoxLayout()
        layout_expiration.addWidget(QLabel("Срок действия"))
        layout_expiration.addWidget(self.expiration_combo)
        layout_expiration.addWidget(self.expiration_label)

        # -------------------------------
        # 4. Страйк-цена
        self.strike_price_combo = QComboBox(self)
        self.strike_price_combo.addItems([str(x) for x in range(90, 111, 5)])
        self.strike_price_combo.setCurrentText(str(100))
        self.strike_price_combo.currentTextChanged.connect(self.update_strike_price)
        self.strike_price_display = QLabel("——", self)
        self.strike_price_display.hide()
        layout_strike = QVBoxLayout()
        layout_strike.addWidget(QLabel("Страйк-цена"))
        layout_strike.addWidget(self.strike_price_combo)
        layout_strike.addWidget(self.strike_price_display)

        # -------------------------------
        # 5. Тип
        self.option_type_combo = QComboBox(self)
        self.option_type_combo.addItems(["Call", "Put"])
        self.option_type_combo.setCurrentText(self.option_type)
        self.option_type_combo.currentTextChanged.connect(self.update_option_type)
        self.option_type_label = QLabel("——", self)
        self.option_type_label.hide()
        layout_option_type = QVBoxLayout()
        layout_option_type.addWidget(QLabel("Тип"))
        layout_option_type.addWidget(self.option_type_combo)
        layout_option_type.addWidget(self.option_type_label)

        # -------------------------------
        # 6. Направление
        self.direction_combo = QComboBox(self)
        self.direction_combo.addItems(["Купить", "Продать"])
        self.direction_combo.setCurrentText(self.direction)
        self.direction_combo.currentTextChanged.connect(self.update_direction)
        layout_direction = QVBoxLayout()
        layout_direction.addWidget(QLabel("Направление"))
        layout_direction.addWidget(self.direction_combo)

        # 7. Размер спроса
        self.demand_size_input = QDoubleSpinBox(self)
        self.demand_size_input.setRange(0.001, 1000.0)
        self.demand_size_input.setValue(self.demand_size)
        self.demand_size_input.setDecimals(3)  # Устанавливаем 3 знака после запятой
        self.demand_size_input.valueChanged.connect(self.update_demand_size)
        layout_demand_size = QVBoxLayout()
        layout_demand_size.addWidget(QLabel("Размер спроса"))
        layout_demand_size.addWidget(self.demand_size_input)

        # 8. Цена спроса
        self.demand_price_input = QLineEdit(str(self.demand_price), self)
        self.demand_price_input.textChanged.connect(self.update_demand_price)
        layout_demand_price = QVBoxLayout()
        layout_demand_price.addWidget(QLabel("Цена спроса"))
        layout_demand_price.addWidget(self.demand_price_input)

        # 9. Цена ордера/IV
        self.order_price_input = QLineEdit(str(self.order_price), self)
        self.order_price_input.setReadOnly(not self.is_order_price_fixed)  # Делаем поле редактируемым или нет
        layout_order_price = QVBoxLayout()
        layout_order_price.addWidget(QLabel("Цена ордера"))
        layout_order_price.addWidget(self.order_price_input)

        # 10. Количество
        self.quantity_input = QDoubleSpinBox(self)
        self.quantity_input.setRange(0.001, 1000.0)
        self.quantity_input.setValue(self.quantity)
        self.quantity_input.setDecimals(3)  # Устанавливаем 3 знака после запятой
        self.quantity_input.valueChanged.connect(self.update_quantity)
        layout_quantity = QVBoxLayout()
        layout_quantity.addWidget(QLabel("Количество"))
        layout_quantity.addWidget(self.quantity_input)

        # 11. Размер предложения
        self.offer_size_input = QDoubleSpinBox(self)
        self.offer_size_input.setRange(0.001, 1000.0)
        self.offer_size_input.setValue(self.offer_size)
        self.offer_size_input.setDecimals(3)  # Устанавливаем 3 знака после запятой
        self.offer_size_input.valueChanged.connect(self.update_offer_size)
        layout_offer_size = QVBoxLayout()
        layout_offer_size.addWidget(QLabel("Размер предложения"))
        layout_offer_size.addWidget(self.offer_size_input)

        # 12. Цена предложения/IV
        self.offer_price_input = QLineEdit(str(self.offer_price), self)
        self.offer_price_input.textChanged.connect(self.update_offer_price)
        layout_offer_price = QVBoxLayout()
        layout_offer_price.addWidget(QLabel("Цена предложения"))
        layout_offer_price.addWidget(self.offer_price_input)

        # 13. Кнопка удаления позиции
        self.delete_button = QPushButton("Удалить", self)
        self.delete_button.clicked.connect(lambda: self.remove_callback(self))
        layout_delete = QVBoxLayout()
        layout_delete.addWidget(QLabel("Действие"))
        layout_delete.addWidget(self.delete_button)

        # 14. Кнопка фиксации/разблокировки цены ордера
        self.toggle_price_button = QPushButton("Зафиксировать цену ордера", self)
        self.toggle_price_button.clicked.connect(self.toggle_order_price_fixation)
        layout_toggle_price = QVBoxLayout()
        layout_toggle_price.addWidget(QLabel(""))
        layout_toggle_price.addWidget(self.toggle_price_button)

        # 14. Комиссия
        self.fee_rate = QLineEdit(str(self.fee), self)
        layout_fee_rate = QVBoxLayout()
        layout_fee_rate.addWidget(QLabel("Комиссия"))
        layout_fee_rate.addWidget(self.fee_rate)

        # Основной горизонтальный макет для размещения всех групп
        main_layout = QHBoxLayout()
        main_layout.addLayout(layout_name)
        main_layout.addLayout(layout_leverage)
        main_layout.addLayout(layout_expiration)
        main_layout.addLayout(layout_strike)
        main_layout.addLayout(layout_option_type)
        main_layout.addLayout(layout_direction)
        main_layout.addLayout(layout_demand_size)
        main_layout.addLayout(layout_demand_price)
        main_layout.addLayout(layout_order_price)
        main_layout.addLayout(layout_quantity)
        main_layout.addLayout(layout_offer_size)
        main_layout.addLayout(layout_offer_price)
        main_layout.addLayout(layout_delete)
        main_layout.addLayout(layout_toggle_price)  # Добавьте кнопку фиксации в конец
        main_layout.addLayout(layout_fee_rate)

        # Устанавливаем основной макет для виджета позиции (без заголовка)
        self.setLayout(main_layout)

        # Первоначальное обновление отображения в зависимости от выбранной позиции
        self.update_position_name(self.position_name)
        self.update_order_price()  # Обновляем цену ордера согласно начальным параметрам

        self.option_data, self.futures_data, self.usdt_perp_data, self.usdc_perp_data, self.spot_data = DataFromBB_BTC.process_tickers()

    def toggle_order_price_fixation(self):
        """Переключение состояния фиксации цены ордера."""
        self.is_order_price_fixed = not self.is_order_price_fixed
        if self.is_order_price_fixed:
            self.toggle_price_button.setText("Разблокировать цену ордера")
            self.order_price_input.setReadOnly(False)  # Делаем поле редактируемым
            self.order_price_input.setStyleSheet("font-weight: bold; color: green;")  # Для визуального обозначения
        else:
            self.toggle_price_button.setText("Зафиксировать цену ордера")
            self.order_price_input.setReadOnly(True)  # Делаем поле не редактируемым
            self.order_price_input.setStyleSheet("")  # Сброс стиля

        # Обновляем цену ордера на основе введенного значения
        self.update_order_price()

    def update_option_data(self, options_data, futures_data, usdt_perp_data, usdc_perp_data, spot_data):
        """Получение и обновление данных для позиции."""
        self.option_data = options_data  # Хранит данные
        self.futures_data = futures_data
        self.usdt_perp_data = usdt_perp_data
        self.usdc_perp_data = usdc_perp_data
        self.spot_data = spot_data

        # Вам нужно добавить логику для обновления информации о фьючерсах и других типах данных, если это необходимо
        # Пример обновления данных опций:
        if self.position_name == "USDC опционы":
            self.update_strike_price(self.strike_price)
            self.update_fee_rate(self.option_data.get(self.expiration)[0].get('options')[0].get('fee'))

        if self.position_name == "USDC фьючерсы":
            self.update_expiration(self.expiration)
            self.update_fee_rate(self.futures_data.get(self.expiration)[0].get('fee'))


        elif self.position_name == "Бессрочный USDT":
            try:
                self.demand_size = float(self.usdt_perp_data[0].get('bid1Size'))
                self.demand_price = float(self.usdt_perp_data[0].get('bid1Price'))
                self.offer_size = float(self.usdt_perp_data[0].get('ask1Size'))
                self.offer_price = float(self.usdt_perp_data[0].get('ask1Price'))

                self.demand_size_input.setValue(self.demand_size)
                self.demand_price_input.setText(str(self.demand_price))
                self.offer_size_input.setValue(self.offer_size)
                self.offer_price_input.setText(str(self.offer_price))

                self.update_order_price()

                self.update_fee_rate(self.usdt_perp_data[0].get('fee'))
            except Exception:
                pass

        elif self.position_name == "Бессрочный USDC":
            try:
                self.demand_size = float(self.usdc_perp_data[0].get('bid1Size'))
                self.demand_price = float(self.usdc_perp_data[0].get('bid1Price'))
                self.offer_size = float(self.usdc_perp_data[0].get('ask1Size'))
                self.offer_price = float(self.usdc_perp_data[0].get('ask1Price'))

                self.demand_size_input.setValue(self.demand_size)
                self.demand_price_input.setText(str(self.demand_price))
                self.offer_size_input.setValue(self.offer_size)
                self.offer_price_input.setText(str(self.offer_price))

                self.update_order_price()

                self.update_fee_rate(self.usdc_perp_data[0].get('fee'))
            except Exception:
                pass

        elif self.position_name == "Спот":
            try:
                self.demand_size = float(self.spot_data[0].get('bid1Size'))
                self.demand_price = float(self.spot_data[0].get('bid1Price'))
                self.offer_size = float(self.spot_data[0].get('ask1Size'))
                self.offer_price = float(self.spot_data[0].get('ask1Price'))

                self.demand_size_input.setValue(self.demand_size)
                self.demand_price_input.setText(str(self.demand_price))
                self.offer_size_input.setValue(self.offer_size)
                self.offer_price_input.setText(str(self.offer_price))

                self.update_order_price()

                self.update_fee_rate(self.spot_data[0].get('fee'))
            except Exception:
                pass


    def update_position_name(self, text):
        """Обновление наименования позиции и переключение между интерактивными элементами и метками."""
        self.position_name = text
        if self.position_name == "USDC опционы":
            # Обновляем даты экспирации
            self.expiration_combo.clear()
            self.expiration_combo.addItems(self.option_data.keys())
            # Обновляем Страйк цены
            self.strike_price_combo.show()
            self.strike_price_display.hide()
            # Для позиции 4:
            # Кредитное плечо не применяется
            self.leverage_input.hide()
            self.leverage_label.setText("——")
            self.leverage_label.show()
            # Срок действия применяется
            self.expiration_combo.show()
            self.expiration_label.hide()
            # Страйк-цена и Тип применяются
            self.option_type_combo.show()
            self.option_type_label.hide()
        elif self.position_name in ["Бессрочный USDT", "Бессрочный USDC", "Спот"]:
            # Для позиций 1 и 2:
            # Кредитное плечо применяется
            self.leverage_input.show()
            self.leverage_label.hide()
            # Срок действия не применяется
            self.expiration_combo.hide()
            self.expiration_label.setText("——")
            self.expiration_label.show()
            self.expiration_combo.clear()
            self.expiration_combo.addItems(["1 неделя", "1 месяц", "3 месяца"])
            self.expiration_combo.setCurrentText("1 неделя")
            # Страйк-цена и Тип не применяются
            self.strike_price_combo.hide()
            self.strike_price_display.setText("——")
            self.strike_price_display.show()
            self.strike_price_combo.clear()
            self.strike_price_combo.addItems([str(x) for x in range(90, 111, 5)])
            self.strike_price_combo.setCurrentText(str(100))
            self.option_type_combo.hide()
            self.option_type_label.setText("——")
            self.option_type_label.show()
            self.option_type_combo.clear()
            self.option_type_combo.addItems(["Call", "Put"])
            self.option_type_combo.setCurrentText("Call")
        elif self.position_name == "USDC фьючерсы":
            # Для позиции 3:
            self.expiration_combo.clear()
            self.expiration_combo.addItems(self.futures_data.keys())
            # Кредитное плечо применяется
            self.leverage_input.show()
            self.leverage_label.hide()
            # Срок действия применяется
            self.expiration_combo.show()
            self.expiration_label.hide()
            # Страйк-цена и Тип не применяются
            self.strike_price_combo.hide()
            self.strike_price_display.setText("——")
            self.strike_price_display.show()
            self.strike_price_combo.clear()
            self.strike_price_combo.addItems([str(x) for x in range(90, 111, 5)])
            self.strike_price_combo.setCurrentText(str(100))
            self.option_type_combo.hide()
            self.option_type_label.setText("——")
            self.option_type_label.show()
            self.option_type_combo.clear()
            self.option_type_combo.addItems(["Call", "Put"])
            self.option_type_combo.setCurrentText("Call")

    def update_leverage(self, value):
        self.leverage = value

    def update_expiration(self, text):
        self.expiration = text
        if self.position_name == "USDC опционы":
            try:
                self.strike_price_combo.clear()
                for i in range(len(self.option_data[self.expiration])):
                    self.strike_price_combo.addItems([self.option_data[self.expiration][i]['str_price']])
            except Exception:
                pass

        if self.position_name == "USDC фьючерсы":
            try:
                self.demand_size = float(self.futures_data.get(self.expiration)[0].get('bid1Size'))
                self.demand_price = float(self.futures_data.get(self.expiration)[0].get('bid1Price'))
                self.offer_size = float(self.futures_data.get(self.expiration)[0].get('ask1Size'))
                self.offer_price = float(self.futures_data.get(self.expiration)[0].get('ask1Price'))

                self.demand_size_input.setValue(self.demand_size)
                self.demand_price_input.setText(str(self.demand_price))
                self.offer_size_input.setValue(self.offer_size)
                self.offer_price_input.setText(str(self.offer_price))

                self.update_order_price()
            except Exception:
                pass


    def update_strike_price(self, text):
        try:
            self.strike_price = int(text)
            if self.position_name == "USDC опционы":
                if self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('option_type') == 'Call' and self.option_type == 'Call' or self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('option_type') == 'Put' and self.option_type == 'Put':
                    # Если тип Call, устанавливаем параметры
                    self.demand_size = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('bid1Size'))
                    self.demand_price = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('bid1Price'))
                    self.offer_size = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('ask1Size'))
                    self.offer_price = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('ask1Price'))
                elif self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('option_type') == 'Call' and self.option_type == 'Put' or self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[0].get('option_type') == 'Put' and self.option_type == 'Call':
                    # Если тип Put, устанавливаем параметры
                    self.demand_size = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[1].get('bid1Size'))
                    self.demand_price = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[1].get('bid1Price'))
                    self.offer_size = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[1].get('ask1Size'))
                    self.offer_price = float(self.option_data.get(self.expiration)[self.strike_price_combo.currentIndex()].get('options')[1].get('ask1Price'))

                self.demand_size_input.setValue(self.demand_size)
                self.demand_price_input.setText(str(self.demand_price))
                self.offer_size_input.setValue(self.offer_size)
                self.offer_price_input.setText(str(self.offer_price))


            self.update_order_price()
        except ValueError:
            pass

    def update_option_type(self, text):
        self.option_type = text
        self.update_strike_price(self.strike_price)

    def update_direction(self, text):
        self.direction = text
        self.update_order_price()  # Пересчитываем цену ордера

    def update_demand_size(self, value):
        self.demand_size = value

    def update_demand_price(self, text):
        try:
            self.demand_price = float(text)
        except ValueError:
            pass
        self.update_order_price()  # Пересчитываем цену ордера при изменении цены спроса

    def update_quantity(self, value):
        self.quantity = value

    def update_offer_size(self, value):
        self.offer_size = value

    def update_offer_price(self, text):
        try:
            self.offer_price = float(text)
        except ValueError:
            pass
        self.update_order_price()  # Пересчитываем цену ордера при изменении цены предложения

    def update_fee_rate(self, value):
        self.fee = f"{value * self.quantity * self.order_price:.3f}"
        self.fee_rate.setText(self.fee)

    def update_order_price(self):
        """Пересчет цены ордера в зависимости от направления.
           Если направление 'Купить' – цена ордера равна цене предложения,
           иначе – цена ордера равна цене спроса."""
        if self.is_order_price_fixed:
            try:
                # Если цена зафиксирована, считываем значение из поля ввода
                self.order_price = float(self.order_price_input.text())
            except ValueError:
                pass  # Игнорируем ошибки преобразования
        else:
            if self.direction == "Купить":
                self.order_price = self.offer_price
            else:
                self.order_price = self.demand_price

        self.order_price_input.setText(f"{self.order_price}")  # Обновляем поле ввода с новой ценой


class App(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Конструктор позиций")
        self.setGeometry(100, 100, 1400, 100)

        # Create instances of the display windows
        self.open_position_display_window = OpenPositionDisplayWindow()
        self.data_display_window = DataDisplayWindow()
        self.parameters_display_window = ParametersDisplayWindow()  # New parameters display window

        self.open_position_display_window.show()
        self.data_display_window.show()  # Show the original window on startup
        self.parameters_display_window.show()  # Show the new parameters window on startup

        self.positions = []

        self.data_fetcher_fut = DataUpdaterDvgFut(data_source="BTC")
        self.data_fetcher_fut.data_updated_dvg_fut.connect(self.update_dvg_futures)
        self.data_fetcher_fut.start()

        self.data_fetcher = DataUpdaterDvg(data_source="BTC")
        self.data_fetcher.data_updated_dvg.connect(self.update_dvg)
        self.data_fetcher.start()

        # Создание потока для обновления данных
        self.data_updater = DataUpdater(data_source="BTC")
        self.data_updater.data_updated.connect(self.update_all_positions)  # Подключаем сигнал к методу
        self.data_updater.start()  # Запуск потока

        # Единая плашка для всех позиций
        header_label = QLabel("Параметры позиции:")
        header_label.setStyleSheet("font-size: 16px; font-weight: bold;")

        # Добавление кнопок для выбора BTC и ETH
        self.btc_button = QPushButton("BTC", self)
        self.eth_button = QPushButton("ETH", self)

        # Установка начального состояния (BTC выбран по умолчанию)
        self.btc_button.setStyleSheet("background-color: green; color: white;")  # Подсветка BTC
        self.eth_button.setStyleSheet("background-color: lightgray; color: black;")  # Неактивная ETH

        # Подключение сигналов к методам
        self.btc_button.clicked.connect(self.select_btc)
        self.eth_button.clicked.connect(self.select_eth)

        # Установка начального состояния (BTC выбран по умолчанию)
        self.btc_button.setChecked(True)

        # Горизонтальный макет для кнопок
        button_layout = QHBoxLayout()
        button_layout.addWidget(self.btc_button)
        button_layout.addWidget(self.eth_button)

        # Вертикальный макет для размещения позиций
        self.positions_layout = QVBoxLayout()

        # Основной вертикальный макет с единым заголовком
        self.main_layout = QVBoxLayout()
        self.main_layout.addWidget(header_label)
        self.main_layout.addLayout(button_layout)
        self.main_layout.addLayout(self.positions_layout)

        # Кнопка для добавления новой позиции
        self.add_button = QPushButton("Добавить позицию", self)
        self.add_button.clicked.connect(self.add_position)

        # Новая кнопка для отправки данных
        self.send_button = QPushButton("Отправить в книгу ордеров", self)
        self.send_button.clicked.connect(self.send_positions_data)  # Привязываем сигнал к функции

        add_layout = QHBoxLayout()
        add_layout.addWidget(self.add_button)
        add_layout.addWidget(self.send_button)  # Добавляем новую кнопку в горизонтальный макет

        # Добавляем кнопку в основной макет
        self.main_layout.addLayout(add_layout)
        self.setLayout(self.main_layout)

    def select_btc(self):
        """Выбор BTC как источника данных."""
        self.data_fetcher_fut.data_source = "BTC"
        self.data_updater.data_source = "BTC"  # Устанавливаем источник данных на BTC
        self.data_fetcher.data_source = "BTC"  # Обновляем источник данных для DataUpdaterDvg
        self.btc_button.setStyleSheet("background-color: green; color: white;")  # Подсветка выбранной кнопки
        self.eth_button.setStyleSheet("background-color: lightgray; color: black;")  # Сброс стиля невыбранной кнопки

    def select_eth(self):
        """Выбор ETH как источника данных."""
        self.data_fetcher_fut.data_source = "ETH"
        self.data_updater.data_source = "ETH"  # Устанавливаем источник данных на ETH
        self.data_fetcher.data_source = "ETH"  # Обновляем источник данных для DataUpdaterDvg
        self.eth_button.setStyleSheet("background-color: green; color: white;")  # Подсветка выбранной кнопки
        self.btc_button.setStyleSheet("background-color: lightgray; color: black;")  # Сброс стиля невыбранной кнопки

    def send_positions_data(self):
        """Сбор данных всех открытых позиций и отправка их."""
        # Собираем данные всех позиций
        positions_data = []

        for position in self.positions:
            position_data = {
                'position_name': position.position_name,
                'leverage': position.leverage,
                'expiration': position.expiration,
                'strike_price': position.strike_price,
                'option_type': position.option_type,
                'direction': position.direction,
                'demand_size': position.demand_size,
                'demand_price': position.demand_price,
                'order_price': position.order_price,
                'quantity': position.quantity,
                'offer_size': position.offer_size,
                'offer_price': position.offer_price,
                'data_source': self.data_updater.data_source
            }
            positions_data.append(position_data)

        POST.post_orders(positions_data, self.open_position_display_window)  # Передаем собранные данные

    def add_position(self):
        """Добавление новой позиции в интерфейс, передавая общий option_data."""
        position = PositionWidget(remove_callback=self.remove_position, option_data={})
        self.positions.append(position)
        self.positions_layout.addWidget(position)

    def update_all_positions(self, data):
        options_data, futures_data, usdt_perp_data, usdc_perp_data, spot = data

        for position in self.positions:
            position.update_option_data(options_data, futures_data, usdt_perp_data, usdc_perp_data, spot)

    def update_dvg_futures(self, dvg_data_fut):
        """Update all positions and refresh the data display window."""
        position_data = []  # Collect data for the display window

        # You might need to adjust the way you access data based on your exact requirements
        for _ in dvg_data_fut.keys():
            position_info = dvg_data_fut[_]
            for entry in position_info:
                # Assuming the structure of entry matches your requirements
                position_data.append([
                    _,
                    entry[0],  # Купить
                    entry[1],  # Продать
                    entry[2],  # Result
                ])

        # Update the data display window with the collected data
        self.parameters_display_window.update_data(position_data)

    def update_dvg(self, dvg_data):
        """Update all positions and refresh the data display window."""
        position_data = []  # Collect data for the display window

        # You might need to adjust the way you access data based on your exact requirements
        for _ in dvg_data.keys():
            position_info = dvg_data[_]
            for entry in position_info:
                # Assuming the structure of entry matches your requirements
                position_data.append([
                    _,
                    entry[0],  # Call (Купить)
                    entry[1],  # Call (Продать)
                    entry[2],  # Put (Купить)
                    entry[3],  # Put (Продать)
                    entry[4],  # Strike Call
                    entry[5],  # Strike Put
                    entry[6]  # Result
                ])

        # Update the data display window with the collected data
        self.data_display_window.update_data(position_data)

    def remove_position(self, position_widget):
        """Удаление позиции из интерфейса и списка."""
        try:
            if position_widget in self.positions:
                self.positions.remove(position_widget)
                self.positions_layout.removeWidget(position_widget)
                position_widget.deleteLater()
        except Exception as e:
            print(e)

class DataDisplayWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Лучшая разница опционы")
        self.setGeometry(50, 500, 850, 500)

        # Create a table widget
        self.table_widget = QTableWidget(self)
        self.table_widget.setColumnCount(8)  # 8 columns
        self.table_widget.setHorizontalHeaderLabels(["Date expiration", "Call (Купить)", "Call (Продать)", "Put (Купить)", "Put (Продать)", "Strike Call", "Strike Put", "Result, %"])

        # Layout for the table
        layout = QVBoxLayout()
        layout.addWidget(self.table_widget)
        self.setLayout(layout)

    def update_data(self, data):
        """Update the table with the provided data."""
        self.table_widget.setRowCount(len(data))
        for row_index, row_data in enumerate(data):
            for column_index, item in enumerate(row_data):
                self.table_widget.setItem(row_index, column_index, QTableWidgetItem(str(item)))

class ParametersDisplayWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Лучшая разница фьючерсы")
        self.setGeometry(900, 500, 450, 500)

        # Create a table widget
        self.table_widget = QTableWidget(self)
        self.table_widget.setColumnCount(4)  # 4 columns
        self.table_widget.setHorizontalHeaderLabels(["Date expiration", "Купить", "Продать", "Result %"])

        # Layout for the table
        layout = QVBoxLayout()
        layout.addWidget(self.table_widget)
        self.setLayout(layout)

    def update_data(self, data):
        """Update the table with the provided parameter's data."""
        self.table_widget.setRowCount(len(data))
        for row_index, row_data in enumerate(data):
            for column_index, item in enumerate(row_data):
                self.table_widget.setItem(row_index, column_index, QTableWidgetItem(str(item)))


class OpenPositionDisplayWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Открытые позиции")
        self.setGeometry(1350, 500, 550, 300)

        # Создаем таблицу
        self.table_widget = QTableWidget(self)
        self.table_widget.setColumnCount(5)  # 5 столбцов
        self.table_widget.setHorizontalHeaderLabels(["Позиция", "Нужно купить", "Куплено", "%", "Остановить"])

        # Макет для таблицы
        layout = QVBoxLayout()
        layout.addWidget(self.table_widget)
        self.setLayout(layout)

        self.current_data = []  # Список для хранения текущих данных

    def update_data(self, new_data):
        """Обновление таблицы с новыми данными."""
        # Объединяем новые данные с текущими
        self.current_data.extend(new_data)

        # Обновляем таблицу
        self.table_widget.setRowCount(len(self.current_data))
        for row_index, row_data in enumerate(self.current_data):
            for column_index, item in enumerate(row_data[:-1]):  # Исключаем последнюю ячейку для кнопки
                self.table_widget.setItem(row_index, column_index, QTableWidgetItem(str(item)))

            # Создаем кнопку для последнего столбца
            stop_button = QPushButton("Остановить")
            stop_button.clicked.connect(lambda checked, row=row_index: self.stop_position(row))
            self.table_widget.setCellWidget(row_index, 4, stop_button)  # Устанавливаем кнопку в последний столбец

    def stop_position(self, row):
        """Обработка действия остановки позиции."""
        print(f"Stopping position at row {row}")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = App()
    window.show()
    sys.exit(app.exec_()) 

из за долгого выполнения send_positions_data программа начинает лагать