Ошибка обработки данных json по формуле и внесение данных в таблицу QTabWidget

Я написал код для взаимодействия с данными цены монет на Binance, на вход программа получает файл .json, со стоимостью всех монет.
После чего загружает эти данные во вторую таблицу.

Пользователь должен ввести формулу в lineEdit и во второй таблице должна появится формула и ее результат, но почему-то код выдает ошибку даже на корректную формулу.
Как это исправить?

BinanceTracker.py:

from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtWidgets import QTableWidgetItem, QMessageBox
from data_loader import load_data_to_table  # Import the data loader


class Ui_BinanceTracker(object):
    def setupUi(self, BinanceTracker):
        BinanceTracker.setObjectName("BinanceTracker")
        BinanceTracker.resize(640, 480)
        BinanceTracker.setStyleSheet("QPushButton {\n"
                                      "    height: 50px; \n"
                                      "    width: 120px;\n"
                                      "    font: 9pt \"Segoe UI\";\n"
                                      "}\n"
                                      "QLineEdit {\n"
                                      "    height: 50px; \n"
                                      "    width: 120px; \n"
                                      "    font: 9pt \"Segoe UI\";\n"
                                      "}\n"
                                      "")
        self.centralwidget = QtWidgets.QWidget(parent=BinanceTracker)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.tabWidget = QtWidgets.QTabWidget(parent=self.centralwidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.tab)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.tableWidget = QtWidgets.QTableWidget(parent=self.tab)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setHorizontalHeaderLabels(["Формула", "Результат"])
        self.tableWidget.setRowCount(0)
        self.gridLayout_2.addWidget(self.tableWidget, 0, 0, 1, 2)
        self.groupBox = QtWidgets.QGroupBox(parent=self.tab)
        self.groupBox.setObjectName("groupBox")
        self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox)
        self.gridLayout_4.setObjectName("gridLayout_4")
        self.lineEdit = QtWidgets.QLineEdit(parent=self.groupBox)
        self.lineEdit.setObjectName("lineEdit")
        self.gridLayout_4.addWidget(self.lineEdit, 0, 0, 1, 1)
        self.pushButton = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout_4.addWidget(self.pushButton, 0, 1, 1, 1)
        self.pushButton_3 = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButton_3.setObjectName("pushButton_3")
        self.gridLayout_4.addWidget(self.pushButton_3, 0, 2, 1, 1)
        self.gridLayout_2.addWidget(self.groupBox, 1, 0, 1, 2)
        self.groupBox_2 = QtWidgets.QGroupBox(parent=self.tab)
        self.groupBox_2.setObjectName("groupBox_2")
        self.gridLayout_5 = QtWidgets.QGridLayout(self.groupBox_2)
        self.gridLayout_5.setObjectName("gridLayout_5")
        self.lineEdit_2 = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.gridLayout_5.addWidget(self.lineEdit_2, 0, 0, 1, 1)
        self.lineEdit_3 = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.gridLayout_5.addWidget(self.lineEdit_3, 0, 1, 1, 1)
        self.pushButton_2 = QtWidgets.QPushButton(parent=self.groupBox_2)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout_5.addWidget(self.pushButton_2, 0, 2, 1, 1)
        self.gridLayout_2.addWidget(self.groupBox_2, 2, 0, 1, 2)
        self.tabWidget.addTab(self.tab, "")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_2)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.tableWidget_2 = QtWidgets.QTableWidget(parent=self.tab_2)
        self.tableWidget_2.setObjectName("tableWidget_2")
        self.tableWidget_2.setColumnCount(2)
        self.tableWidget_2.setHorizontalHeaderLabels(["Пара", "Цена"])
        self.tableWidget_2.setRowCount(0)
        self.gridLayout_3.addWidget(self.tableWidget_2, 0, 0, 1, 1)
        self.tabWidget.addTab(self.tab_2, "")
        self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
        BinanceTracker.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(parent=BinanceTracker)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 22))
        self.menubar.setObjectName("menubar")
        BinanceTracker.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(parent=BinanceTracker)
        self.statusbar.setObjectName("statusbar")
        BinanceTracker.setStatusBar(self.statusbar)

        self.retranslateUi(BinanceTracker)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(BinanceTracker)

        # Load data into tableWidget_2
        num_pairs_per_row = 6  # Change this to the desired number of pairs per row
        load_data_to_table(self.tableWidget_2, 'price.json', num_pairs_per_row)

        # Connect the pushButton to a function that will handle the formula
        self.pushButton.clicked.connect(self.calculate_formula)

    def calculate_formula(self):
        # Получаем формулу из lineEdit
        formula = self.lineEdit.text().strip()

        # Разделяем формулу на части (например, ETHBTC*BNBBTC -> ['ETHBTC', 'BNBBTC'])
        parts = formula.replace(' ', '').split('+')  # Сначала разбиваем по '+'

        # Инициализируем результат
        result = 0.0
        valid_formula = True

        # Вычисляем результат
        for part in parts:
            sub_parts = part.split('-')  # Разбиваем по '-'
            sub_result = 0.0
            for sub_part in sub_parts:
                if '*' in sub_part or '/' in sub_part:  # Если есть умножение или деление
                    # Разбиваем по '*' и '/'
                    factors = []
                    for factor in sub_part.replace('-', ' -').replace('+', ' +').split():
                        if factor:  # Проверяем, что не пустая строка
                            factors.append(factor)
                    # Вычисляем результат для текущей подчасти
                    try:
                        sub_result = eval('*'.join(factors))  # Используем eval для вычисления
                    except Exception as e:
                        valid_formula = False
                        break
                else:
                    # Если это просто монета, ищем ее цену
                    found = False
                    for row_index in range(self.tableWidget_2.rowCount()):
                        for col_index in range(0, self.tableWidget_2.columnCount(), 2):
                            if self.tableWidget_2.item(row_index, col_index) and self.tableWidget_2.item(row_index,
                                                                                                         col_index).text() == sub_part:
                                price_item = self.tableWidget_2.item(row_index, col_index + 1)
                                if price_item:
                                    sub_result += float(price_item.text())
                                    found = True
                                break
                    if not found:
                        valid_formula = False
                        break

            result += sub_result

        # Если формула корректна, добавляем результат в tableWidget
        if valid_formula:
            current_row_count = self.tableWidget.rowCount()
            self.tableWidget.setRowCount(current_row_count + 1)  # Увеличиваем количество строк

            # Заполняем строку формулой и результатом
            self.tableWidget.setItem(current_row_count, 0, QTableWidgetItem(formula))  # Добавляем формулу
            self.tableWidget.setItem(current_row_count, 1, QTableWidgetItem(str(result)))  # Добавляем результат
        else:
            # Показываем сообщение об ошибке, если формула некорректна
            QMessageBox.warning(self.centralwidget, "Ошибка", "Некорректная формула или монета не найдена.")

    def retranslateUi(self, BinanceTracker):
        _translate = QtCore.QCoreApplication.translate
        BinanceTracker.setWindowTitle(_translate("BinanceTracker", "BinanceTracker V1"))
        self.groupBox.setTitle(_translate("BinanceTracker", "Операции"))
        self.pushButton.setText(_translate("BinanceTracker", "Добавить операцию"))
        self.lineEdit.setPlaceholderText(_translate("BinanceTracker", "Добавьте отслеживаемую функцию, например: ETHBTC*BNBBTC"))
        self.pushButton_3.setText(_translate("BinanceTracker", "Удалить операцию"))
        self.groupBox_2.setTitle(_translate("BinanceTracker", "Настройки трекера"))
        self.lineEdit_2.setPlaceholderText(_translate("BinanceTracker", "Минимальное значение:"))
        self.lineEdit_3.setPlaceholderText(_translate("BinanceTracker", "Максимальное значение:"))
        self.pushButton_2.setText(_translate("BinanceTracker", "Сохранить значения"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("BinanceTracker", "Отслеживаемые монеты"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("BinanceTracker", "Полный список монет"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    BinanceTracker = QtWidgets.QMainWindow()
    ui = Ui_BinanceTracker()
    ui.setupUi(BinanceTracker)
    BinanceTracker.show()
    sys.exit(app.exec())

data_loader.py:

import json
from PyQt6.QtWidgets import QTableWidgetItem


def load_data_to_table(table_widget, json_file_path, num_pairs_per_row):
    with open(json_file_path, 'r') as file:
        data = json.load(file)


    num_columns = num_pairs_per_row * 2
    table_widget.setColumnCount(num_columns)

    # Set horizontal header labels
    headers = []
    for i in range(num_pairs_per_row):
        headers.append(f"Монета {i + 1}")
        headers.append(f"Цена {i + 1}")
    table_widget.setHorizontalHeaderLabels(headers)

    num_rows = -(-len(data) // num_pairs_per_row)

    table_widget.setRowCount(num_rows)

    for index, item in enumerate(data):
        row_index = index // num_pairs_per_row
        col_index = (index % num_pairs_per_row) * 2
        table_widget.setItem(row_index, col_index, QTableWidgetItem(item['symbol']))  # Symbol
        table_widget.setItem(row_index, col_index + 1, QTableWidgetItem(item['price']))  # Price

Файл с тестовыми данными: https://drive.google.com/file/d/15Jb82HgrRUalP-YyVQpx_x2TRO_fsbZA/view?usp=sharing


Ответы (1 шт):

Автор решения: S. Nick

Основная ошибка при обработке функции: ETHBTC * BNBBTC, возникает с строке

        # !!! ТУТ ОШИБКА  vvvvvvvvvvvvvvvv 
        sub_result = eval('*'.join(factors))

т.к. factors содержит названия переменных, которые не имеют значений.

введите сюда описание изображения


Вы не написали какова логика и порядок обработки вводимых функций.
Я попробовал что-то сделать для вас, чтобы НЕКОТОРЫЕ введенные функции обрабатывались, но вам еще есть над чем потрудиться.

Я внес некоторые дополнения и изменения в ваш код и прокомментировал их.

НИКОГДА НЕ ИЗМЕНЯЙТЕ код, сгенерированный Qt Designer, НИКОГДА.
Создайте другой класс, который наследуется от соответствующего виджета, и используйте созданный класс для его заполнения.

main.py:

import json
'''
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtWidgets import QTableWidgetItem, QMessageBox
'''
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QTableWidgetItem, QMessageBox

#from data_loader import load_data_to_table    # Import the data loader
def load_data_to_table(table_widget, json_file_path, num_pairs_per_row):
    with open(json_file_path, 'r') as file:
        data = json.load(file)

    num_columns = num_pairs_per_row * 2
    table_widget.setColumnCount(num_columns)

    # Set horizontal header labels
    headers = []
    for i in range(num_pairs_per_row):
        headers.append(f"Монета {i + 1}")
        headers.append(f"Цена {i + 1}")
    table_widget.setHorizontalHeaderLabels(headers)

    num_rows = -(-len(data) // num_pairs_per_row)
    print(f'num_rows: {num_rows}; num_columns: {num_columns};\n')
    table_widget.setRowCount(num_rows)

    for index, item in enumerate(data):
        row_index = index // num_pairs_per_row
        col_index = (index % num_pairs_per_row) * 2
        table_widget.setItem(row_index, col_index, 
            QTableWidgetItem(item['symbol']))                # Symbol
        table_widget.setItem(row_index, col_index + 1, 
            QTableWidgetItem(item['price']))                 # Price
        

class Ui_BinanceTracker(object):
    def setupUi(self, BinanceTracker):
        BinanceTracker.setObjectName("BinanceTracker")
        BinanceTracker.resize(840, 480)
        BinanceTracker.setStyleSheet("QPushButton {\n"
                                      "    height: 50px; \n"
                                      "    width: 120px;\n"
                                      "    font: 9pt \"Segoe UI\";\n"
                                      "}\n"
                                      "QLineEdit {\n"
                                      "    height: 50px; \n"
                                      "    width: 120px; \n"
                                      "    font: 14pt \"Segoe UI\";\n"
                                      "}\n"
                                      
                                      "#tableWidget {\n"
                                      "    font: 14pt \"Segoe UI\";\n"
                                      "}\n"
                                      "")
        self.centralwidget = QtWidgets.QWidget(parent=BinanceTracker)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        self.tabWidget = QtWidgets.QTabWidget(parent=self.centralwidget)
        self.tabWidget.setObjectName("tabWidget")
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName("tab")
        self.gridLayout_2 = QtWidgets.QGridLayout(self.tab)
        self.gridLayout_2.setObjectName("gridLayout_2")
        self.tableWidget = QtWidgets.QTableWidget(parent=self.tab)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setHorizontalHeaderLabels(
            ["Формула", "Результат"])
        self.tableWidget.setRowCount(0)
        self.gridLayout_2.addWidget(self.tableWidget, 0, 0, 1, 2)
        self.groupBox = QtWidgets.QGroupBox(parent=self.tab)
        self.groupBox.setObjectName("groupBox")
        self.gridLayout_4 = QtWidgets.QGridLayout(self.groupBox)
        self.gridLayout_4.setObjectName("gridLayout_4")
        self.lineEdit = QtWidgets.QLineEdit(parent=self.groupBox)
        self.lineEdit.setObjectName("lineEdit")
        self.gridLayout_4.addWidget(self.lineEdit, 0, 0, 1, 1)
        self.pushButton = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButton.setObjectName("pushButton")
        self.gridLayout_4.addWidget(self.pushButton, 0, 1, 1, 1)
        self.pushButton_3 = QtWidgets.QPushButton(parent=self.groupBox)
        self.pushButton_3.setObjectName("pushButton_3")
        self.gridLayout_4.addWidget(self.pushButton_3, 0, 2, 1, 1)
        self.gridLayout_2.addWidget(self.groupBox, 1, 0, 1, 2)
        self.groupBox_2 = QtWidgets.QGroupBox(parent=self.tab)
        self.groupBox_2.setObjectName("groupBox_2")
        self.gridLayout_5 = QtWidgets.QGridLayout(self.groupBox_2)
        self.gridLayout_5.setObjectName("gridLayout_5")
        self.lineEdit_2 = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.gridLayout_5.addWidget(self.lineEdit_2, 0, 0, 1, 1)
        self.lineEdit_3 = QtWidgets.QLineEdit(parent=self.groupBox_2)
        self.lineEdit_3.setObjectName("lineEdit_3")
        self.gridLayout_5.addWidget(self.lineEdit_3, 0, 1, 1, 1)
        self.pushButton_2 = QtWidgets.QPushButton(parent=self.groupBox_2)
        self.pushButton_2.setObjectName("pushButton_2")
        self.gridLayout_5.addWidget(self.pushButton_2, 0, 2, 1, 1)
        self.gridLayout_2.addWidget(self.groupBox_2, 2, 0, 1, 2)
        self.tabWidget.addTab(self.tab, "")
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName("tab_2")
        self.gridLayout_3 = QtWidgets.QGridLayout(self.tab_2)
        self.gridLayout_3.setObjectName("gridLayout_3")
        self.tableWidget_2 = QtWidgets.QTableWidget(parent=self.tab_2)
        self.tableWidget_2.setObjectName("tableWidget_2")
        self.tableWidget_2.setColumnCount(2)
        self.tableWidget_2.setHorizontalHeaderLabels(["Пара", "Цена"])
        self.tableWidget_2.setRowCount(0)
        self.gridLayout_3.addWidget(self.tableWidget_2, 0, 0, 1, 1)
        self.tabWidget.addTab(self.tab_2, "")
        self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
        BinanceTracker.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(parent=BinanceTracker)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 22))
        self.menubar.setObjectName("menubar")
        BinanceTracker.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(parent=BinanceTracker)
        self.statusbar.setObjectName("statusbar")
        BinanceTracker.setStatusBar(self.statusbar)

        self.retranslateUi(BinanceTracker)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(BinanceTracker)

    def retranslateUi(self, BinanceTracker):
        _translate = QtCore.QCoreApplication.translate
        BinanceTracker.setWindowTitle(_translate("BinanceTracker", "BinanceTracker V1"))
        self.groupBox.setTitle(_translate("BinanceTracker", "Операции"))
        self.pushButton.setText(_translate("BinanceTracker", "Добавить операцию"))
        self.lineEdit.setPlaceholderText(_translate(
            "BinanceTracker", 
            "Добавьте функцию, например: ETHBTC*BNBBTC"))
        self.pushButton_3.setText(_translate("BinanceTracker", "Удалить операцию"))
        self.groupBox_2.setTitle(_translate("BinanceTracker", "Настройки трекера"))
        self.lineEdit_2.setPlaceholderText(_translate("BinanceTracker", "Минимальное значение:"))
        self.lineEdit_3.setPlaceholderText(_translate("BinanceTracker", "Максимальное значение:"))
        self.pushButton_2.setText(_translate("BinanceTracker", "Сохранить значения"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("BinanceTracker", "Отслеживаемые монеты"))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("BinanceTracker", "Полный список монет"))


class MainWindow(QtWidgets.QMainWindow, Ui_BinanceTracker):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        
        self.tableWidget.horizontalHeader().setSectionResizeMode(  # +
            QtWidgets.QHeaderView.Stretch)
        self.tableWidget.setAlternatingRowColors(True)             # + 
                

        # Load data into tableWidget_2
        # Change this to the desired number of pairs per row
        num_pairs_per_row = 6  
        load_data_to_table(
            self.tableWidget_2, 
            'price.json', 
            num_pairs_per_row
        )

        # Connect the pushButton to function formula
        self.pushButton.clicked.connect(self.calculate_formula)

    def calculate_formula(self):
        # Получаем формулу из lineEdit
        formula = self.lineEdit.text().strip()
        
# +++ vvv
        if not formula:
            QMessageBox.warning(
                self, 
                "Ошибка", 
                "Напишите функцию в lineEdit.")
            return
# +++ ^^^
        # Разделяем формулу на части 
        # (например, ETHBTC*BNBBTC -> ['ETHBTC', 'BNBBTC'])
        # Сначала разбиваем по '+'
        parts = formula.replace(' ', '').split('+')  
        print(f'111 formula: {formula}; parts: {parts};\n') #
        
        # Инициализируем результат
        result = 0.0
        valid_formula = True

        # Вычисляем результат
        for part in parts:
            sub_parts = part.split('-')            # Разбиваем по '-' ???
            sub_result = 0.0
            print(f'\n222 part={part}; sub_parts={sub_parts};')
            for sub_part in sub_parts:
                print(f"\t333 1 sub_part={sub_part};") #
# Если есть умножение или деление
                if '*' in sub_part or '/' in sub_part:  
                    print(f"\t333 2 sub_part={sub_part}; --> if '*' in sub_part or '/' in sub_part: ") #
                    factors = []

                    # Разбиваем по '*' и '/'
# ???                                                v    vv
#                    for factor in sub_part.replace('-', ' -').\
#                        replace('+', ' +').split():
# ???                             ^    ^^
# +++ vvv                                               v?v
                    for factor in sub_part.replace('*', ' ').\
                        replace('/', ' ').split():
# +++ ^^^                            ^?^
                        print(f'\t444 factor={factor}\n') # 
                        if factor:    # Проверяем, что не пустая строка
                            factors.append(factor)
                    print(f'\t555 factors={factors} \n') #  
                    # Вычисляем результат для текущей подчасти
                    try:
# Используем eval для вычисления  ETHBTC*LTCBTC
# !!! +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
                        _factors = self.looking_for_price(
                            factors, sub_result, result)
                        print(f"\n666 1 _factors={_factors}\n") #
                        print(f"666 2 _factors={'*'.join([str(_factors[0]), str(_factors[1])])}\n") # 
   
                        sub_result = eval(
                            '*'.join(
                                [str(_factors[0]), 
                                 str(_factors[1])]
                             ))
# !!! +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

                        print(f"777 eval={'*'.join(factors)}\n") # 
# !!! ТУТ ОШИБКА                          vvvvvvvvvvvvvvvv                        
#                       sub_result = eval('*'.join(factors))
# !!! этот принт не выводится, если  eval('*'.join(factors))                     
                        print(f"888 sub_result={sub_result}\n") # 
                        
                    except Exception as e:
                        valid_formula = False
                        print(f"999 sub_result={sub_result}\n") #
                        break
                else:
# Если это просто монета, ищем ее цену
                    found = False
                    
                    for row in range(self.tableWidget_2.rowCount()):
                        for col in range(0, self.tableWidget_2.columnCount(), 2):

# !!! +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
                            item = self.tableWidget_2.item(row, col)
                            
                            if item and item.text() == sub_part:
                                price_item = self.tableWidget_2.item(
                                    row, col + 1)
                                print(f'\t{price_item.text()};') #
                                if price_item:
                                    sub_result += float(price_item.text())
                                    found = True
                                break
# +++
                            print(f'{found}\n') # 
                        if found:
                            break

                    if not found:
                        valid_formula = False
                        break
# !!! +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

            result += sub_result

        # Если формула корректна, добавляем результат
        if valid_formula:
            current_row_count = self.tableWidget.rowCount()
            self.tableWidget.setRowCount(current_row_count + 1)  

            # Заполняем строку формулой и результатом
            self.tableWidget.setItem(current_row_count, 0, 
                QTableWidgetItem(formula))  
            self.tableWidget.setItem(current_row_count, 1, 
#-                QTableWidgetItem(str(result)))
# !!! +++  
                QTableWidgetItem(f'{result:>12.8f}'))            # +++                 

        else:
            # Показываем сообщение об ошибке
            QMessageBox.warning(self.centralwidget, 
                "Ошибка", 
                "Некорректная формула или монета не найдена.")

# !!! +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
# Если это просто монета, ищем ее цену
    def looking_for_price(self, factors, sub_result, result):
        _factors = []
        
        for factor in factors:
            print(f'factor={factor}') # 
        
            for row in range(self.tableWidget_2.rowCount()):
                for col in range(0, self.tableWidget_2.columnCount(), 2):
                    item = self.tableWidget_2.item(row, col)
                    if item and item.text() == factor:
                        price_item = self.tableWidget_2.item(row, col + 1)
                        print(f'\t{price_item.text()};') #
                        if price_item:
                            sub_result += float(price_item.text())
                            _factors.append(float(price_item.text()))
                            found = True
                        break

# +++
                    print(f'{found}\n') # 
                if found:
                    break

        if not found:
            valid_formula = False
#            break

        result *= sub_result        
        print(f'{result} += {sub_result}==={_factors}===') # 
        return _factors
# !!! +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        
        

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    '''
    BinanceTracker = QtWidgets.QMainWindow()
    ui = Ui_BinanceTracker()
    ui.setupUi(BinanceTracker)
    BinanceTracker.show()
    '''
    w = MainWindow()
    w.show()
    sys.exit(app.exec())

price.json:

[
  {"symbol":"ETHBTC","price":"0.02158000"},
  {"symbol":"LTCBTC","price":"0.00099700"},
  {"symbol":"BNBBTC","price":"0.00717100"},
  {"symbol":"NEOBTC","price":"0.00005690"},
  {"symbol":"QTUMETH","price":"0.00105100"},
  {"symbol":"EOSETH","price":"0.00043200"},
  {"symbol":"SNTETH","price":"0.00001210"},
  {"symbol":"BNTETH","price":"0.00020260"},
  {"symbol":"BCCBTC","price":"0.00000000"},
  {"symbol":"GASBTC","price":"0.00002460"},
  {"symbol":"BNBETH","price":"0.33230000"},
  {"symbol":"BTCUSDT","price":"82388.00000000"},
  {"symbol":"ETHUSDT","price":"1778.46000000"},
  {"symbol":"HSRBTC","price":"0.00000000"},
  {"symbol":"OAXETH","price":"0.00000000"},
  {"symbol":"DNTETH","price":"0.00000000"},
  {"symbol":"MCOETH","price":"0.00000000"},
  {"symbol":"ICNETH","price":"0.00000000"},
  {"symbol":"MCOBTC","price":"0.00000000"},
  {"symbol":"WTCBTC","price":"0.00000024"},
  {"symbol":"WTCETH","price":"0.00000000"},
  {"symbol":"LRCBTC","price":"0.00000114"},
  {"symbol":"LRCETH","price":"0.00005281"},
  {"symbol":"QTUMBTC","price":"0.00002255"}
]

введите сюда описание изображения

введите сюда описание изображения

введите сюда описание изображения

введите сюда описание изображения

→ Ссылка