reqhistoricaldata instead of using a soecific duration can we change it so that it takes a date from the csv column called"PrevDate" and uses that day high or low ? import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import pandas as pd
from ib_insync import *
import csv
from datetime import datetime
import queue
import threading
import asyncio
import os
import traceback
import math

# Initialize the queue for thread-safe communication
ui_queue = queue.Queue()

# Define log file paths
LOG_DIR = 'logs'
ACTIVE_ORDERS_LOG = os.path.join(LOG_DIR, 'active_orders.csv')
ACTIVE_TRADES_LOG = os.path.join(LOG_DIR, 'active_trades.csv')
CLOSED_TRADES_LOG = os.path.join(LOG_DIR, 'closed_trades.csv')
GENERAL_LOGS = os.path.join(LOG_DIR, 'general_logs.csv')

# Ensure log directory exists
os.makedirs(LOG_DIR, exist_ok=True)

def round_to_tick(price, tick_size):
    """
    Rounds the price to the nearest tick size.
    
    :param price: Desired price
    :param tick_size: Minimum tick size for the contract
    :return: Rounded price adhering to tick size
    """
    return math.floor(price / tick_size) * tick_size

# Function to log general messages
def log_general(message, level='INFO'):
    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    formatted_message = f"{timestamp} - {level} - {message}"
    ui_queue.put(('log', formatted_message))
    print(formatted_message)  # Also print to console for debugging

    # Append to general_logs.csv
    with open(GENERAL_LOGS, 'a', newline='') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow([timestamp, level, message])

# Function to log active orders
def log_active_order(order_id, symbol, action, quantity, price, status):
    with open(ACTIVE_ORDERS_LOG, 'a', newline='') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow([order_id, symbol, action, quantity, price, status])

# Function to log active trades
def log_active_trade(trade_id, symbol, entry_price, stop_loss_price, quantity, status):
    with open(ACTIVE_TRADES_LOG, 'a', newline='') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow([trade_id, symbol, entry_price, stop_loss_price, quantity, status])

# Function to log closed trades
def log_closed_trade(trade_id, symbol, entry_price, exit_price, profit_loss, exit_time):
    with open(CLOSED_TRADES_LOG, 'a', newline='') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow([trade_id, symbol, entry_price, exit_price, profit_loss, exit_time])

# Read the CSV file
def read_daily_entries(csv_file):
    try:
        entries_df = pd.read_csv(csv_file)
        print("CSV file read successfully.")

        # Convert percentage strings to float
        percentage_columns = [
            'ManualStopLossAdjustment',      # [8]
            'EntryPriceRangePercentage1',    # [2]
            'EntryPriceRangePercentage2',    # [3]
            'TakeProfitSharePercentage'      # [7]
        ]
        for col in percentage_columns:
            if col in entries_df.columns:
                try:
                    print(f"Converting percentage strings to floats in column: {col}")
                    entries_df[col] = pd.to_numeric(entries_df[col].astype(str).str.rstrip('%'), errors='coerce') / 100.0
                    print(f"Converted {col} successfully.")
                except Exception as e:
                    log_general(f"Error converting column {col}: {e}", level='ERROR')
            else:
                log_general(f"Column {col} not found in CSV.", level='WARNING')

        # Ensure 'TakeProfitType' column exists and clean up
        if 'TakeProfitType' not in entries_df.columns:
            entries_df['TakeProfitType'] = 'partial'
        else:
            entries_df['TakeProfitType'] = entries_df['TakeProfitType'].fillna('partial').astype(str).str.lower().str.strip()

        return entries_df
    except Exception as e:
        log_general(f"Error reading daily entries: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')
        return pd.DataFrame()  # Return empty DataFrame on error

# Get previous day's high or low
def get_previous_day_price(symbol, price_type, ib):
    try:
        log_general(f"Fetching previous day's {price_type} price for symbol: {symbol}")
        contract = Stock(symbol, 'SMART', 'USD')
        ib.qualifyContracts(contract)
        log_general(f"Contract qualified: {contract}")

        # Retrieve contract details to get minTick
        contract_details = ib.reqContractDetails(contract)
        if not contract_details:
            log_general(f"No contract details found for {symbol}.", level='ERROR')
            return None
        min_tick = contract_details[0].minTick
        if min_tick is None or min_tick <= 0:
            log_general(f"Invalid minTick for {symbol}. Using default tick size of 0.01.", level='WARNING')
            min_tick = 0.01
        contract.minTick = min_tick  # Assign minTick to the contract object

        bars = ib.reqHistoricalData(
            contract,
            endDateTime='',
            durationStr='2 D',
            barSizeSetting='1 day',
            whatToShow='TRADES',
            useRTH=True,
            formatDate=1
        )
        log_general(f"Received {len(bars)} historical bars for {symbol}")

        if len(bars) >= 2:
            prev_day_bar = bars[-2]
            if price_type == 'high':
                log_general(f"Previous day high for {symbol}: {prev_day_bar.high}")
                return prev_day_bar.high  # [9]
            elif price_type == 'low':
                log_general(f"Previous day low for {symbol}: {prev_day_bar.low}")
                return prev_day_bar.low  # [9]
        else:
            log_general(f"Not enough historical data for {symbol}", level='WARNING')
            return None
    except Exception as e:
        log_general(f"Error fetching previous day price for {symbol}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')
        return None

# Function to create contract based on SecurityType
def create_contract(row, ib):
    security_type = row['SecurityType'].strip().lower()
    symbol = row['Ticker'].strip()
    currency = row.get('Currency', 'USD').strip()
    primary_exchange = row.get('PrimaryExchange', 'SMART').strip()

    try:
        if security_type == 'stock':
            if pd.notna(row.get('PrimaryExchange')):
                contract = Stock(symbol, primary_exchange, currency, primaryExchange=row['PrimaryExchange'])
            else:
                contract = Stock(symbol, primary_exchange, currency)
        elif security_type == 'forex':
            contract = Forex(symbol)
        elif security_type == 'cfd':
            contract = CFD(symbol)
        elif security_type in ['future', 'futures']:
            expiry = row.get('Expiry', '').strip()  # Expected format: YYYYMMDD
            exchange = row.get('Exchange', 'GLOBEX').strip()
            contract = Future(symbol, expiry, exchange)
        elif security_type == 'option':
            expiry = row.get('Expiry', '').strip()  # Expected format: YYYYMMDD
            strike = float(row.get('Strike', 0))
            right = row.get('Right', 'C').strip().upper()  # 'C' or 'P'
            exchange = row.get('Exchange', 'SMART').strip()
            contract = Option(symbol, expiry, strike, right, exchange)
        elif security_type == 'bond':
            sec_id_type = row.get('SecIdType', 'ISIN').strip()
            sec_id = row.get('SecId', '').strip()
            contract = Bond(secIdType=sec_id_type, secId=sec_id)
        elif security_type == 'crypto':
            exchange = row.get('Exchange', 'PAXOS').strip()
            currency = row.get('Currency', 'USD').strip()
            contract = Crypto(symbol, exchange, currency)
        else:
            raise ValueError(f"Unsupported SecurityType: {security_type}")
        
        # Qualify contract and retrieve minTick
        ib.qualifyContracts(contract)
        contract_details = ib.reqContractDetails(contract)
        if not contract_details:
            log_general(f"No contract details found for {symbol}.", level='ERROR')
            return None
        min_tick = contract_details[0].minTick
        if min_tick is None or min_tick <= 0:
            log_general(f"Invalid minTick for {symbol}. Using default tick size of 0.01.", level='WARNING')
            min_tick = 0.01
        contract.minTick = min_tick  # Assign minTick to the contract object

        log_general(f"Created contract for {symbol}: {contract}, minTick: {contract.minTick}")
        return contract
    except Exception as e:
        log_general(f"Error creating contract for symbol {symbol}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')
        return None

# Place conditional orders
def place_order(row, ib):
    try:
        symbol = row['Ticker']  # [4] Ticker
        position_type = row['PositionType']  # [5] Position Type (Long/Short)
        entry_price1 = float(row['EntryPrice1'])  # [11] Entry Price 1
        entry_price2 = float(row['EntryPrice2'])  # [12] Entry Price 2
        quantity = int(row['Quantity'])  # [13] Quantity
        account = str(row['IBAccount'])
        entry_type_hours = row['EntryTypeHours']
        entry_tif = row['EntryTimeInForce']

        log_general(f"Placing order for {position_type} position on {symbol}: Quantity={quantity}, StopLimit Prices=({entry_price1}, {entry_price2})")

        # Instantiate the appropriate contract based on SecurityType
        contract = create_contract(row, ib)
        if not contract:
            log_general(f"Failed to create contract for {symbol}. Skipping order placement.", level='ERROR')
            return None, None

        # Retrieve minTick
        tick_size = contract.minTick
        if tick_size is None or tick_size <= 0:
            log_general(f"Invalid or undefined minTick for {symbol}. Using default tick size of 0.01.", level='WARNING')
            tick_size = 0.01  # Default tick size if undefined

        # Round entry prices to conform to minTick
        rounded_entry_price1 = round_to_tick(entry_price1, tick_size)
        rounded_entry_price2 = round_to_tick(entry_price2, tick_size)

        log_general(f"Rounded Entry Prices: {rounded_entry_price1} (Original: {entry_price1}), {rounded_entry_price2} (Original: {entry_price2}) for {symbol}.")

        action = 'BUY' if position_type.lower() == 'long' else 'SELL'
        outside_rth = False if entry_type_hours.lower() == 'rth' else True

        # Create StopLimitOrder with the rounded entry prices
        entry_order = StopLimitOrder(action, quantity, rounded_entry_price2, rounded_entry_price1, tif=entry_tif, outsideRth=outside_rth)

        trade = ib.placeOrder(contract, entry_order)
        log_general(f"Placed {position_type} order for {symbol}: {quantity} contracts StopLimit({rounded_entry_price1:.2f}, {rounded_entry_price2:.2f}), Outside RTH: {outside_rth}")

        log_active_order(
            order_id=trade.order.orderId,
            symbol=symbol,
            action=action,
            quantity=quantity,
            price=rounded_entry_price1,
            status=trade.orderStatus.status
        )
        # Assign callback
        trade.filledEvent += lambda fill: on_trade_fill(trade, contract, row, ib)
        return trade, contract
    except Exception as e:
        log_general(f"Error placing order for {row.get('Ticker', 'Unknown')}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')
        return None, None

# Callback function to handle trade fills
def on_trade_fill(trade, contract, row, ib):
    try:
        log_general(f"Trade fill detected for Order ID {trade.order.orderId} - {contract.symbol}")
        # Start profit management only once
        if not hasattr(trade, 'profit_managed'):
            trade.profit_managed = True
            profit_management(trade, contract, row, ib)
    except Exception as e:
        log_general(f"Error in on_trade_fill callback for Order ID {trade.order.orderId}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')

def get_entry_price(trade_id, symbol):
    """
    Retrieves the entry price for a given trade ID and symbol from the active trades log.

    :param trade_id: The ID of the trade.
    :param symbol: The trading symbol.
    :return: The entry price as a float, or None if not found.
    """
    try:
        if not os.path.exists(ACTIVE_TRADES_LOG):
            log_general(f"Active trades log file not found: {ACTIVE_TRADES_LOG}", level='ERROR')
            return None
        
        active_trades_df = pd.read_csv(ACTIVE_TRADES_LOG)
        # Ensure columns are correctly named
        active_trades_df.columns = ['Trade ID', 'Symbol', 'Entry Price', 'Stop Loss Price', 'Quantity', 'Status']
        trade_row = active_trades_df[(active_trades_df['Trade ID'] == trade_id) & (active_trades_df['Symbol'] == symbol)]
        
        if not trade_row.empty:
            return float(trade_row.iloc[0]['Entry Price'])
        else:
            log_general(f"No active trade found with Trade ID {trade_id} and Symbol {symbol}.", level='ERROR')
            return None
    except Exception as e:
        log_general(f"Error retrieving entry price for Trade ID {trade_id}, Symbol {symbol}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')
        return None

def remove_closed_trade(trade_id, symbol):
    """
    Removes a closed trade from the active trades log.

    :param trade_id: The ID of the trade.
    :param symbol: The trading symbol.
    """
    try:
        if not os.path.exists(ACTIVE_TRADES_LOG):
            log_general(f"Active trades log file not found: {ACTIVE_TRADES_LOG}", level='ERROR')
            return
        
        active_trades_df = pd.read_csv(ACTIVE_TRADES_LOG)
        active_trades_df.columns = ['Trade ID', 'Symbol', 'Entry Price', 'Stop Loss Price', 'Quantity', 'Status']
        updated_trades_df = active_trades_df[(active_trades_df['Trade ID'] != trade_id) | (active_trades_df['Symbol'] != symbol)]
        
        # Overwrite the active_trades_log with updated data
        updated_trades_df.to_csv(ACTIVE_TRADES_LOG, index=False)
        log_general(f"Removed closed trade {trade_id} for {symbol} from Active Trades log.")
    except Exception as e:
        log_general(f"Error removing closed trade {trade_id} for {symbol}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')

# Function to handle take profit fills
def on_tp_fill(fill, contract, position_type, stop_loss_price, remaining_quantity, sl_order, tp_trade, ib):
    try:
        symbol = contract.symbol
        filled_quantity = fill.size
        log_general(f"Take Profit order {tp_trade.order.orderId} filled at ${tp_trade.lmtPrice:.2f} for {symbol}.")

        # Retrieve the entry price from active trades log
        entry_price = get_entry_price(tp_trade.order.orderId, symbol)
        if entry_price is None:
            log_general(f"Cannot log closed trade for Order ID {tp_trade.order.orderId} due to missing entry price.", level='ERROR')
            return

        exit_price = float(tp_trade.lmtPrice)  # Ensure it's a float
        profit_loss = (exit_price - entry_price) * filled_quantity if position_type.lower() == 'long' else (entry_price - exit_price) * filled_quantity
        exit_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        log_closed_trade(tp_trade.order.orderId, symbol, entry_price, exit_price, profit_loss, exit_time)

        remaining_quantity -= filled_quantity

        ib.cancelOrder(sl_order)
        log_general(f"Canceled Stop Loss order {sl_order.orderId} for {symbol}.")

        if remaining_quantity > 0:
            # Adjust stop loss for remaining contracts
            new_sl_order = StopOrder(sl_order.action, remaining_quantity, stop_loss_price, tif='GTC', outsideRth=sl_order.outsideRth)
            ib.placeOrder(contract, new_sl_order)
            log_general(f"Placed new Stop Loss order at ${stop_loss_price:.2f} for remaining {remaining_quantity} contracts.")

            log_active_order(
                order_id=new_sl_order.orderId,
                symbol=symbol,
                action=new_sl_order.action,
                quantity=remaining_quantity,
                price=stop_loss_price,
                status=new_sl_order.orderStatus.status
            )
        else:
            log_general(f"Position for {symbol} fully closed.")
            # Remove the trade from active trades log
            remove_closed_trade(tp_trade.order.orderId, symbol)
    except Exception as e:
        log_general(f"Error in on_tp_fill callback for Order ID {tp_trade.order.orderId}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')

# Profit management after a trade is filled
def profit_management(trade, contract, row, ib):
    symbol = row['Ticker']
    position_type = row['PositionType']
    take_profit_share_percentage = row['TakeProfitSharePercentage']
    manual_stop_loss_adj = row['ManualStopLossAdjustment']
    risk_amount = float(row['RiskAmount'])
    account = str(row['IBAccount'])
    take_profit_hours = row['TakeProfitHours']
    take_profit_type = row['TakeProfitType']

    log_general(f"Starting profit management for {symbol}.")

    filled_price = float(trade.orderStatus.avgFillPrice)
    total_quantity = int(trade.orderStatus.filled)

    log_general(f"Order {trade.order.orderId} filled at ${filled_price:.2f} for {total_quantity} contracts.")

    initial_stop_loss = float(row['InitialStopLoss'])

    # Calculate Risk After Entry
    if position_type.lower() == 'long':
        risk_after_entry = filled_price - initial_stop_loss
    else:
        risk_after_entry = initial_stop_loss - filled_price

    # Calculate Stop Loss Price
    if position_type.lower() == 'long':
        stop_loss_price = filled_price - (manual_stop_loss_adj * risk_after_entry)
    else:
        stop_loss_price = filled_price + (manual_stop_loss_adj * risk_after_entry)

    log_general(f"Calculated risk_after_entry: {risk_after_entry}, Stop Loss Price: {stop_loss_price} for {symbol}.")

    log_active_trade(
        trade_id=trade.order.orderId,
        symbol=symbol,
        entry_price=filled_price,
        stop_loss_price=stop_loss_price,
        quantity=total_quantity,
        status=trade.orderStatus.status
    )

    # Define stop loss order
    if position_type.lower() == 'long':
        stop_action = 'SELL'
    else:
        stop_action = 'BUY'

    sl_outside_rth = False if row['StopLossHours'].lower() == 'rth' else True

    # Retrieve minTick for stop loss price adjustment
    tick_size = contract.minTick
    if tick_size is None or tick_size <= 0:
        log_general(f"Invalid or undefined minTick for {symbol}. Using default tick size of 0.01.", level='WARNING')
        tick_size = 0.01  # Default tick size if undefined

    # Round stop_loss_price to conform to minTick
    rounded_sl_price = round_to_tick(stop_loss_price, tick_size)
    log_general(f"Rounded Stop Loss Price: {rounded_sl_price} (Original: {stop_loss_price}) for {symbol}.")

    sl_order = StopOrder(stop_action, total_quantity, rounded_sl_price, tif='GTC', outsideRth=sl_outside_rth)
    ib.placeOrder(contract, sl_order)
    log_general(f"Placed Stop Loss order at ${rounded_sl_price:.2f}, Outside RTH: {sl_outside_rth}")

    log_active_order(
        order_id=sl_order.orderId,
        symbol=symbol,
        action=stop_action,
        quantity=total_quantity,
        price=rounded_sl_price,
        status="Submitted"
    )

    remaining_quantity = total_quantity
    R_level = 1  # Assuming 1R for risk-reward ratio
    entry_price = filled_price
    tp_outside_rth = False if take_profit_hours.lower() == 'rth' else True

    if take_profit_type == 'partial':
        log_general(f"Using partial Take Profit strategy for {symbol}.")

        tp_quantity = max(int(remaining_quantity * take_profit_share_percentage), 1)  # Adjust as needed
        tp_price_raw = filled_price + (R_level * risk_after_entry) if position_type.lower() == 'long' else filled_price - (R_level * risk_after_entry)

        # Round tp_price to conform to minTick
        tp_price = round_to_tick(tp_price_raw, tick_size)
        log_general(f"Calculated Take Profit price: ${tp_price:.2f} (Raw: {tp_price_raw:.2f}), Quantity: {tp_quantity} for {symbol}.")

        tp_order = LimitOrder(take_profit_action(position_type), tp_quantity, tp_price, tif='GTC', outsideRth=tp_outside_rth)
        tp_trade = ib.placeOrder(contract, tp_order)
        log_general(f"Placed Take Profit order at ${tp_price:.2f} for {tp_quantity} contracts, Outside RTH: {tp_outside_rth}")

        log_active_order(
            order_id=tp_trade.order.orderId,
            symbol=symbol,
            action=take_profit_action(position_type),
            quantity=tp_quantity,
            price=tp_price,
            status=tp_trade.orderStatus.status
        )

        # Monitor the TP order via callback
        tp_trade.filledEvent += lambda fill: on_tp_fill(fill, contract, position_type, rounded_sl_price, remaining_quantity, sl_order, tp_trade, ib)

    else:
        log_general(f"Using full Take Profit strategy for {symbol}.")

        desired_R = 1  # 1R risk-reward
        tp_price_raw = filled_price + (desired_R * risk_after_entry) if position_type.lower() == 'long' else filled_price - (desired_R * risk_after_entry)

        # Round tp_price to conform to minTick
        tp_price = round_to_tick(tp_price_raw, tick_size)
        log_general(f"Calculated Take Profit price: ${tp_price:.2f} (Raw: {tp_price_raw:.2f}) for full quantity.")

        tp_order = LimitOrder(take_profit_action(position_type), remaining_quantity, tp_price, tif='GTC', outsideRth=tp_outside_rth)
        tp_trade = ib.placeOrder(contract, tp_order)
        log_general(f"Placed Take Profit order at ${tp_price:.2f} for {remaining_quantity} contracts, Outside RTH: {tp_outside_rth}")

        log_active_order(
            order_id=tp_trade.order.orderId,
            symbol=symbol,
            action=take_profit_action(position_type),
            quantity=remaining_quantity,
            price=tp_price,
            status=tp_trade.orderStatus.status
        )

        # Monitor the TP order via callback
        tp_trade.filledEvent += lambda fill: on_tp_fill(fill, contract, position_type, rounded_sl_price, remaining_quantity, sl_order, tp_trade, ib)

# Determine action based on position type
def take_profit_action(position_type):
    return 'SELL' if position_type.lower() == 'long' else 'BUY'

# Calculate risk based on position type
def calculate_risk(entry_price, stop_loss_price, position_type):
    try:
        entry_price = float(entry_price)
        stop_loss_price = float(stop_loss_price)
        if position_type.lower() == 'long':
            risk = entry_price - stop_loss_price
        elif position_type.lower() == 'short':
            risk = stop_loss_price - entry_price
        else:
            risk = 0.0
            log_general(f"Unknown position type '{position_type}' for risk calculation.", level='WARNING')
        return risk
    except Exception as e:
        log_general(f"Error calculating risk: {e}", level='ERROR')
        return 0.0

# Calculate unrealized P/L
def calculate_unrealized_pl(entry_price, current_price, quantity, position_type):
    try:
        entry_price = float(entry_price)
        current_price = float(current_price)
        quantity = float(quantity)
        if position_type.lower() == 'long':
            pl = (current_price - entry_price) * quantity
        elif position_type.lower() == 'short':
            pl = (entry_price - current_price) * quantity
        else:
            pl = 0.0
            log_general(f"Unknown position type '{position_type}' for P/L calculation.", level='WARNING')
        return pl
    except Exception as e:
        log_general(f"Error calculating Unrealized P/L: {e}", level='ERROR')
        return 0.0

# Get current price (Placeholder)
def get_current_price(symbol, ib_instance):
    """
    Retrieves the current market price for a given symbol using the IB API.

    :param symbol: The ticker symbol to retrieve the price for.
    :param ib_instance: The active IB instance.
    :return: The current market price as a float. Returns None if unable to retrieve.
    """
    try:
        # Define the contract
        contract = Stock(symbol, 'SMART', 'USD')
        ib_instance.qualifyContracts(contract)

        # Request market data
        market_data = ib_instance.reqMktData(contract, '', False, False)

        # Allow some time for market data to be received
        ib_instance.sleep(1)

        # Retrieve the last price
        current_price = market_data.last

        # Cancel market data subscription
        ib_instance.cancelMktData(contract)

        if current_price is None:
            log_general(f"Market data for {symbol} not available.", level='WARNING')
            return None

        log_general(f"Fetched current price for {symbol}: ${current_price:.2f}")
        return float(current_price)
    except Exception as e:
        log_general(f"Error fetching current price for {symbol}: {e}", level='ERROR')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='ERROR')
        return None

# Main trading logic
def main_trading(csv_file, ib):
    log_general("Starting main trading function.")
    entries_df = read_daily_entries(csv_file)

    if entries_df.empty:
        log_general("No entries to process. Exiting trading function.", level='WARNING')
        print("No entries to process. Exiting trading function.")
        return

    placed_trades = []

    for index, row in entries_df.iterrows():
        symbol = row.get('Ticker')  # [4] Ticker
        position_type = row.get('PositionType')  # [5] Position Type (Long/Short)
        initial_stop_loss = float(row.get('InitialStopLoss'))  # [6] Stop Loss Price
        risk_amount = float(row.get('RiskAmount'))  # [1] Risk $ to calculate position size
        entry_percentage1 = float(row.get('EntryPriceRangePercentage1'))  # [2] % to calculate price range for entry 1
        entry_percentage2 = float(row.get('EntryPriceRangePercentage2'))  # [3] % to calculate price range for entry 2
        take_profit_share_percentage = float(row.get('TakeProfitSharePercentage', 0.5))  # [7] Take Profit Share %
        manual_stop_loss_adj = float(row.get('ManualStopLossAdjustment', 0.1))  # [8] Manual SL Adjustment %

        # Other parameters...
        ib_account = row.get('IBAccount', 'default_account')
        entry_time_in_force = row.get('EntryTimeInForce', 'GTC')
        entry_type_hours = row.get('EntryTypeHours', 'rth')
        stop_loss_hours = row.get('StopLossHours', 'rth')
        take_profit_hours = row.get('TakeProfitHours', 'rth')
        take_profit_type = row.get('TakeProfitType', 'partial')

        if pd.isna(symbol):
            log_general(f"Skipping entry at Index: {index} due to missing 'Ticker'.", level='WARNING')
            print(f"Skipping entry at Index: {index} due to missing 'Ticker'.")
            continue

        log_general(f"Processing entry for {symbol} (Index: {index}).")
        print(f"Processing entry for {symbol} (Index: {index}).")

        # [9] Get Previous Day Price (High for Long, Low for Short)
        price_type = 'high' if position_type.lower() == 'long' else 'low'
        prev_price = get_previous_day_price(symbol, price_type, ib)  # [9] Previous day's high/low price

        if prev_price is None:
            log_general(f"Couldn't retrieve previous day's price for {symbol}. Skipping entry.", level='WARNING')
            print(f"Couldn't retrieve previous day's price for {symbol}. Skipping entry.")
            continue

        try:
            if position_type.lower() == 'long':
                # [10] Risk per Contract = Previous Day High - Stop Loss Price
                risk_per_unit = prev_price - initial_stop_loss  # [10] = [9] - [6]
                # [11] Entry Price 1 = ([2] * [10]) + [9]
                entry_price1 = (entry_percentage1 * risk_per_unit) + prev_price  # [11]
                # [12] Entry Price 2 = ([3] * [10]) + [9]
                entry_price2 = (entry_percentage2 * risk_per_unit) + prev_price  # [12]
            else:
                # For Short positions
                risk_per_unit = initial_stop_loss - prev_price  # [10] = [6] - [9]
                # [11] Entry Price 1 = [9] - ([2] * [10])
                entry_price1 = prev_price - (entry_percentage1 * risk_per_unit)  # [11]
                # [12] Entry Price 2 = [9] - ([3] * [10])
                entry_price2 = prev_price - (entry_percentage2 * risk_per_unit)  # [12]

            log_general(f"Calculated risk_per_unit: {risk_per_unit}, EntryPrice1: {entry_price1}, EntryPrice2: {entry_price2} for {symbol}.")
            print(f"Calculated risk_per_unit: {risk_per_unit}, EntryPrice1: {entry_price1}, EntryPrice2: {entry_price2} for {symbol}.")

            # [13] Contracts to Buy = RoundDown([1] / [10])
            if risk_per_unit == 0:
                log_general(f"Risk per unit is zero for {symbol}. Skipping entry.", level='ERROR')
                print(f"Risk per unit is zero for {symbol}. Skipping entry.")
                continue


            adj_risk_per_unit = abs( entry_price1 - initial_stop_loss) #[17]
            
            #contracts to buy
            quantity = int(risk_amount / adj_risk_per_unit)  # [13]

            if quantity <= 0:
                log_general(f"Calculated quantity {quantity} for {symbol} is not positive. Skipping entry.", level='WARNING')
                print(f"Calculated quantity {quantity} for {symbol} is not positive. Skipping entry.")
                continue

        except ZeroDivisionError:
            log_general(f"Risk per unit is zero for {symbol}. Skipping entry.", level='ERROR')
            print(f"Risk per unit is zero for {symbol}. Skipping entry.")
            continue
        except TypeError:
            log_general(f"Invalid data type for 'RiskAmount' or 'RiskPerUnit' for {symbol}. Skipping entry.", level='ERROR')
            print(f"Invalid data type for 'RiskAmount' or 'RiskPerUnit' for {symbol}. Skipping entry.")
            continue

        log_general(f"Calculated quantity: {quantity} for {symbol} based on risk_amount: {risk_amount} and risk_per_unit: {risk_per_unit}.")
        print(f"Calculated quantity: {quantity} for {symbol} based on risk_amount: {risk_amount} and risk_per_unit: {risk_per_unit}.")

        # Store calculated values back into the DataFrame
        entries_df.at[index, 'RiskPerUnit'] = adj_risk_per_unit  # [10] #changing to adj version
        entries_df.at[index, 'EntryPrice1'] = entry_price1  # [11]
        entries_df.at[index, 'EntryPrice2'] = entry_price2  # [12]
        entries_df.at[index, 'Quantity'] = quantity  # [13]
        entries_df.at[index, 'TakeProfitSharePercentage'] = take_profit_share_percentage  # [7]
        entries_df.at[index, 'ManualStopLossAdjustment'] = manual_stop_loss_adj  # [8]
        entries_df.at[index, 'IBAccount'] = ib_account
        entries_df.at[index, 'EntryTypeHours'] = entry_type_hours
        entries_df.at[index, 'StopLossHours'] = stop_loss_hours
        entries_df.at[index, 'TakeProfitHours'] = take_profit_hours
        entries_df.at[index, 'TakeProfitType'] = take_profit_type

        print(f"Updated Row at Index {index}:")
        print(entries_df.loc[index])
        log_general(f"Updated Row at Index {index}:\n{entries_df.loc[index].to_string()}")

        if pd.notna(entry_price1):
            trade, contract = place_order(entries_df.loc[index], ib)
            if trade and contract:
                placed_trades.append(trade)
                log_general(f"Order placed and callback assigned for {symbol} at Index: {index}.")
                print(f"Order placed and callback assigned for {symbol} at Index: {index}.")
        else:
            log_general(f"Skipping order placement for {symbol} at Index: {index} due to missing EntryPrice1.", level='WARNING')
            print(f"Skipping order placement for {symbol} at Index: {index} due to missing EntryPrice1.")

    log_general("All entry orders placed. Awaiting fills...")
    print("All entry orders placed. Awaiting fills...")

# GUI Application using Tkinter
class TradingApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Trading Interface")
        self.geometry("1400x800")
        log_general("Initialized TradingApp GUI.")

        self.notebook = ttk.Notebook(self)
        self.notebook.pack(expand=1, fill='both')

        # Define tabs
        self.active_orders_tab = ttk.Frame(self.notebook)
        self.active_trades_tab = ttk.Frame(self.notebook)
        self.active_risk_tab = ttk.Frame(self.notebook)
        self.closed_trades_tab = ttk.Frame(self.notebook)
        self.settings_tab = ttk.Frame(self.notebook)
        self.logs_tab = ttk.Frame(self.notebook)

        # Add tabs to notebook
        self.notebook.add(self.active_orders_tab, text='Active Orders')
        self.notebook.add(self.active_trades_tab, text='Active Trades')
        self.notebook.add(self.active_risk_tab, text='Active Risk Summary')
        self.notebook.add(self.closed_trades_tab, text='Closed Trades')
        self.notebook.add(self.settings_tab, text='Settings')
        self.notebook.add(self.logs_tab, text='Logs')

        # Initialize each tab
        self.init_active_orders_tab()
        self.init_active_trades_tab()
        self.init_active_risk_tab()
        self.init_closed_trades_tab()
        self.init_settings_tab()
        self.init_logs_tab()

        # Import CSV button
        self.import_button = ttk.Button(self, text="Import CSV", command=self.import_csv)
        self.import_button.pack(pady=10)
        log_general("Added Import CSV button to GUI.")

        # Start processing the UI queue and updating the UI from logs
        self.after(1000, self.process_queue)
        self.after(2000, self.update_ui_from_logs)

    # Initialize Active Orders Tab
    def init_active_orders_tab(self):
        try:
            columns = ('Order ID', 'Symbol', 'Action', 'Quantity', 'Price', 'Status')
            self.active_orders_tree = ttk.Treeview(self.active_orders_tab, columns=columns, show='headings')
            for col in columns:
                self.active_orders_tree.heading(col, text=col)
                self.active_orders_tree.column(col, width=200, anchor='center')
            self.active_orders_tree.pack(expand=True, fill='both', padx=10, pady=10)

            vsb = ttk.Scrollbar(self.active_orders_tab, orient="vertical", command=self.active_orders_tree.yview)
            self.active_orders_tree.configure(yscrollcommand=vsb.set)
            vsb.pack(side='right', fill='y')

            log_general("Initialized Active Orders tab.")
        except Exception as e:
            log_general(f"Error initializing Active Orders tab: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Initialize Active Trades Tab
    def init_active_trades_tab(self):
        try:
            columns = ('Trade ID', 'Symbol', 'Entry Price', 'Stop Loss Price', 'Quantity', 'Status', 'Entry Time', 'Current Price', 'Unrealized P/L')
            self.active_trades_tree = ttk.Treeview(self.active_trades_tab, columns=columns, show='headings')
            for col in columns:
                self.active_trades_tree.heading(col, text=col)
                self.active_trades_tree.column(col, width=150, anchor='center')
            self.active_trades_tree.pack(expand=True, fill='both', padx=10, pady=10)

            vsb = ttk.Scrollbar(self.active_trades_tab, orient="vertical", command=self.active_trades_tree.yview)
            self.active_trades_tree.configure(yscrollcommand=vsb.set)
            vsb.pack(side='right', fill='y')

            log_general("Initialized Active Trades tab.")
        except Exception as e:
            log_general(f"Error initializing Active Trades tab: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Initialize Active Risk Summary Tab
    def init_active_risk_tab(self):
        try:
            summary_frame = ttk.Frame(self.active_risk_tab)
            summary_frame.pack(fill='both', expand=True, padx=20, pady=20)

            columns = ('Trade ID', 'Symbol', 'Entry Price', 'Stop Loss Price', 'Quantity', 'Risk', 'Status')
            self.active_risk_tree = ttk.Treeview(summary_frame, columns=columns, show='headings')
            for col in columns:
                self.active_risk_tree.heading(col, text=col)
                self.active_risk_tree.column(col, width=150, anchor='center')
            self.active_risk_tree.pack(expand=True, fill='both', padx=10, pady=10)

            vsb = ttk.Scrollbar(summary_frame, orient="vertical", command=self.active_risk_tree.yview)
            self.active_risk_tree.configure(yscrollcommand=vsb.set)
            vsb.pack(side='right', fill='y')

            self.refresh_risk_button = ttk.Button(summary_frame, text="Refresh", command=self.update_active_risk_summary)
            self.refresh_risk_button.pack(pady=10)

            # Label to display total risk
            self.total_risk_label = ttk.Label(summary_frame, text="Total Risk Exposure: $0.00", font=("Helvetica", 14, "bold"))
            self.total_risk_label.pack(pady=10)

            log_general("Initialized Active Risk Summary tab.")
        except Exception as e:
            log_general(f"Error initializing Active Risk Summary tab: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Initialize Closed Trades Tab
    def init_closed_trades_tab(self):
        try:
            columns = ('Trade ID', 'Symbol', 'Entry Price', 'Exit Price', 'Profit/Loss', 'Exit Time')
            self.closed_trades_tree = ttk.Treeview(self.closed_trades_tab, columns=columns, show='headings')
            for col in columns:
                self.closed_trades_tree.heading(col, text=col)
                self.closed_trades_tree.column(col, width=150, anchor='center')
            self.closed_trades_tree.pack(expand=True, fill='both', padx=10, pady=10)

            vsb = ttk.Scrollbar(self.closed_trades_tab, orient="vertical", command=self.closed_trades_tree.yview)
            self.closed_trades_tree.configure(yscrollcommand=vsb.set)
            vsb.pack(side='right', fill='y')

            log_general("Initialized Closed Trades tab.")
        except Exception as e:
            log_general(f"Error initializing Closed Trades tab: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Initialize Settings Tab
    def init_settings_tab(self):
        try:
            default_frame = ttk.LabelFrame(self.settings_tab, text="Default Trade Settings")
            default_frame.pack(fill='x', padx=10, pady=10)

            ttk.Label(default_frame, text="Default Risk Amount:").grid(row=0, column=0, padx=5, pady=5, sticky='e')
            self.default_risk_amount = ttk.Entry(default_frame)
            self.default_risk_amount.grid(row=0, column=1, padx=5, pady=5)
            self.default_risk_amount.insert(0, '2000')  # [1] Default Risk $

            log_general("Initialized Default Trade Settings frame.")

            ib_frame = ttk.LabelFrame(self.settings_tab, text="IB Connection")
            ib_frame.pack(fill='x', padx=10, pady=10)

            ttk.Label(ib_frame, text="Host:").grid(row=0, column=0, padx=5, pady=5, sticky='e')
            self.ib_host = ttk.Entry(ib_frame)
            self.ib_host.grid(row=0, column=1, padx=5, pady=5)
            self.ib_host.insert(0, '127.0.0.1')

            ttk.Label(ib_frame, text="Port:").grid(row=1, column=0, padx=5, pady=5, sticky='e')
            self.ib_port = ttk.Entry(ib_frame)
            self.ib_port.grid(row=1, column=1, padx=5, pady=5)
            self.ib_port.insert(0, '7497')  # Default IB port

            ttk.Label(ib_frame, text="Client ID:").grid(row=2, column=0, padx=5, pady=5, sticky='e')
            self.ib_client_id = ttk.Entry(ib_frame)
            self.ib_client_id.grid(row=2, column=1, padx=5, pady=5)
            self.ib_client_id.insert(0, '1')

            self.connect_button = ttk.Button(ib_frame, text="Connect", command=self.connect_ib)
            self.connect_button.grid(row=3, column=0, columnspan=2, pady=10)

            log_general("Initialized IB Connection frame.")

            comm_frame = ttk.LabelFrame(self.settings_tab, text="Communication Setup")
            comm_frame.pack(fill='x', padx=10, pady=10)

            ttk.Label(comm_frame, text="Email:").grid(row=0, column=0, padx=5, pady=5, sticky='e')
            self.comm_email = ttk.Entry(comm_frame)
            self.comm_email.grid(row=0, column=1, padx=5, pady=5)

            ttk.Label(comm_frame, text="Text:").grid(row=1, column=0, padx=5, pady=5, sticky='e')
            self.comm_text = ttk.Entry(comm_frame)
            self.comm_text.grid(row=1, column=1, padx=5, pady=5)

            log_general("Initialized Communication Setup frame.")

            logs_frame = ttk.LabelFrame(self.settings_tab, text="Logs")
            logs_frame.pack(fill='x', padx=10, pady=10)

            self.settings_logs = tk.Text(logs_frame, height=10)
            self.settings_logs.pack(fill='x', padx=5, pady=5)

            log_general("Initialized Logs frame in Settings tab.")
        except Exception as e:
            log_general(f"Error initializing Settings tab: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Initialize Logs Tab
    def init_logs_tab(self):
        try:
            self.logs_text = tk.Text(self.logs_tab, state='disabled')
            self.logs_text.pack(expand=True, fill='both', padx=10, pady=10)
            log_general("Initialized Logs tab.")
        except Exception as e:
            log_general(f"Error initializing Logs tab: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Connect to Interactive Brokers
    def connect_ib(self):
        try:
            host = self.ib_host.get()
            port = int(self.ib_port.get())
            client_id = int(self.ib_client_id.get())

            log_general(f"Attempting to set connection parameters: {host}:{port} Client ID {client_id}.")
            messagebox.showinfo("Connection", "Connect via Import CSV to start trading thread.")
        except Exception as e:
            messagebox.showerror("Connection Error", str(e))
            log_general(f"Failed to set connection parameters: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Import CSV and start trading thread
    def import_csv(self):
        try:
            file_path = filedialog.askopenfilename(filetypes=[("CSV Files", "*.csv")])
            if file_path:
                log_general(f"Imported CSV file: {file_path}")
                trading_thread = threading.Thread(target=self.start_trading, args=(file_path,), daemon=True)
                trading_thread.start()
                log_general("Started trading thread.")
        except Exception as e:
            log_general(f"Error importing CSV file: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Start trading logic in a separate thread
    def start_trading(self, csv_file):
        try:
            log_general("Starting trading thread.")
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)

            ib = IB()
            host = self.ib_host.get()
            port = int(self.ib_port.get())
            client_id = int(self.ib_client_id.get())

            log_general(f"Connecting to IB at {host}:{port} with Client ID {client_id}.")
            ib.connect(host, port, clientId=client_id)

            if ib.isConnected():
                log_general("Successfully connected to IB.")
            else:
                log_general("Failed to connect to IB.", level='ERROR')
                return

            # Start trading logic
            main_trading(csv_file, ib)

            # Start the event loop
            ib.run()
        except Exception as e:
            log_general(f"Error in trading thread: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Update Active Orders from logs
    def update_active_orders(self):
        try:
            if not os.path.exists(ACTIVE_ORDERS_LOG):
                return

            df = pd.read_csv(ACTIVE_ORDERS_LOG, header=None)
            df.columns = ['Order ID', 'Symbol', 'Action', 'Quantity', 'Price', 'Status']

            for item in self.active_orders_tree.get_children():
                self.active_orders_tree.delete(item)

            for index, row in df.iterrows():
                # Ensure numerical fields are correctly formatted
                try:
                    order_id = int(row['Order ID'])
                    symbol = str(row['Symbol'])
                    action = str(row['Action'])
                    quantity = int(row['Quantity'])
                    price = float(row['Price'])
                    status = str(row['Status'])

                    self.active_orders_tree.insert('', 'end', iid=order_id, values=(
                        order_id,
                        symbol,
                        action,
                        quantity,
                        f"${price:.2f}",
                        status
                    ))
                except Exception as e:
                    log_general(f"Error processing Active Orders row {index}: {e}", level='ERROR')
        except Exception as e:
            log_general(f"Error updating Active Orders from logs: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Update Active Trades from logs
    def update_active_trades(self):
        try:
            if not os.path.exists(ACTIVE_TRADES_LOG):
                return

            df = pd.read_csv(ACTIVE_TRADES_LOG, header=None)
            df.columns = ['Trade ID', 'Symbol', 'Entry Price', 'Stop Loss Price', 'Quantity', 'Status']

            for item in self.active_trades_tree.get_children():
                self.active_trades_tree.delete(item)

            for index, row in df.iterrows():
                try:
                    trade_id = int(row['Trade ID'])
                    symbol = str(row['Symbol'])
                    entry_price = float(row['Entry Price'])
                    stop_loss_price = float(row['Stop Loss Price'])
                    quantity = int(row['Quantity'])
                    status = str(row['Status'])

                    current_price = get_current_price(symbol, ib_instance=None)  # Placeholder
                    unrealized_pl = calculate_unrealized_pl(entry_price, current_price, quantity, status)

                    self.active_trades_tree.insert('', 'end', iid=trade_id, values=(
                        trade_id,
                        symbol,
                        f"${entry_price:.2f}",
                        f"${stop_loss_price:.2f}",
                        quantity,
                        status,
                        "N/A",  # Entry Time can be added if tracked
                        f"${current_price:.2f}",
                        f"${unrealized_pl:.2f}"
                    ))
                except Exception as e:
                    log_general(f"Error processing Active Trades row {index}: {e}", level='ERROR')
        except Exception as e:
            log_general(f"Error updating Active Trades from logs: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Update Closed Trades from logs
    def update_closed_trades(self):
        try:
            if not os.path.exists(CLOSED_TRADES_LOG):
                return

            df = pd.read_csv(CLOSED_TRADES_LOG, header=None)
            df.columns = ['Trade ID', 'Symbol', 'Entry Price', 'Exit Price', 'Profit/Loss', 'Exit Time']

            for item in self.closed_trades_tree.get_children():
                self.closed_trades_tree.delete(item)

            for index, row in df.iterrows():
                try:
                    trade_id = int(row['Trade ID'])
                    symbol = str(row['Symbol'])
                    entry_price = float(row['Entry Price'])
                    exit_price = float(row['Exit Price'])
                    profit_loss = float(row['Profit/Loss'])
                    exit_time = str(row['Exit Time'])

                    self.closed_trades_tree.insert('', 'end', iid=trade_id, values=(
                        trade_id,
                        symbol,
                        f"${entry_price:.2f}",
                        f"${exit_price:.2f}",
                        f"${profit_loss:.2f}",
                        exit_time
                    ))
                except Exception as e:
                    log_general(f"Error processing Closed Trades row {index}: {e}", level='ERROR')
        except Exception as e:
            log_general(f"Error updating Closed Trades from logs: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Update Active Risk Summary
    def update_active_risk_summary(self):
        try:
            if not os.path.exists(ACTIVE_TRADES_LOG):
                self.active_risk_tree.delete(*self.active_risk_tree.get_children())
                self.total_risk_label.config(text="Total Risk Exposure: $0.00")
                return

            df = pd.read_csv(ACTIVE_TRADES_LOG, header=None)
            df.columns = ['Trade ID', 'Symbol', 'Entry Price', 'Stop Loss Price', 'Quantity', 'Status']

            # Convert numerical columns
            numeric_columns = ['Entry Price', 'Stop Loss Price', 'Quantity']
            for col in numeric_columns:
                df[col] = pd.to_numeric(df[col], errors='coerce')

            self.active_risk_tree.delete(*self.active_risk_tree.get_children())

            total_risk = 0.0
            for index, row in df.iterrows():
                try:
                    trade_id = int(row['Trade ID'])
                    symbol = str(row['Symbol'])
                    entry_price = float(row['Entry Price'])
                    stop_loss_price = float(row['Stop Loss Price'])
                    quantity = int(row['Quantity'])
                    status = str(row['Status'])

                    risk = calculate_risk(entry_price, stop_loss_price, position_type='long' if 'long' in status.lower() else 'short')  # Assuming status indicates position type
                    total_risk += risk

                    self.active_risk_tree.insert('', 'end', iid=trade_id, values=(
                        trade_id,
                        symbol,
                        f"${entry_price:.2f}",
                        f"${stop_loss_price:.2f}",
                        quantity,
                        f"${risk:.2f}",
                        status
                    ))
                except Exception as e:
                    log_general(f"Error processing Active Risk Summary row {index}: {e}", level='ERROR')

            self.total_risk_label.config(text=f"Total Risk Exposure: ${total_risk:.2f}")

            log_general("Updated Active Risk Summary tab.")
        except Exception as e:
            log_general(f"Error updating Active Risk Summary: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Update Logs from general_logs.csv
    def update_logs_from_general(self):
        try:
            if not os.path.exists(GENERAL_LOGS):
                return
            with open(GENERAL_LOGS, 'r') as file:
                logs = file.read()

            self.logs_text.configure(state='normal')
            self.logs_text.delete(1.0, tk.END)
            self.logs_text.insert(tk.END, logs)
            self.logs_text.configure(state='disabled')
        except Exception as e:
            log_general(f"Error updating Logs from general_logs.csv: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Periodically update the UI from logs
    def update_ui_from_logs(self):
        self.update_active_orders()
        self.update_active_trades()
        self.update_closed_trades()
        self.update_active_risk_summary()
        self.update_logs_from_general()
        self.after(2000, self.update_ui_from_logs)

    # Process messages from the queue
    def process_queue(self):
        try:
            while not ui_queue.empty():
                try:
                    item = ui_queue.get_nowait()
                    if item[0] == 'log':
                        self.update_logs(item[1])
                except queue.Empty:
                    break
            self.after(1000, self.process_queue)
        except Exception as e:
            log_general(f"Error processing UI queue: {e}", level='ERROR')
            traceback_str = traceback.format_exc()
            log_general(f"Traceback: {traceback_str}", level='ERROR')

    # Update the Logs tab
    def update_logs(self, message):
        try:
            self.logs_text.configure(state='normal')
            self.logs_text.insert('end', f"{message}\n")
            self.logs_text.configure(state='disabled')
            self.logs_text.see('end')
        except Exception as e:
            print(f"Error updating Logs tab: {e}")

# Run the application
if __name__ == "__main__":
    try:
        app = TradingApp()
        log_general("Starting TradingApp main loop.")
        app.mainloop()
    except Exception as e:
        log_general(f"Unhandled exception in main thread: {e}", level='CRITICAL')
        traceback_str = traceback.format_exc()
        log_general(f"Traceback: {traceback_str}", level='CRITICAL')