Извините за задержки с решением. Давайте посмотрим, почему вычисленное количество единиц становится 0.0 и что можно сделать, чтобы это исправить.

### Анализ проблемы:

1. Причина:
- amount_units становится 0.0, если результатами расчетов значения cost / current_price дают число, которое округляется до 0 с текущей точностью.

2. Минимальный объем:
- Минимальный объем (min_volume) для торговли может быть очень маленьким, например 1e-06. Нужно убедиться, что количество вычисленных единиц больше этого значения.

### Решения:

1. Проверьте cost и current_price: Убедитесь, что cost и current_price задаются правильно и в разумных пределах. Например, если cost равен 10, а цена биткоина в текущий момент $20,000, то вы покупаете на существенно малую сумму.

2. Добавьте проверку и корректировку amount_units: Убедитесь, что округленное количество единиц больше или равно минимальному объему. Если это не так, увеличьте cost или измените параметры.

Вот способ, как можно скорректировать ваш код:

def buy(symbol, cost):
    try:
        if cost <= 0:
            messagebox.showerror(‘Ошибка’, ‘Сумма должна быть положительной.’)
            return None

        current_price = get_current_price(symbol)
        if current_price is None or current_price <= 0:
            messagebox.showerror(‘Ошибка’, ‘Не удалось получить корректную текущую цену.’)
            return None

        market = exchange.market(symbol)
        min_volume = market[‘limits’][‘amount’][‘min’]

        # Рассчитываем, сколько минимально надо затрат для объема
        required_cost = min_volume * current_price

        if cost < required_cost:
            logging.error(f’Недостаточно средств для покупки. Нужно минимум {required_cost:.8f} {market[“quote”]}.‘)
            messagebox.showerror(
                ‘Ошибка’, f’Недостаточно средств для покупки. Нужно минимум {required_cost:.8f} {market[“quote”]}.’
            )
            return None

        # Вычисление и округление количества единиц
        amount_units = cost / current_price
        precision = int(market[‘precision’][‘amount’])
        amount_units = round(amount_units, precision)

        if amount_units < min_volume:
            logging.warning(‘Вычисленное количество единиц слишком мало. Пожалуйста, увеличьте сумму покупки.’)
            messagebox.showerror(
                ‘Ошибка’, f’Вычисленное количество единиц ({amount_units}) слишком мало. Минимум: {min_volume}. Пожалуйста, увеличьте сумму.‘
            )
            return None

        logging.info(f’Текущая цена: {current_price}’)
        logging.info(f’Вычисленное количество единиц: {amount_units}‘)
        logging.info(f’Минимальный объем для {symbol}: {min_volume}’)

        order = exchange.create_market_buy_order(symbol, amount_units)
        if order:
            open_positions.append({‘symbol’: symbol, ‘amount’: amount_units, ‘price’: current_price, ‘order_id’: order[‘id’]})
            return current_price
    except Exception as e:
        logging.error(‘Ошибка покупки: %s’, e)
        messagebox.showerror(‘Ошибка’, f’Не удалось купить: {e}')
        return None


### Дополнительные шаги:

- Проверяйте параметры перед покупкой: Перед выполнением покупки убедитесь, что значения cost и current_price разумны и при расчете amount_units результат не округляется до нуля.
- Обратите внимание на округление: Убедитесь, что округление производится с правильной точностью, и не приводит к результату меньшему минимального объема.
бот должен совершать покупки на любую часть от биткоина от минимально возможного до сколько есть на балансе, у меня достаточно баланса минимального для покупки, проверь всё еще раз и протестируй сам что например идёт покупка на 4доллара как пример.   import tkinter as tk
from tkinter import messagebox, OptionMenu, StringVar
import ccxt
import logging
from datetime import datetime
import time
import hmac
import hashlib
from logging.handlers import RotatingFileHandler
import pytz
import threading
from queue import Queue, Empty

# Установить уровень логирования
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s - %(message)s',
    handlers=[
        RotatingFileHandler(r'C:\Users\NOD\trading_bot.log', maxBytes=5000000, encoding='utf-8', mode='a+'),
        logging.StreamHandler()
    ]
)

# Конфигурация API
api_key = 'mx0vgl9KtaKYrVqgxi'
secret = '067d53047cf245f0b5e6b2f9e987c4c6'

# Функция для генерации сигнатуры
def generate_signature(api_key, secret, req_time, params=''):
    message = api_key + str(req_time) + params
    signature = hmac.new(secret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).hexdigest()
    return signature

# Глобальные переменные
connected = False
symbols = []
units = []
open_positions = []
session_profit = 0.0
session_start_time = None
trading_active = False
paused = False
trade_history = []

# Инициализация биржи
try:
    exchange = ccxt.mexc({
        'apiKey': api_key,
        'secret': secret,
        'options': {
            'recvWindow': 5000,
        }
    })
    exchange.load_markets()
    symbols = list(exchange.symbols)
    if not symbols:
        raise ValueError('Не удалось загрузить символы биржи.')
    logging.info('Биржа MEXC успешно инициализирована.')
    connected = True
except Exception as e:
    logging.error('Ошибка инициализации биржи MEXC: %s', e)
    connected = False

# Функция для получения и отображения баланса
def get_and_display_balance():
    try:
        balance = exchange.fetch_balance()
        usdt_balance = balance.get('total', {}).get('USDT', 0)
        label_balance.config(text=f'Баланс USDT: {usdt_balance:.2f}')
    except Exception as e:
        logging.error('Ошибка получения баланса: %s', e)

# Функция для покупки
def buy(symbol, cost):
    try:
        if cost <= 0:
            messagebox.showerror('Ошибка', 'Сумма должна быть положительной.')
            return None

        current_price = get_current_price(symbol)
        if current_price is None or current_price <= 0:
            messagebox.showerror('Ошибка', 'Не удалось получить корректную текущую цену.')
            return None

        market = exchange.market(symbol)
        min_volume = market['limits']['amount']['min']

        # Рассчитываем, сколько минимально надо затрат для объема
        required_cost = min_volume * current_price

        if cost < required_cost:
            logging.error(f'Недостаточно средств для покупки. Нужно минимум {required_cost:.8f} {market["quote"]}.')
            messagebox.showerror(
                'Ошибка', f'Недостаточно средств для покупки. Нужно минимум {required_cost:.8f} {market["quote"]}.'
            )
            return None

        # Вычисление и округление количества единиц
        amount_units = cost / current_price
        precision = int(market['precision']['amount'])  # Преобразуем в целое число
        amount_units = round(amount_units, precision)

        logging.info(f'Текущая цена: {current_price}')
        logging.info(f'Вычисленное количество единиц: {amount_units}')
        logging.info(f'Минимальный объем для {symbol}: {min_volume}')

        if amount_units < min_volume:
            messagebox.showerror(
                'Ошибка', f'Количество слишком мало для торговли: минимум {min_volume}. Пожалуйста, увеличьте.'
            )
            return None

        order = exchange.create_market_buy_order(symbol, amount_units)
        if order:
            open_positions.append({'symbol': symbol, 'amount': amount_units, 'price': current_price, 'order_id': order['id']})
            return current_price
    except Exception as e:
        logging.error('Ошибка покупки: %s', e)
        messagebox.showerror('Ошибка', f'Не удалось купить: {e}')
        return None

# Функция для продажи
def sell(symbol, amount):
    try:
        current_price = get_current_price(symbol)
        if current_price is None or current_price <= 0:
            messagebox.showerror('Ошибка', 'Не удалось получить корректную текущую цену.')
            return None

        market = exchange.market(symbol)
        min_volume = market['limits']['amount']['min']

        if amount < min_volume:
            logging.error(f"Минимальное количество для продажи: {min_volume}. Нужно продать больше {min_volume}.")
            messagebox.showerror(
                'Ошибка', f"Минимальное количество для продажи: {min_volume}. Нужно продать больше {min_volume}."
            )
            return None

        precision = market['precision']['amount']
        amount = round(amount, precision)

        logging.info(f'Текущая цена: {current_price}')
        logging.info(f'Продаваемое количество единиц: {amount}')
        logging.info(f'Минимальный объем для {symbol}: {min_volume}')

        order = exchange.create_market_sell_order(symbol, amount)
        logging.info('Продажа: %s', order)

        if open_positions:
            last_buy_order = open_positions.pop()
            profit = (current_price - last_buy_order['price']) * amount
            save_trade_state('sell', order, profit)
            logging.info('Торговая история: %s', {'type': 'sell', 'order': order, 'profit': profit})
            return current_price
    except Exception as e:
        logging.error('Ошибка продажи: %s', e)
        messagebox.showerror('Ошибка', f"Не удалось продать: {e}")
        return None

# Загрузка состояния торговли из логов
def load_trade_state():
    global session_profit, open_positions
    try:
        with open('trading_bot_state.log', 'r') as f:
            lines = f.readlines()
            open_positions = []
            session_profit = 0
            for line in lines:
                action, symbol, amount, price, profit = line.strip().split(',')
                if action == 'buy':
                    open_positions.append({'symbol': symbol, 'amount': float(amount), 'price': float(price)})
                session_profit += float(profit)
    except FileNotFoundError:
        logging.info('Лог состояния торговли не найден.')

# Сохранение состояния торговли
def save_trade_state(action, order, profit=0):
    with open('trading_bot_state.log', 'a') as f:
        f.write(f"{action},{order['symbol']},{order['amount']},{order['price']},{profit}\n")

def continue_previous_session():
    load_trade_state()
    messagebox.showinfo('Продолжение торговой сессии', 'Предыдущая торговая сессия загружена.')
    execute_trade()

# Функция для обновления и отображения открытых позиций
def update_open_positions_display():
    open_orders_text.delete(1.0, tk.END)
    for position in open_positions:
        current_profit = calculate_current_profit(position)
        open_orders_text.insert(tk.END, f"{position['symbol']} {position['amount']} @ {position['price']} текущая прибыль: {current_profit:.2f}\n")

# Функция для расчета текущей прибыли
def calculate_current_profit(position):
    current_price = get_current_price(position['symbol'])
    if current_price is not None:
        profit = (current_price - position['price']) * position['amount']
        return profit
    return 0.0

def update_symbol_menu(search_query):
    filtered_symbols = [symbol for symbol in symbols if search_query.lower() in symbol.lower()]
    menu = symbol_menu['menu']
    menu.delete(0, 'end')
    for symbol in filtered_symbols:
        menu.add_command(label=symbol, command=lambda s=symbol: on_symbol_select(s))
    if filtered_symbols:
        selected_symbol.set(filtered_symbols[0])
        update_units(filtered_symbols[0])

def on_symbol_select(symbol):
    selected_symbol.set(symbol)
    update_units(symbol)

def update_units(symbol):
    global units
    if symbol in exchange.markets:
        market = exchange.markets[symbol]
        base_currency = market['base']
        quote_currency = market['quote']
        units = [base_currency, quote_currency]
    else:
        units = []
    update_unit_menu()

def update_unit_menu():
    menu = unit_menu['menu']
    menu.delete(0, 'end')
    for unit in units:
        menu.add_command(label=unit, command=lambda u=unit: selected_unit.set(u))
    if units:
        selected_unit.set(units[0])

def pause_trade():
    global paused
    paused = True
    button_trade.config(text='Торговля на паузе')
    logging.info('Торговля приостановлена пользователем.')

def synchronize_time():
    global connected
    try:
        server_time = exchange.fetch_time()
        local_time = int(time.time() * 1000)
        time_difference = server_time - local_time
        utc = pytz.utc
        logging.info('Синхронизация времени с биржей.')
        logging.info(f'Серверное время: {datetime.fromtimestamp(server_time / 1000, utc)}')
        logging.info(f'Локальное время: {datetime.fromtimestamp(local_time / 1000, utc)}')
        logging.info(f'Временная разница: {time_difference} мс')
        connected = True
    except Exception as e:
        logging.error('Ошибка синхронизации времени: %s', e)
        connected = False

def get_current_price(symbol):
    try:
        if not validate_symbol(symbol):
            return None
        ticker = exchange.fetch_ticker(symbol)
        return ticker['last']
    except Exception as e:
        logging.error('Ошибка при получении текущей цены: %s', e)
        return None

def update_ui():
    symbol = selected_symbol.get()
    current_price = get_current_price(symbol)
    if current_price:
        label_current_price.config(text=f'Текущая цена: {current_price:.2f}')

    if session_start_time:
        elapsed_time = datetime.now() - session_start_time
        label_session_time.config(text=f'Время сессии: {elapsed_time}')

    connection_status.config(bg='green' if connected else 'red')
    update_open_positions_display()
    root.after(1000, update_ui)

def validate_symbol(symbol):
    return exchange.symbols is not None and symbol in exchange.symbols

def trade_logic_thread(q):
    try:
        symbol = selected_symbol.get()
        cost = float(entry_amount.get())
        dip_threshold = float(entry_dip.get()) / 100
        rise_threshold = float(entry_rise.get()) / 100

        current_price = get_current_price(symbol)
        if current_price is None:
            raise Exception('Недоступна текущая цена.')

        if not hasattr(execute_trade, "baseline_price") or not open_positions:
            new_buy_price = buy(symbol, cost)
            if new_buy_price:
                execute_trade.baseline_price = new_buy_price
                q.put('Куплено!')

        else:
            if current_price <= execute_trade.baseline_price * (1 - dip_threshold):
                new_buy_price = buy(symbol, cost)
                if new_buy_price:
                    execute_trade.baseline_price = new_buy_price
                    q.put('Куплено на просадке!')

            if current_price >= execute_trade.baseline_price * (1 + rise_threshold):
                for pos in open_positions[:]:
                    sell(pos['symbol'], pos['amount'])
                    open_positions.remove(pos)
                q.put('Продано при росте!')
    except Exception as e:
        q.put(f'Ошибка: {e}')

def execute_trade():
    global trading_active, paused
    if paused:
        paused = False
        button_trade.config(text='Торговля активна')
        return

    trading_active = True
    session_start_time = datetime.now()
    button_trade.config(text='Торговля активна')

    q = Queue()
    trade_thread = threading.Thread(target=trade_logic_thread, args=(q,))
    trade_thread.start()

    check_queue(q)

def check_queue(q):
    try:
        message = q.get_nowait()
    except Empty:
        root.after(100, check_queue, q)
        return

    messagebox.showinfo('Статус', message)

root = tk.Tk()
root.title('MEXC Trading Bot')

load_trade_state()
logging.info(f'Местное время компьютера: {datetime.now()}')

label_search = tk.Label(root, text='Поиск символа:')
label_search.pack()

entry_search = tk.Entry(root)
entry_search.pack()
entry_search.bind('<KeyRelease>', lambda event: update_symbol_menu(entry_search.get()))

label_symbol = tk.Label(root, text='Символ:')
label_symbol.pack()

selected_symbol = StringVar(root)
symbol_menu = OptionMenu(root, selected_symbol, '')
symbol_menu.pack()

label_unit = tk.Label(root, text='Торговая единица:')
label_unit.pack()
selected_unit = StringVar(root)
unit_menu = OptionMenu(root, selected_unit, '')
unit_menu.pack()

update_symbol_menu('')

label_balance = tk.Label(root, text="Баланс")
label_balance.pack()

label_min_volume = tk.Label(root, text="Мин. объем:")
label_min_volume.pack()

label_amount = tk.Label(root, text='Сумма (в фиатной или криптовалюте):')
label_amount.pack()
entry_amount = tk.Entry(root)
entry_amount.pack()
entry_amount.insert(tk.END, '10')

label_dip = tk.Label(root, text='Покупка при просадке (%):')
label_dip.pack()
entry_dip = tk.Entry(root)
entry_dip.pack()
entry_dip.insert(tk.END, '0.5')

label_rise = tk.Label(root, text='Продажа при росте (%):')
label_rise.pack()
entry_rise = tk.Entry(root)
entry_rise.pack()
entry_rise.insert(tk.END, '1')

button_trade = tk.Button(root, text='Начать торговлю', command=execute_trade)
button_trade.pack()

button_continue = tk.Button(root, text='Продолжить прошлую сессию', command=continue_previous_session)
button_continue.pack()

button_pause = tk.Button(root, text='Пауза', command=pause_trade)
button_pause.pack()

label_current_price = tk.Label(root, text='Текущая цена:')
label_current_price.pack()

label_positions = tk.Label(root, text='Открытых сделок: 0')
label_positions.pack()

label_profit = tk.Label(root, text='Прибыль сессии: 0.00')
label_profit.pack()

label_session_time = tk.Label(root, text='Время сессии: 00:00:00')
label_session_time.pack()

label_trade_history = tk.Label(root, text='История ордеров:')
label_trade_history.pack()
text_history = tk.Text(root, height=10, width=50)
text_history.pack()

label_open_orders = tk.Label(root, text='Текущие ордера:')
label_open_orders.pack()
open_orders_text = tk.Text(root, height=10, width=50)
open_orders_text.pack()

connection_status = tk.Label(root, text='Статус подключения', width=20, bg='red')
connection_status.pack(anchor='se')

synchronize_time()
get_and_display_balance()
update_ui()

root.mainloop()  Исправь всё и напиши полный обновленный код