Traceback (most recent call last):
  File "C:\Users\NOD\trading_bot.py", line 345, in <module>
    update_symbol_menu('')
  File "C:\Users\NOD\trading_bot.py", line 64, in update_symbol_menu
    update_units(selected_symbol.get())
  File "C:\Users\NOD\trading_bot.py", line 76, in update_units
    update_unit_menu()
  File "C:\Users\NOD\trading_bot.py", line 80, in update_unit_menu
    menu = unit_menu["menu"]
           ^^^^^^^^^
NameError: name 'unit_menu' is not defined import tkinter as tk
from tkinter import messagebox, OptionMenu
import ccxt
import logging
from datetime import datetime, timedelta
import pandas as pd
import time
import hmac
import hashlib
import requests

# Логирование
logging.basicConfig(filename='trading_bot.log', level=logging.INFO)

# Конфигурация API (замените YOUR_API_KEY и YOUR_SECRET_KEY своими настоящими ключами)
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 = []

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

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

# Функция для обновления списка символов в OptionMenu на основе поискового запроса
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: selected_symbol.set(s))
    if filtered_symbols:
        selected_symbol.set(filtered_symbols[0])
        update_units(selected_symbol.get())

# Функция для обновления списка торговых единиц на основе выбранного символа
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:
        exchange.load_time_difference()
        logging.info("Синхронизация времени с биржей.")
        connected = True
    except Exception as e:
        logging.error("Ошибка синхронизации времени: %s", e)
        connected = False

# Функция для обновления UI
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"Время сессии: {str(elapsed_time).split('.')[0]}")
    
    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 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)
        messagebox.showerror("Ошибка", f"Не удалось получить текущую цену для {symbol}.")
        return None

# Функция для покупки на заданную сумму в валюте
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']

        amount_units = cost / current_price
        amount_units = round(amount_units, market['precision']['amount'])

        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

        if amount_units <= 0:
            messagebox.showerror("Ошибка", "Количество единиц должно быть положительным.")
            return None

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

# Функция для размещения ордера
def place_order(symbol, quantity, price, trade_type='BID'):
    endpoint = "/open/api/v2/order/place"
    url = f"https://www.mexc.com{endpoint}"

    req_time = int(time.time() * 1000)
    params = {
        "symbol": symbol,
        "quantity": quantity,
        "price": price,
        "trade_type": trade_type,
        "order_type": "LIMIT_ORDER"
    }

    sign = generate_signature(api_key, secret, req_time, f"symbol={symbol}&quantity={quantity}&price={price}&trade_type={trade_type}&order_type=LIMIT_ORDER")

    headers = {
        "ApiKey": api_key,
        "Request-Time": str(req_time),
        "Signature": sign,
        "Content-Type": "application/json"
    }
    
    response = requests.post(url, headers=headers, json=params)

    if response.status_code == 200:
        data = response.json()
        if data['code'] == 200:
            logging.info("Order placed: %s", data)
            return data['data']
        else:
            logging.error("Failed to place order: %s", data)
    else:
        logging.error("HTTP Error: %d", response.status_code)

# Загрузка состояния торговли из логов
def load_trade_state():
    global session_profit, open_positions
    try:
        with open('trading_bot_state.log', 'r') as f:
            lines = f.readlines()
            open_positions = []
            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")

# Экспорт истории торгов в Excel
def export_to_excel():
    df = pd.DataFrame(trade_history)
    df.to_excel("trade_history.xlsx", index=False)

# Функция для обновления и отображения открытых позиций
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['buy_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['buy_price']) * position['amount']
        return profit
    return 0.0

# Функция для начала/продолжения торговли
def execute_trade():
    global session_start_time, trading_active, paused
    if paused:
        paused = False
        button_trade.config(text="Торговля активна")
        return

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

        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:
            return

        if not hasattr(execute_trade, "baseline_price"):
            execute_trade.baseline_price = current_price

        # Покупка при просадке
        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

        # Продажа при росте
        if current_price >= execute_trade.baseline_price * (1 + rise_threshold):
            for pos in open_positions:
                sell(pos['symbol'], pos['amount'])
                open_positions.remove(pos)

        label_positions.config(text=f"Открытых сделок: {len(open_positions)}")
        label_profit.config(text=f"Прибыль сессии: {session_profit:.2f}")

    except ValueError:
        messagebox.showerror("Ошибка", "Некорректный ввод. Убедитесь, что все значения заданы корректно.")

# Функция для продажи
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:
            messagebox.showerror("Ошибка", f"Минимальный объем для торговли: {min_volume}")
            return None

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

# Создание интерфейса
root = tk.Tk()
root.title("MEXC Trading Bot")

# Инициализация состояния
load_trade_state()

# Элементы интерфейса
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 = tk.StringVar(root)
symbol_menu = OptionMenu(root, selected_symbol, '')
symbol_menu.pack()

# Обновление меню символов изначально
update_symbol_menu('')

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

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=lambda: execute_trade())
button_trade.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()

# Обновление UI
update_ui()

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