import math
import time
from pybit.unified_trading import HTTP
from requests import Session

import key

def get_data_check(name, data_source, expiration, strike_price, option_type, session):
try:
if name == "Спот":
result = session.get_tickers(
category="spot",
symbol=f"{data_source}USDC"
).get('result', {}).get('list')[0]


    if name == "Бессрочный USDC":
        result = session.get_tickers(
            category="linear",
            symbol=f"{data_source}USDC"
        ).get('result', {}).get('list')[0]

    if name == "Бессрочный USDT":
        result = session.get_tickers(
            category="linear",
            symbol=f"{data_source}USDT"
        ).get('result', {}).get('list')[0]

    if name == "USDC фьючерсы":
        result = session.get_tickers(
            category="linear",
            symbol=f"{data_source}-{expiration}"
        ).get('result', {}).get('list')[0]

    if name == "USDC опционы":
        if option_type == "Put":
            type = "P"
        elif option_type == "Call":
            type = "C"

        result = session.get_tickers(
            category="options",
            symbol=f"{data_source}-{expiration}-{strike_price}-{type}"
        ).get('result', {}).get('list')[0]
except Exception as e:
    print(e)

offer_price = float(result['ask1Price'])
demand_price = float(result['bid1Price'])
offer_size = float(result['ask1Size'])
demand_size = float(result['bid1Size'])

return offer_price, demand_price, offer_size, demand_size
Функция для округления числа вниз до n знаков после запятой
def round_down(value, decimals):
factor = 10 ** decimals
return math.floor(value * factor) / factor

def post_orders(params, display_window):
# Создаем подключение к API Bybit
session = HTTP(
api_key=key.APIK,
api_secret=key.APISK,
)
first_st_qte = {}
not_repeat = []
repeat_index = []
try:
for index, ticker in enumerate(params):
# Создаем копию ticker, чтобы не изменять оригинал
ticker_copy = ticker.copy()
qte_need = ticker_copy['quantity']
del ticker_copy['quantity']


        if ticker_copy not in not_repeat:
            not_repeat.append(ticker_copy)
        else:
            match_index = not_repeat.index(ticker_copy)
            repeat_index.append(match_index)
            repeat_index.append(index)
            continue

        if ticker_copy['direction'] == 'Купить':
            qte = ticker_copy['offer_size']
        else:
            qte = ticker_copy['demand_size']

        percent_have = qte / qte_need
        qte_need_for_buy = (qte_need - qte) / 10
        if qte_need_for_buy < 0:
            qte_need_for_buy = 0
            percent_have = 1

        buy_size = qte_need_for_buy
        first_st_qte[index] = [qte_need_for_buy, buy_size, percent_have]
except Exception as e:
    print(e)

unique_repeat_index = list(dict.fromkeys(repeat_index))
keys_to_delete = []

for _ in first_st_qte.keys():
    if _ in unique_repeat_index:
        keys_to_delete.append(_)

# Теперь мы можем безопасно удалить ключи
for _ in keys_to_delete:
    del first_st_qte[_]


repeat_pos_one_B = {}
repeat_pos_one_C = {}
repeat_pos_two_B = {}
repeat_pos_two_C = {}
repeat_pos_three_B = {}
repeat_pos_three_C = {}
repeat_pos_four_B = {}
repeat_pos_four_C = {}
repeat_pos_five_B = {}
repeat_pos_five_C = {}

for num in unique_repeat_index:
    if params[num].get('position_name') == 'Бессрочный USDT':
        if params[num].get('direction') == 'Купить':
            repeat_pos_one_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_one_C[num] = params[num]
    if params[num].get('position_name') == 'Бессрочный USDC':
        if params[num].get('direction') == 'Купить':
            repeat_pos_two_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_two_C[num] = params[num]
    if params[num].get('position_name') == 'USDC фьючерсы':
        if params[num].get('direction') == 'Купить':
            repeat_pos_three_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_three_C[num] = params[num]
    if params[num].get('position_name') == 'USDC опционы':
        if params[num].get('direction') == 'Купить':
            repeat_pos_four_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_four_C[num] = params[num]
    if params[num].get('position_name') == 'Спот':
        if params[num].get('direction') == 'Купить':
            repeat_pos_five_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_five_C[num] = params[num]

for repeat_pos in [repeat_pos_one_B, repeat_pos_two_B, repeat_pos_three_B, repeat_pos_four_B, repeat_pos_five_B]:
    if repeat_pos:
        qte_need = 0
        for index in repeat_pos:
            qte = repeat_pos[index]['offer_size']
            qte_need += repeat_pos[index]['quantity']

        percent_have = qte / qte_need
        qte_need_for_buy = (qte_need - qte) / 10

        for index in repeat_pos:
            qte_other = repeat_pos[index]['quantity']
            buy_size = (qte_other - qte_other * percent_have) / 10

            if qte_need_for_buy < 0:
                qte_need_for_buy = 0
                percent_have = 1
                buy_size = 0

            first_st_qte[index] = [qte_need_for_buy, buy_size, percent_have]

for repeat_pos in [repeat_pos_one_C, repeat_pos_two_C, repeat_pos_three_C, repeat_pos_four_C, repeat_pos_five_C]:
    if repeat_pos:
        qte_need = 0
        for index in repeat_pos:
            qte = repeat_pos[index]['demand_size']
            qte_need += repeat_pos[index]['quantity']

        percent_have = qte / qte_need
        qte_need_for_buy = (qte_need - qte) / 10

        for index in repeat_pos:
            qte_other = repeat_pos[index]['quantity']
            buy_size = (qte_other - qte_other * percent_have) / 10

            if qte_need_for_buy < 0:
                qte_need_for_buy = 0
                percent_have = 1
                buy_size = 0

            first_st_qte[index] = [qte_need_for_buy, buy_size, percent_have]

first_st_qte = {keys: first_st_qte[keys] for keys in sorted(first_st_qte)}

# Инициализируем переменные для хранения наименьшего третьего значения и соответствующего ключа
min_percent = float('inf')  # Инициализируем как бесконечность

# Проходим по словарю
for _, value in first_st_qte.items():
    third_value = value[2]  # Берем третье значение массива
    if third_value < min_percent:  # Если текущее значение меньше, чем минимальное
        min_percent = third_value  # Обновляем минимальное значение

second_st_qte = {}
not_repeat = []
repeat_index = []
try:
    for index, ticker in enumerate(params):
        # Создаем копию ticker, чтобы не изменять оригинал
        ticker_copy = ticker.copy()
        qte_need = ticker_copy['quantity']
        del ticker_copy['quantity']

        if ticker_copy not in not_repeat:
            not_repeat.append(ticker_copy)
        else:
            match_index = not_repeat.index(ticker_copy)
            repeat_index.append(match_index)
            repeat_index.append(index)
            continue

        first_buy = qte_need * min_percent
        qte_need_for_buy = (qte_need - first_buy) / 10

        buy_size = qte_need_for_buy
        second_st_qte[index] = [qte_need_for_buy, buy_size, first_buy]
except Exception as e:
    print(e)

unique_repeat_index = list(dict.fromkeys(repeat_index))
keys_to_delete = []

for _ in second_st_qte.keys():
    if _ in unique_repeat_index:
        keys_to_delete.append(_)

# Теперь мы можем безопасно удалить ключи
for _ in keys_to_delete:
    del second_st_qte[_]

repeat_pos_one_B = {}
repeat_pos_one_C = {}
repeat_pos_two_B = {}
repeat_pos_two_C = {}
repeat_pos_three_B = {}
repeat_pos_three_C = {}
repeat_pos_four_B = {}
repeat_pos_four_C = {}
repeat_pos_five_B = {}
repeat_pos_five_C = {}

for num in unique_repeat_index:
    if params[num].get('position_name') == 'Бессрочный USDT':
        if params[num].get('direction') == 'Купить':
            repeat_pos_one_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_one_C[num] = params[num]
    if params[num].get('position_name') == 'Бессрочный USDC':
        if params[num].get('direction') == 'Купить':
            repeat_pos_two_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_two_C[num] = params[num]
    if params[num].get('position_name') == 'USDC фьючерсы':
        if params[num].get('direction') == 'Купить':
            repeat_pos_three_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_three_C[num] = params[num]
    if params[num].get('position_name') == 'USDC опционы':
        if params[num].get('direction') == 'Купить':
            repeat_pos_four_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_four_C[num] = params[num]
    if params[num].get('position_name') == 'Спот':
        if params[num].get('direction') == 'Купить':
            repeat_pos_five_B[num] = params[num]
        if params[num].get('direction') == 'Продать':
            repeat_pos_five_C[num] = params[num]

for repeat_pos in [repeat_pos_one_B, repeat_pos_two_B, repeat_pos_three_B, repeat_pos_four_B, repeat_pos_five_B]:
    if repeat_pos:
        qte_first_buy = 0
        qte_all_need = 0
        for index in repeat_pos:
            qte = repeat_pos[index]['quantity']
            qte_all_need += qte
            first_buy = qte * min_percent
            qte_first_buy += first_buy

        qte_need_for_buy = (qte_all_need - qte_first_buy) / 10

        for index in repeat_pos:
            qte = repeat_pos[index]['quantity']
            first_buy = qte * min_percent
            buy_size = (qte - first_buy) / 10

            second_st_qte[index] = [qte_need_for_buy, buy_size, first_buy]

for repeat_pos in [repeat_pos_one_C, repeat_pos_two_C, repeat_pos_three_C, repeat_pos_four_C, repeat_pos_five_C]:
    if repeat_pos:
        qte_first_buy = 0
        qte_all_need = 0
        for index in repeat_pos:
            qte = repeat_pos[index]['quantity']
            qte_all_need += qte
            first_buy = qte * min_percent
            qte_first_buy += first_buy

        qte_need_for_buy = (qte_all_need - qte_first_buy) / 10

        for index in repeat_pos:
            qte = repeat_pos[index]['quantity']
            first_buy = qte * min_percent
            buy_size = (qte - first_buy) / 10

            second_st_qte[index] = [qte_need_for_buy, buy_size, first_buy]

second_st_qte = {keys: second_st_qte[keys] for keys in sorted(second_st_qte)}

for keys, value in second_st_qte.items():
    second_st_qte[keys] = [round_down(v, 3) for v in value]

data_display = []
buyAll = False

approwed = 0
while approwed != len(second_st_qte):
    approwed = 0
    for _, value in second_st_qte.items():
        check = params[_]

        offer_price, demand_price, offer_size, demand_size\
            = get_data_check(check['position_name'], check['data_source'], check['expiration'], check['strike_price'], check['option_type'], session)

        if check['direction'] == 'Купить':
            if check['order_price'] >= offer_price:
                approwed += 1
        if check['direction'] == 'Продать':
            if check['order_price'] <= demand_price:
                approwed += 1


for keys, values in second_st_qte.items():
    ticker = params[keys]
    qte = values[2]

    if qte == ticker['quantity']:
        buyAll = True

    try:
        if ticker.get("position_name") == "Спот":
            # Параметры ордера
            try:
                if ticker['option_type'] == 'Call':
                    type = 'C'
                elif ticker['option_type'] == 'Put':
                    type = 'P'
                if ticker['direction'] == 'Купить':
                    direction = 'Buy'
                if ticker['direction'] == 'Продать':
                    direction = 'Sell'

                order_params = {
                    "category": "spot",
                    "isLeverage": ticker['leverage'],
                    "symbol": f"{ticker['data_source']}USDC",
                    "side": direction,
                    "orderType": "Limit",
                    "qty": qte,
                    "price": ticker['order_price'],
                    "timeInForce": "GTC",
                    "orderLinkId": f"{time.time()}"
                }

                print(session.place_order(**order_params))
            except Exception as e:
                print(e)

        if ticker.get("position_name") == "USDC опционы":
            # Параметры ордера
            try:
                if ticker['option_type'] == 'Call':
                    type = 'C'
                elif ticker['option_type'] == 'Put':
                    type = 'P'
                if ticker['direction'] == 'Купить':
                    direction = 'Buy'
                if ticker['direction'] == 'Продать':
                    direction = 'Sell'

                order_params = {
                    "category": "option",
                    "symbol": f"{ticker['data_source']}-{ticker['expiration']}-{ticker['strike_price']}-{type}",
                    "side": direction,
                    "orderType": "Limit",
                    "qty": qte,
                    "price": ticker['order_price'],
                    "timeInForce": "GTC",
                    "orderLinkId": f"{time.time()}"
                }

                print(session.place_order(**order_params))
            except Exception as e:
                print(e)

        if ticker.get("position_name") == "USDC фьючерсы":
            # Параметры ордера
            try:
                if ticker['direction'] == 'Купить':
                    direction = 'Buy'
                if ticker['direction'] == 'Продать':
                    direction = 'Sell'

                order_params = {
                    "category": "linear",
                    "isLeverage": ticker['leverage'],
                    "symbol": f"{ticker['data_source']}-{ticker['expiration']}",
                    "side": direction,
                    "orderType": "Limit",
                    "qty": qte,
                    "price": ticker['order_price'],
                    "timeInForce": "GTC",
                    "orderLinkId": f"{time.time()}"
                }

                print(session.place_order(**order_params))
            except Exception as e:
                print(e)

        if ticker.get("position_name") == "Бессрочный USDC":
            # Параметры ордера
            try:
                if ticker['direction'] == 'Купить':
                    direction = 'Buy'
                if ticker['direction'] == 'Продать':
                    direction = 'Sell'

                order_params = {
                    "category": "linear",
                    "isLeverage": ticker['leverage'],
                    "symbol": f"{ticker['data_source']}PERP",
                    "side": direction,
                    "orderType": "Limit",
                    "qty": qte,
                    "price": ticker['order_price'],
                    "timeInForce": "GTC",
                    "orderLinkId": f"{time.time()}"
                }

                print(session.place_order(**order_params))
            except Exception as e:
                print(e)

        if ticker.get("position_name") == "Бессрочный USDT":
            # Параметры ордера
            try:
                if ticker['direction'] == 'Купить':
                    direction = 'Buy'
                if ticker['direction'] == 'Продать':
                    direction = 'Sell'

                order_params = {
                    "category": "linear",
                    "isLeverage": ticker['leverage'],
                    "symbol": f"{ticker['data_source']}USDT",
                    "side": direction,
                    "orderType": "Limit",
                    "qty": qte,
                    "price": ticker['order_price'],
                    "timeInForce": "GTC",
                    "orderLinkId": f"{time.time()}"
                }

                # print(session.place_order(**order_params))
            except Exception as e:
                print(e)

        data_display.append([
            ticker['position_name'],
            ticker['quantity'],
            qte,
            qte / ticker['quantity'] * 100,
            ])
    except Exception:
        return 0

display_window.update_data(data_display)

if buyAll == True:
    return 0

for i in range(10):
    data_display = []
    approwed = 0
    approwed_qte = 0

    while approwed != len(second_st_qte) and approwed_qte !=len(second_st_qte):
        approwed = 0
        approwed_qte = 0
        for _, value in second_st_qte.items():
            check = params[_]
            offer_price, demand_price, offer_size, demand_size \
                = get_data_check(check['position_name'], check['data_source'], check['expiration'],
                                 check['strike_price'], check['option_type'], session)

            if check['direction'] == 'Купить':
                if check['order_price'] >= offer_price:
                    approwed += 1
            if check['direction'] == 'Продать':
                if check['order_price'] <= demand_price:
                    approwed += 1

            if check['direction'] == 'Купить':
                if value[0] >= offer_size:
                    approwed_qte += 1
            if check['direction'] == 'Купить':
                if value[0] >= demand_size:
                    approwed_qte += 1

    for keys, values in second_st_qte.items():
        ticker = params[keys]
        qte = values[1]

        try:
            if ticker.get("position_name") == "Спот":
                # Параметры ордера
                try:
                    if ticker['option_type'] == 'Call':
                        type = 'C'
                    elif ticker['option_type'] == 'Put':
                        type = 'P'
                    if ticker['direction'] == 'Купить':
                        direction = 'Buy'
                    if ticker['direction'] == 'Продать':
                        direction = 'Sell'

                    order_params = {
                        "category": "spot",
                        "isLeverage": ticker['leverage'],
                        "symbol": f"{ticker['data_source']}USDC",
                        "side": direction,
                        "orderType": "Limit",
                        "qty": qte,
                        "price": ticker['order_price'],
                        "timeInForce": "GTC",
                        "orderLinkId": f"{time.time()}"
                    }

                    print(session.place_order(**order_params))
                except Exception as e:
                    print(e)

            if ticker.get("position_name") == "USDC опционы":
                # Параметры ордера
                try:
                    if ticker['option_type'] == 'Call':
                        type = 'C'
                    elif ticker['option_type'] == 'Put':
                        type = 'P'
                    if ticker['direction'] == 'Купить':
                        direction = 'Buy'
                    if ticker['direction'] == 'Продать':
                        direction = 'Sell'

                    order_params = {
                        "category": "option",
                        "symbol": f"{ticker['data_source']}-{ticker['expiration']}-{ticker['strike_price']}-{type}",
                        "side": direction,
                        "orderType": "Limit",
                        "qty": qte,
                        "price": ticker['order_price'],
                        "timeInForce": "GTC",
                        "orderLinkId": f"{time.time()}"
                    }

                    print(session.place_order(**order_params))
                except Exception as e:
                    print(e)

            if ticker.get("position_name") == "USDC фьючерсы":
                # Параметры ордера
                try:
                    if ticker['direction'] == 'Купить':
                        direction = 'Buy'
                    if ticker['direction'] == 'Продать':
                        direction = 'Sell'

                    order_params = {
                        "category": "linear",
                        "isLeverage": ticker['leverage'],
                        "symbol": f"{ticker['data_source']}-{ticker['expiration']}",
                        "side": direction,
                        "orderType": "Limit",
                        "qty": qte,
                        "price": ticker['order_price'],
                        "timeInForce": "GTC",
                        "orderLinkId": f"{time.time()}"
                    }

                    print(session.place_order(**order_params))
                except Exception as e:
                    print(e)

            if ticker.get("position_name") == "Бессрочный USDC":
                # Параметры ордера
                try:
                    if ticker['direction'] == 'Купить':
                        direction = 'Buy'
                    if ticker['direction'] == 'Продать':
                        direction = 'Sell'

                    order_params = {
                        "category": "linear",
                        "isLeverage": ticker['leverage'],
                        "symbol": f"{ticker['data_source']}PERP",
                        "side": direction,
                        "orderType": "Limit",
                        "qty": qte,
                        "price": ticker['order_price'],
                        "timeInForce": "GTC",
                        "orderLinkId": f"{time.time()}"
                    }

                    print(session.place_order(**order_params))
                except Exception as e:
                    print(e)

            if ticker.get("position_name") == "Бессрочный USDT":
                # Параметры ордера
                try:
                    if ticker['direction'] == 'Купить':
                        direction = 'Buy'
                    if ticker['direction'] == 'Продать':
                        direction = 'Sell'

                    order_params = {
                        "category": "linear",
                        "isLeverage": ticker['leverage'],
                        "symbol": f"{ticker['data_source']}USDT",
                        "side": direction,
                        "orderType": "Limit",
                        "qty": qte,
                        "price": ticker['order_price'],
                        "timeInForce": "GTC",
                        "orderLinkId": f"{time.time()}"
                    }

                    # print(session.place_order(**order_params))
                except Exception as e:
                    print(e)

            data_display.append([
                ticker['position_name'],
                ticker['quantity'],
                qte,
                qte / ticker['quantity'] * 100,
            ])

        except Exception:
            return 0

    display_window.update_data(data_display)
if name == "main":
session = HTTP(
api_key=key.APIK,
api_secret=key.APISK,
)
check = {'position_name': 'Бессрочный USDT', 'leverage': 10, 'expiration': '1 неделя', 'strike_price': 100, 'option_type': 'Call', 'direction': 'Купить', 'demand_size': 25.586, 'demand_price': 96940.6, 'order_price': 96940.7, 'quantity': 0.1, 'offer_size': 0.757, 'offer_price': 96940.7, 'data_source': 'BTC'}
offer_price, demand_price, offer_size, demand_size
= get_data_check(check['position_name'], check['data_source'], check['expiration'], check['strike_price'],
check['option_type'], session)


print(type(offer_price), type(demand_price), type(offer_size), type(demand_size)) 
POST выглядит так
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_())
UI выглядит так зная всё это дай ответ как мне исправить программу что бы интерфейс не лагагл