#!/usr/bin/env python3
"""
PRODUCTION READY SOLANA HFT BOT
===============================
High-frequency trading bot with beautiful UI, integrated with your custom setup.
Optimized for your hardware and Helius RPC endpoints.
"""

import sys
import os
import time
import json
import asyncio
import logging
import requests
import traceback
import numpy as np
import pandas as pd
import threading
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional, Tuple, Set
from dataclasses import dataclass, field
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
from dotenv import load_dotenv
import random
from collections import deque

# Configure Rich for beautiful UI
try:
    from rich.console import Console
    from rich.table import Table
    from rich.panel import Panel
    from rich.layout import Layout
    from rich.text import Text
    from rich.progress import Progress, BarColumn, TextColumn, TimeElapsedColumn, SpinnerColumn
    from rich.live import Live
    from rich import box
    from rich.style import Style
    from rich.traceback import install as install_rich_traceback
    from rich.prompt import Prompt
    from rich.markdown import Markdown
    
    # Install rich traceback handler
    install_rich_traceback(show_locals=True)
    
    # Initialize rich console
    console = Console()
    
    RICH_ENABLED = True
except ImportError:
    RICH_ENABLED = False
    print("Rich library not found. Install with: pip install rich")
    # Fall back to standard console output
    class FakeConsole:
        def print(self, *args, **kwargs):
            print(*args)
    console = FakeConsole()

# Configure logging but reduce file output
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    handlers=[
        logging.FileHandler(f"solana_hft_bot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"),
        logging.NullHandler()  # Don't duplicate to stdout since we'll use rich
    ]
)
logger = logging.getLogger("solana_hft_bot")

# Reduce noise from HTTP libraries
logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.getLogger("requests").setLevel(logging.WARNING)

# Try to import your Rust module
try:
    from solana_rust_bot import SolanaTrader, WSOL_ADDRESS
    RUST_MODULE_AVAILABLE = True
except ImportError:
    console.print("[bold red]WARNING:[/] solana_rust_bot module not found - running in demo mode")
    RUST_MODULE_AVAILABLE = False
    # Create a mock for demo mode
    class MockSolanaTrader:
        def __init__(self, *args, **kwargs):
            pass
        def get_address(self):
            return "77ssrQ7LmPso1d1wYp4jAQdz4NqKSbKK8t6mFLcx6Xwr"
        def force_update_blockhash(self):
            return "7mEWo8T2F5NhGkAVGrAuLvf17ujnmZdLUXBbb636tmn8"
        def get_sol_balance(self):
            return 3.5
        def execute_jupiter_swap(self, *args, **kwargs):
            time.sleep(1.5)  # Simulate network delay
            return "5v7t5MJriBjJs81xR5XCKcXLqQ9HD2eN9gKPWy4rxFHyzr18PXzpS2GqjdiBhSJydsEzEFmkpwxShByQUWT1A78z"
        def confirm_transaction(self, *args, **kwargs):
            time.sleep(2)  # Simulate confirmation time
            return True
        def get_token_balance(self, *args, **kwargs):
            return 1000.0
        def sell_token_for_sol_via_jupiter(self, *args, **kwargs):
            time.sleep(1.5)  # Simulate network delay
            return "8zJ37spQ2mfLEYGEqKF6nQqZmhuaGN6fmJZKFpNyuci1GkRJ66NH9Sb2YTmAyiYYxcFMTFP7nRSxUCXxYBuEK7rC"
    
    SolanaTrader = MockSolanaTrader
    WSOL_ADDRESS = "So11111111111111111111111111111111111111112"

# Load environment variables
load_dotenv()

# Configure PyTorch for GPU acceleration
try:
    import torch
    GPU_ENABLED = torch.cuda.is_available()
    if GPU_ENABLED:
        device_name = torch.cuda.get_device_name(0)
        logger.info(f"GPU ACCELERATION ENABLED: {device_name}")
        
        # Apply settings from .env file
        memory_fraction = float(os.getenv('GPU_MEMORY_FRACTION', '0.95'))
        torch.backends.cuda.matmul.allow_tf32 = os.getenv('ALLOW_TF32', 'true').lower() == 'true'
        torch.backends.cudnn.benchmark = os.getenv('CUDA_BENCHMARK', 'true').lower() == 'true'
        torch.backends.cudnn.deterministic = os.getenv('CUDA_DETERMINISTIC', 'false').lower() == 'true'
        
        if memory_fraction < 1.0 and hasattr(torch.cuda, 'set_per_process_memory_fraction'):
            torch.cuda.set_per_process_memory_fraction(memory_fraction)
            
        if RICH_ENABLED:
            console.print(f"[bold green]GPU Acceleration Enabled:[/] {device_name}")
            console.print(f"[dim]CUDA Version: {torch.version.cuda}[/]")
    else:
        logger.info("GPU not available. Using CPU for processing.")
        if RICH_ENABLED:
            console.print("[yellow]GPU not available - using CPU for processing[/]")
except ImportError:
    GPU_ENABLED = False
    logger.info("PyTorch not installed. GPU acceleration disabled.")
    if RICH_ENABLED:
        console.print("[yellow]PyTorch not installed - GPU acceleration disabled[/]")

# ==== CONFIGURATION FROM ENVIRONMENT ====
# RPC Settings
RPC_URL = os.getenv('RPC_URL', 'https://winny-rychu7-fast-mainnet.helius-rpc.com')
WS_URL = os.getenv('WS_URL', 'wss://winny-rychu7-fast-mainnet.helius-rpc.com/')
API_KEY = os.getenv('API_KEY', '86ab5634-df30-4a5b-bcfb-3f53d7095ca2')
FALLBACK_RPC_URL = os.getenv('FALLBACK_RPC', 'https://mainnet.helius-rpc.com')
FALLBACK_WS_URL = os.getenv('FALLBACK_WS_URL', 'wss://mainnet.helius-rpc.com')
CONNECTION_TIMEOUT = int(os.getenv('CONNECTION_TIMEOUT', '500'))
REQUEST_TIMEOUT = int(os.getenv('REQUEST_TIMEOUT', '500'))

# Wallet Settings
KEYPAIR_PATH = os.getenv('SOLANA_KEYPAIR', r"C:\solana_rust_bot\keypair.bin")
WALLET_ADDRESS = os.getenv('SOLANA_PUBLIC_KEY', '77ssrQ7LmPso1d1wYp4jAQdz4NqKSbKK8t6mFLcx6Xwr')
WSOL_ADDRESS = os.getenv('WSOL_ADDRESS', "So11111111111111111111111111111111111111112")

# Transaction Settings
COMPUTE_LIMIT = int(os.getenv('COMPUTE_LIMIT', '200000'))
PRIORITY_FEE = int(os.getenv('PRIORITY_FEE', '50000'))
PRIORITY_MULTIPLIER = int(os.getenv('PRIORITY_MULTIPLIER', '2'))
SKIP_PREFLIGHT = os.getenv('SKIP_PREFLIGHT', 'true').lower() == 'true'
MAX_RETRIES = int(os.getenv('MAX_RETRIES', '3'))
SLIPPAGE_PERCENT = float(os.getenv('SLIPPAGE', '3.0'))

# Trading Strategy Settings
SIMULATION_MODE = os.getenv('SIMULATION_MODE', 'false').lower() == 'true'
MAX_ACTIVE_POSITIONS = 3  # Maximum number of positions
SCAN_INTERVAL = float(os.getenv('CHECK_INTERVAL', '0.5'))  # Market scan interval in seconds
POSITION_CHECK_INTERVAL = float(os.getenv('POSITION_CHECK_INTERVAL', '0.2'))  # Position update interval in seconds
POSITION_SIZE_SOL = float(os.getenv('INITIAL_INVESTMENT', '0.2'))  # Position size in SOL
TAKE_PROFIT_PERCENT = float(os.getenv('PROFIT_TARGET_PCT', '7.0'))  # Take profit percentage
STOP_LOSS_PERCENT = float(os.getenv('STOP_LOSS_PCT', '2.5'))  # Stop loss percentage
TRAILING_STOP_PCT = float(os.getenv('TRAILING_STOP_PCT', '0.4'))  # Trailing stop percentage
MAX_POSITION_HOLD_TIME = int(os.getenv('MAX_HOLD_TIME_SECONDS', '120'))  # Max hold time in seconds

# Market Filtering Criteria
MIN_LIQUIDITY_USD = float(os.getenv('MIN_LIQUIDITY_USD', '100000'))  # Minimum liquidity in USD
MAX_LIQUIDITY_USD = 3000000  # Maximum liquidity in USD
MIN_PRICE_CHANGE_5M = 3.0  # Minimum price change in 5 minutes
MIN_BUY_SELL_RATIO = float(os.getenv('MIN_BUY_SELL_RATIO', '2.0'))  # Minimum buy/sell ratio
MIN_BUYS_5M = int(os.getenv('MIN_TRANSACTIONS', '8'))  # Minimum number of buys in 5 minutes
MIN_SIGNAL_STRENGTH = float(os.getenv('MIN_SIGNAL_STRENGTH', '0.6'))  # Minimum signal strength
MIN_24H_VOLUME = float(os.getenv('MIN_24H_VOLUME', '10000'))  # Minimum 24h volume
TOP_TOKENS_COUNT = int(os.getenv('TOP_TOKENS_COUNT', '30'))  # Number of top tokens to monitor
MAX_PRICE_IMPACT_PCT = 3.0  # Maximum price impact percentage

# UI Update frequency (seconds)
UI_UPDATE_INTERVAL = 0.5  # Every half second for smooth UI updates

# Blacklist for token filtering
PERMANENT_BLACKLIST = set([
    "gork", "scam", "shit", "test", "rugpull", "rug", "cum", "porn", "fuck",
    "safe", "moon", "elon", "doge", "shib", "inu", "pepe", "wojak", "baby"
])

# Demo mode for testing the UI without real trading
DEMO_MODE = not RUST_MODULE_AVAILABLE or os.getenv('DEMO_MODE', 'false').lower() == 'true'

if DEMO_MODE and RICH_ENABLED:
    console.print("[bold yellow]DEMO MODE ACTIVE[/] - Using simulated data for UI demonstration")

@dataclass
class TokenData:
    """Token market data with scoring metrics"""
    symbol: str
    name: str
    address: str
    price_usd: float
    price_change_5m: float
    price_change_1h: float = 0.0
    liquidity_usd: float = 0.0
    volume_usd_24h: float = 0.0
    buy_sell_ratio_5m: float = 1.0
    buys_5m: int = 0
    sells_5m: int = 0
    pair_address: str = ""
    dex_id: str = ""
    first_seen: float = field(default_factory=time.time)
    last_updated: float = field(default_factory=time.time)
    volatility_score: float = 0.0
    momentum_score: float = 0.0
    depth_score: float = 0.0
    suspicious_score: float = 0.0
    price_impact_estimate: float = 0.0
    price_history: List[float] = field(default_factory=list)
    depth_map: Dict[str, Dict[float, float]] = field(default_factory=lambda: {"bids": {}, "asks": {}})
    rejection_reasons: List[str] = field(default_factory=list)
    txns: Dict[str, Dict[str, int]] = field(default_factory=dict)
    
    def age_hours(self) -> float:
        """Get age of token in hours"""
        return (time.time() - self.first_seen) / 3600
    
    def calculate_scores(self):
        """Calculate various scoring metrics to evaluate token potential"""
        self.price_history.append(self.price_usd)
        if len(self.price_history) > 20:
            self.price_history.pop(0)
        
        # Calculate volatility score based on price movement and trading activity
        self.volatility_score = min(100,
            abs(self.price_change_5m) * 3 +
            (self.buys_5m + self.sells_5m) / 5 +
            min(30, self.buy_sell_ratio_5m * 10)
        )

        # Calculate momentum with buy pressure factor
        buy_pressure = min(3.0, self.buy_sell_ratio_5m) 
        momentum = self.price_change_5m * (1 + (buy_pressure - 1) * 0.5)
        
        # Factor in how recent the token is (newer tokens get boost)
        recency_factor = max(0.7, min(2.0, 12 / max(1, self.age_hours())))

        # Look for acceleration in price momentum
        acceleration_boost = 0
        if len(self.price_history) >= 3:
            price_changes = [self.price_history[i+1]/self.price_history[i]-1 for i in range(len(self.price_history)-1)]
            if len(price_changes) >= 2 and price_changes[-1] > price_changes[-2] > 0:
                acceleration_boost = 5
        
        self.momentum_score = (momentum * recency_factor) + acceleration_boost
        
        # Calculate depth score based on liquidity
        if self.depth_map and self.depth_map["bids"] and self.depth_map["asks"]:
            current_price = self.price_usd
            buy_depth = sum(size for price, size in self.depth_map["bids"].items() if price >= current_price * 0.97)
            sell_depth = sum(size for price, size in self.depth_map["asks"].items() if price <= current_price * 1.03)
            balance_ratio = min(buy_depth, sell_depth) / max(buy_depth, sell_depth, 1)
            depth_volume = (buy_depth + sell_depth) / 2
            self.depth_score = min(100, depth_volume * balance_ratio * 0.00001)
            trade_value_usd = POSITION_SIZE_SOL * 150  # Approximate SOL price
            if buy_depth > 0:
                self.price_impact_estimate = min(20, (trade_value_usd / buy_depth) * 100)
            else:
                self.price_impact_estimate = 10.0
        else:
            self.depth_score = min(50, self.liquidity_usd * 0.00001)
            self.price_impact_estimate = min(20, (POSITION_SIZE_SOL * self.price_usd / max(self.liquidity_usd, 1)) * 100 * 3)
        
        # Calculate suspiciousness score (detect potential manipulated tokens)
        self.suspicious_score = 0
        if self.buy_sell_ratio_5m > 10:  # Extremely one-sided buys
            self.suspicious_score += 6
        if self.age_hours() < 2 and self.liquidity_usd > 500000:  # Very new with high liquidity
            self.suspicious_score += 8
        if abs(self.price_change_5m) > 15 and (self.buys_5m + self.sells_5m) < 10:  # Big price moves with few transactions
            self.suspicious_score += 6
        
        # Reduce momentum score for suspicious tokens
        if self.suspicious_score > 0:
            self.momentum_score = max(0, self.momentum_score - self.suspicious_score * 0.5)
    
    def price_acceleration(self) -> float:
        """Calculate rate of price change acceleration"""
        if len(self.price_history) < 3:
            return 0
        v1 = (self.price_history[-2]/self.price_history[-3]) - 1
        v2 = (self.price_history[-1]/self.price_history[-2]) - 1
        return (v2 - v1) * 100
    
    def calculate_optimal_position_size(self, sol_price: float, max_size: float = POSITION_SIZE_SOL) -> float:
        """Calculate optimal position size based on liquidity and price impact"""
        max_pct_of_liquidity = 0.003  # 0.3% of liquidity
        liquidity_based_size = self.liquidity_usd * max_pct_of_liquidity / sol_price
        
        if self.price_impact_estimate > 0:
            impact_factor = max(0.1, min(1.0, MAX_PRICE_IMPACT_PCT / self.price_impact_estimate))
            impact_adjusted_size = max_size * impact_factor
        else:
            impact_adjusted_size = max_size
        
        optimal_size = min(liquidity_based_size, impact_adjusted_size, max_size)
        
        # Scale by momentum for position sizing
        momentum_factor = max(0.5, min(1.2, self.momentum_score / 10))
        scaled_size = optimal_size * momentum_factor
        
        return round(min(scaled_size, max_size), 4)


@dataclass
class TradePosition:
    """Represents an active trading position for a token"""
    token_symbol: str
    token_name: str
    token_address: str
    pair_address: str
    entry_price: float
    position_size_sol: float
    entry_time: float
    token_volatility: float
    momentum_score: float
    current_price: float = 0.0
    highest_price: float = 0.0
    lowest_price_since_high: float = 0.0
    take_profit_price: float = 0.0
    stop_loss_price: float = 0.0
    trailing_stop_active: bool = False
    trailing_stop_price: float = 0.0
    transaction_id: str = ""
    exit_transaction_id: str = ""
    exit_price: float = 0.0
    exit_time: float = 0.0
    exit_reason: str = ""
    profit_loss_percent: float = 0.0
    status: str = "ACTIVE"
    price_history: List[Tuple[float, float]] = field(default_factory=list)
    no_data_count: int = 0
    price_check_count: int = 0
    target_hold_time: float = MAX_POSITION_HOLD_TIME
    
    def __post_init__(self):
        """Initialize position with appropriate values"""
        if self.current_price == 0:
            self.current_price = self.entry_price
        if self.highest_price == 0:
            self.highest_price = self.entry_price
        if self.lowest_price_since_high == 0:
            self.lowest_price_since_high = self.entry_price
        
        # Dynamically adjust take profit/stop loss based on volatility and momentum
        volatility_factor = min(1.5, max(0.8, self.token_volatility / 50))
        momentum_factor = min(1.3, max(0.8, self.momentum_score / 10))
        
        # Always use fixed take-profit for fast HFT trades
        self.take_profit_price = self.entry_price * (1 + (TAKE_PROFIT_PERCENT / 100))
        self.stop_loss_price = self.entry_price * (1 - (STOP_LOSS_PERCENT / 100))
        
        # Record initial price
        self.price_history.append((time.time(), self.entry_price))
        
        # Set dynamic hold time based on momentum
        self.target_hold_time = min(MAX_POSITION_HOLD_TIME, 
                                   max(30, int(MAX_POSITION_HOLD_TIME * (1.0 - (momentum_factor - 0.8) * 0.5))))
    
    def update_price(self, new_price: float) -> Tuple[bool, str]:
        """Update current price and check exit conditions"""
        if new_price <= 0 or new_price > self.entry_price * 3:
            self.no_data_count += 1
            return self.no_data_count > 5, "INVALID_PRICE"
        
        self.no_data_count = 0
        self.current_price = new_price
        self.price_check_count += 1
        self.price_history.append((time.time(), new_price))
        
        # Update highest price seen and activate trailing stop if needed
        if new_price > self.highest_price:
            self.highest_price = new_price
            profit_pct = ((new_price / self.entry_price) - 1) * 100
            
            # Activate trailing stop at 1% profit (lower threshold for HFT)
            if profit_pct >= 1.0:
                self.trailing_stop_active = True
                stop_distance_pct = TRAILING_STOP_PCT * 2  # Use environment setting but double it for clearer stops
                self.trailing_stop_price = new_price * (1 - stop_distance_pct / 100)
                self.trailing_stop_price = max(self.trailing_stop_price, self.stop_loss_price)
        
        # Track lowest price since high for trailing stop
        if self.trailing_stop_active and new_price < self.lowest_price_since_high:
            self.lowest_price_since_high = new_price
        
        # Calculate current profit/loss
        self.profit_loss_percent = ((new_price / self.entry_price) - 1) * 100
        
        # Check if any exit conditions are met
        return self.check_exit_conditions()
    
    def check_exit_conditions(self) -> Tuple[bool, str]:
        """Check if any exit conditions are met"""
        # Take profit reached
        if self.current_price >= self.take_profit_price:
            return True, f"TAKE_PROFIT ({self.profit_loss_percent:.2f}%)"
        
        # Trailing stop triggered
        if self.trailing_stop_active and self.current_price <= self.trailing_stop_price:
            return True, f"TRAILING_STOP ({self.profit_loss_percent:.2f}%)"
        
        # Stop loss hit
        if self.current_price <= self.stop_loss_price:
            return True, f"STOP_LOSS ({self.profit_loss_percent:.2f}%)"
        
        # Max hold time reached
        hold_time = time.time() - self.entry_time
        if hold_time >= self.target_hold_time:
            return True, f"MAX_HOLD_TIME ({self.profit_loss_percent:.2f}%)"
        
        # Special HFT exit: profit > 1% after at least 5 seconds + momentum stalling
        if hold_time >= 5 and self.profit_loss_percent > 1.0:
            # Check if momentum is stalling
            if len(self.price_history) >= 3:
                recent_times = [t for t, _ in self.price_history[-3:]]
                recent_prices = [p for _, p in self.price_history[-3:]]
                # Look for price starting to decline or flattening
                if recent_prices[-1] <= recent_prices[-2]:
                    return True, f"PROFIT_LOCK_MOMENTUM_STALL ({self.profit_loss_percent:.2f}%)"
        
        # Detect rapid price decline from peak
        if self.highest_price > self.entry_price and self.price_check_count >= 3:
            peak_gain = ((self.highest_price / self.entry_price) - 1) * 100
            current_vs_peak = ((self.current_price / self.highest_price) - 1) * 100
            
            # If we've lost 50% of our peak gain, exit
            if peak_gain > 1.0 and current_vs_peak < -50:
                return True, f"PEAK_REVERSAL ({self.profit_loss_percent:.2f}%)"
        
        # No exit conditions met
        return False, ""
    
    def close_position(self, exit_price: float, tx_id: str = "") -> Dict:
        """Close the position and calculate final results"""
        self.exit_price = exit_price
        self.exit_time = time.time()
        self.exit_transaction_id = tx_id
        self.status = "CLOSED"
        
        self.profit_loss_percent = ((exit_price / self.entry_price) - 1) * 100
        
        return {
            "token_symbol": self.token_symbol,
            "token_address": self.token_address,
            "entry_price": self.entry_price,
            "exit_price": self.exit_price,
            "hold_time": self.exit_time - self.entry_time,
            "highest_price": self.highest_price,
            "profit_loss_percent": self.profit_loss_percent,
            "exit_reason": self.exit_reason
        }
    
    def get_hold_time(self) -> float:
        """Get the current holding time in seconds"""
        return time.time() - self.entry_time


class TokenDataSource:
    """Data source for token market data from DexScreener API"""
    
    def __init__(self):
        """Initialize the token data source"""
        self.http_client = requests.Session()
        self.http_client.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': 'application/json'
        })
        
        self.dexscreener_base_url = "https://api.dexscreener.com/latest/dex"
        self.token_cache = {}
        self.cache_expiry = {}
        self.cache_duration = 2  # 2 seconds cache for HFT
        self.last_request_time = time.time()
        self.request_interval = 0.25  # 250ms between requests to respect rate limits (240 requests/min)
        self.sol_price_cache = {"price": 150.0, "last_updated": 0}
        self.sol_wsol_pair = "8QyvszDQ3smS8y62kvV3KXgtW6S4xLx1Q1oHNmHGkgrg"  # Raydium SOL/USDC
        self.demo_tokens = self._create_demo_tokens() if DEMO_MODE else {}
    
    def _create_demo_tokens(self):
        """Create demo tokens for testing"""
        demo_tokens = {}
        
        # List of sample tokens to create
        sample_tokens = [
            {"symbol": "JUP", "name": "Jupiter", "price": 1.23, "change_5m": 4.5, "liquidity": 2500000, "volume": 1200000, "buys": 25, "sells": 8},
            {"symbol": "BONK", "name": "Bonk", "price": 0.000025, "change_5m": 2.8, "liquidity": 1800000, "volume": 950000, "buys": 42, "sells": 15},
            {"symbol": "RENDER", "name": "Render", "price": 7.85, "change_5m": -1.2, "liquidity": 3200000, "volume": 1850000, "buys": 18, "sells": 22},
            {"symbol": "PYTH", "name": "Pyth Network", "price": 0.45, "change_5m": 8.2, "liquidity": 4100000, "volume": 2200000, "buys": 55, "sells": 12},
            {"symbol": "DGLN", "name": "Doglaion", "price": 0.000012, "change_5m": 12.5, "liquidity": 850000, "volume": 520000, "buys": 78, "sells": 14},
            {"symbol": "FOXY", "name": "Foxtrot", "price": 0.00075, "change_5m": 3.1, "liquidity": 950000, "volume": 750000, "buys": 32, "sells": 18},
            {"symbol": "WIF", "name": "Dogwifhat", "price": 1.85, "change_5m": 0.8, "liquidity": 5500000, "volume": 3100000, "buys": 45, "sells": 38},
            {"symbol": "HADES", "name": "Hades", "price": 0.0012, "change_5m": 5.7, "liquidity": 720000, "volume": 520000, "buys": 28, "sells": 12},
            {"symbol": "MNGO", "name": "Mango", "price": 0.055, "change_5m": -2.3, "liquidity": 1250000, "volume": 950000, "buys": 16, "sells": 24},
            {"symbol": "AURY", "name": "Aurory", "price": 0.72, "change_5m": 1.6, "liquidity": 2100000, "volume": 1450000, "buys": 26, "sells": 19}
        ]
        
        # Generate random addresses for each token
        import hashlib
        
        for i, token_data in enumerate(sample_tokens):
            # Create demo token address
            token_address = hashlib.sha256(token_data["symbol"].encode()).hexdigest()[:32]
            
            # Create token object
            token = type('TokenData', (), {
                "symbol": token_data["symbol"],
                "name": token_data["name"],
                "address": token_address,
                "prices": {"dexscreener": token_data["price"]},
                "price_change_5m": token_data["change_5m"],
                "price_change_1h": token_data["change_5m"] / 2,  # Just for demo
                "liquidity_usd": token_data["liquidity"],
                "volume_24h": token_data["volume"],
                "pair_addresses": {"dexscreener": hashlib.sha256((token_data["symbol"] + "PAIR").encode()).hexdigest()[:32]},
                "buys_5m": token_data["buys"],
                "sells_5m": token_data["sells"],
                "buy_sell_ratio_5m": token_data["buys"] / max(1, token_data["sells"]),
                "dex_id": "raydium",
                "last_updated": time.time(),
                "txns": {
                    "m5": {"buys": token_data["buys"], "sells": token_data["sells"]},
                    "h1": {"buys": token_data["buys"] * 12, "sells": token_data["sells"] * 12},
                    "h6": {"buys": token_data["buys"] * 72, "sells": token_data["sells"] * 72},
                    "h24": {"buys": token_data["buys"] * 288, "sells": token_data["sells"] * 288}
                }
            })
            
            demo_tokens[token_address] = token
            
        return demo_tokens
    
    def _update_demo_token_prices(self):
        """Update demo token prices with randomized changes for simulation"""
        if not DEMO_MODE or not self.demo_tokens:
            return
            
        for address, token in self.demo_tokens.items():
            # Create randomized price change
            price_change_pct = random.uniform(-2.0, 3.0)  # Bias slightly upward for more buy opportunities
            
            # Apply price change
            current_price = token.prices["dexscreener"]
            new_price = current_price * (1 + price_change_pct / 100)
            
            # Update token data
            token.prices["dexscreener"] = new_price
            token.price_change_5m = price_change_pct
            token.price_change_1h = token.price_change_1h * 0.9 + price_change_pct * 0.1  # Smooth 1h changes
            
            # Update transaction counts
            buys_change = random.randint(-3, 5)  # Bias toward more buys
            sells_change = random.randint(-2, 3)
            
            token.buys_5m = max(5, token.buys_5m + buys_change)
            token.sells_5m = max(2, token.sells_5m + sells_change)
            token.buy_sell_ratio_5m = token.buys_5m / max(1, token.sells_5m)
            
            # Update txns data structure
            token.txns["m5"]["buys"] = token.buys_5m
            token.txns["m5"]["sells"] = token.sells_5m
            
            # Update last updated time
            token.last_updated = time.time()
    
    def throttle_request(self):
        """Respect rate limits by throttling requests"""
        current_time = time.time()
        elapsed = current_time - self.last_request_time
        if elapsed < self.request_interval:
            time.sleep(self.request_interval - elapsed)
        self.last_request_time = time.time()
    
    def get_sol_price(self) -> float:
        """Get the current SOL price"""
        if DEMO_MODE:
            # For demo mode, return a randomized SOL price around $150
            return 150.0 + random.uniform(-2.0, 2.0)
            
        current_time = time.time()
        if current_time - self.sol_price_cache["last_updated"] > 60:
            try:
                self.throttle_request()
                url = f"{self.dexscreener_base_url}/pairs/solana/{self.sol_wsol_pair}"
                response = self.http_client.get(url, timeout=2)
                if response.status_code == 200:
                    data = response.json()
                    if "pairs" in data and len(data["pairs"]) > 0:
                        sol_price = float(data["pairs"][0].get("priceUsd", "0"))
                        if sol_price > 0:
                            self.sol_price_cache = {"price": sol_price, "last_updated": current_time}
            except Exception as e:
                logger.debug(f"Error getting SOL price: {e}")
        
        return self.sol_price_cache["price"]
    
    def get_volatile_tokens(self, min_price_change: float = 2.0, max_tokens: int = 100) -> List[Any]:
        """Get volatile tokens from DexScreener or demo data"""
        if DEMO_MODE:
            # In demo mode, update prices and return demo tokens
            self._update_demo_token_prices()
            volatile_tokens = list(self.demo_tokens.values())
            
            # Sort by price change
            volatile_tokens.sort(key=lambda t: abs(t.price_change_5m), reverse=True)
            
            return volatile_tokens[:max_tokens]
        
        volatile_tokens = []
        
        try:
            # Get top pairs sorted by volume
            self.throttle_request()
            url = f"{self.dexscreener_base_url}/pairs/solana?sort=volume24h:desc"
            response = self.http_client.get(url, timeout=3)
            
            if response.status_code == 200:
                pairs_data = response.json()
                if "pairs" in pairs_data:
                    pairs = pairs_data["pairs"]
                    
                    for pair in pairs:
                        # Only process WSOL pairs (tokens tradable with SOL)
                        if pair.get("quoteToken", {}).get("address") == WSOL_ADDRESS or pair.get("baseToken", {}).get("address") == WSOL_ADDRESS:
                            # Determine which is the token we want (the non-SOL one)
                            if pair.get("quoteToken", {}).get("address") == WSOL_ADDRESS:
                                token = pair.get("baseToken", {})
                                is_token_base = True
                            else:
                                token = pair.get("quoteToken", {})
                                is_token_base = False
                            
                            try:
                                # Get price change metrics
                                price_change_5m = abs(float(pair.get("priceChange", {}).get("m5", 0)))
                                
                                # Check if token meets volatility criteria
                                if price_change_5m >= min_price_change:
                                    # Skip if token symbol contains blacklisted terms
                                    symbol = token.get("symbol", "").lower()
                                    name = token.get("name", "").lower()
                                    blacklisted = False
                                    
                                    for term in PERMANENT_BLACKLIST:
                                        if term in symbol or term in name:
                                            blacklisted = True
                                            break
                                    
                                    if blacklisted:
                                        continue
                                    
                                    # Extract token data
                                    direction = "up" if float(pair.get("priceChange", {}).get("m5", 0)) > 0 else "down"
                                    liquidity_usd = float(pair.get("liquidity", {}).get("usd", 0))
                                    volume_24h = float(pair.get("volume", {}).get("h24", 0))
                                    
                                    # Extract transaction data for buy/sell ratio
                                    txns = pair.get("txns", {})
                                    buys_5m = int(txns.get("m5", {}).get("buys", 0))
                                    sells_5m = int(txns.get("m5", {}).get("sells", 0))
                                    buy_sell_ratio = buys_5m / max(1, sells_5m)
                                    
                                    # Create token data object
                                    token_data = {
                                        "symbol": token.get("symbol", ""),
                                        "name": token.get("name", ""),
                                        "address": token.get("address", ""),
                                        "prices": {"dexscreener": float(pair.get("priceUsd", 0))},
                                        "price_change_5m": float(pair.get("priceChange", {}).get("m5", 0)),
                                        "price_change_1h": float(pair.get("priceChange", {}).get("h1", 0)),
                                        "liquidity_usd": liquidity_usd,
                                        "volume_24h": volume_24h,
                                        "pair_addresses": {"dexscreener": pair.get("pairAddress", "")},
                                        "buys_5m": buys_5m,
                                        "sells_5m": sells_5m,
                                        "buy_sell_ratio_5m": buy_sell_ratio,
                                        "dex_id": pair.get("dexId", ""),
                                        "last_updated": time.time(),
                                        "txns": pair.get("txns", {})
                                    }
                                    
                                    # Create and cache the token object
                                    token_obj = type('TokenData', (), token_data)
                                    self.token_cache[token.get("address", "")] = token_obj
                                    self.cache_expiry[token.get("address", "")] = time.time() + self.cache_duration
                                    
                                    volatile_tokens.append(token_obj)
                                    
                                    if len(volatile_tokens) >= max_tokens:
                                        break
                            except Exception as e:
                                logger.debug(f"Error processing token data: {e}")
        
        except Exception as e:
            logger.error(f"Error fetching volatile tokens: {e}")
        
        return volatile_tokens
    
    def get_token_data(self, token_address: str) -> Optional[Any]:
        """Get token data from cache or API"""
        if DEMO_MODE and token_address in self.demo_tokens:
            return self.demo_tokens[token_address]
            
        current_time = time.time()
        
        # Check if token data is in cache and not expired
        if token_address in self.token_cache and current_time < self.cache_expiry.get(token_address, 0):
            return self.token_cache[token_address]
        
        # Fetch fresh data
        try:
            self.throttle_request()
            url = f"{self.dexscreener_base_url}/tokens/solana/{token_address}"
            response = self.http_client.get(url, timeout=2)
            
            if response.status_code == 200:
                data = response.json()
                if "pairs" in data and len(data["pairs"]) > 0:
                    # Find best pair (highest liquidity)
                    best_pair = max(data["pairs"], key=lambda p: p.get("liquidity", {}).get("usd", 0))
                    
                    # Determine if token is base or quote
                    if best_pair.get("baseToken", {}).get("address") == token_address:
                        token = best_pair.get("baseToken", {})
                        is_token_base = True
                    else:
                        token = best_pair.get("quoteToken", {})
                        is_token_base = False
                    
                    # Extract token data
                    price_change_5m = float(best_pair.get("priceChange", {}).get("m5", 0))
                    price_change_1h = float(best_pair.get("priceChange", {}).get("h1", 0))
                    liquidity_usd = float(best_pair.get("liquidity", {}).get("usd", 0))
                    volume_24h = float(best_pair.get("volume", {}).get("h24", 0))
                    
                    # Extract transaction data
                    txns = best_pair.get("txns", {})
                    buys_5m = int(txns.get("m5", {}).get("buys", 0))
                    sells_5m = int(txns.get("m5", {}).get("sells", 0))
                    buy_sell_ratio = buys_5m / max(1, sells_5m)
                    
                    # Create token data object
                    token_data = {
                        "symbol": token.get("symbol", ""),
                        "name": token.get("name", ""),
                        "address": token_address,
                        "prices": {"dexscreener": float(best_pair.get("priceUsd", 0))},
                        "price_change_5m": price_change_5m,
                        "price_change_1h": price_change_1h,
                        "liquidity_usd": liquidity_usd,
                        "volume_24h": volume_24h,
                        "pair_addresses": {"dexscreener": best_pair.get("pairAddress", "")},
                        "buys_5m": buys_5m,
                        "sells_5m": sells_5m,
                        "buy_sell_ratio_5m": buy_sell_ratio,
                        "dex_id": best_pair.get("dexId", ""),
                        "last_updated": time.time(),
                        "txns": best_pair.get("txns", {})
                    }
                    
                    # Create and cache the token object
                    token_obj = type('TokenData', (), token_data)
                    self.token_cache[token_address] = token_obj
                    self.cache_expiry[token_address] = time.time() + self.cache_duration
                    
                    return token_obj
        
        except Exception as e:
            logger.debug(f"Error fetching token data for {token_address}: {e}")
        
        return None
    
    def update_token_price(self, token_data: Any) -> bool:
        """Update token price and metrics"""
        if DEMO_MODE:
            # In demo mode, simulate a price update
            self._update_demo_token_prices()
            
            if hasattr(token_data, 'address') and token_data.address in self.demo_tokens:
                demo_token = self.demo_tokens[token_data.address]
                
                # Update with demo token data
                token_data.prices["dexscreener"] = demo_token.prices.get("dexscreener", token_data.prices.get("dexscreener", 0))
                token_data.price_change_5m = demo_token.price_change_5m
                token_data.price_change_1h = demo_token.price_change_1h
                token_data.buys_5m = demo_token.buys_5m
                token_data.sells_5m = demo_token.sells_5m
                token_data.buy_sell_ratio_5m = demo_token.buy_sell_ratio_5m
                token_data.txns = demo_token.txns
                token_data.last_updated = time.time()
                
                return True
            
            return False
                
        if not hasattr(token_data, 'address') or not hasattr(token_data, 'pair_addresses'):
            return False
        
        token_address = token_data.address
        pair_address = token_data.pair_addresses.get("dexscreener", "")
        
        if not pair_address:
            return False
        
        try:
            self.throttle_request()
            url = f"{self.dexscreener_base_url}/pairs/solana/{pair_address}"
            response = self.http_client.get(url, timeout=2)
            
            if response.status_code == 200:
                data = response.json()
                if "pairs" in data and len(data["pairs"]) > 0:
                    pair_data = data["pairs"][0]
                    
                    # Update token price and metrics
                    token_data.prices["dexscreener"] = float(pair_data.get("priceUsd", token_data.prices.get("dexscreener", 0)))
                    token_data.price_change_5m = float(pair_data.get("priceChange", {}).get("m5", token_data.price_change_5m))
                    token_data.price_change_1h = float(pair_data.get("priceChange", {}).get("h1", token_data.price_change_1h))
                    token_data.liquidity_usd = float(pair_data.get("liquidity", {}).get("usd", token_data.liquidity_usd))
                    token_data.volume_24h = float(pair_data.get("volume", {}).get("h24", token_data.volume_24h))
                    
                    # Update transaction data
                    txns = pair_data.get("txns", {})
                    token_data.buys_5m = int(txns.get("m5", {}).get("buys", 0))
                    token_data.sells_5m = int(txns.get("m5", {}).get("sells", 0))
                    token_data.buy_sell_ratio_5m = token_data.buys_5m / max(1, token_data.sells_5m)
                    token_data.txns = txns
                    token_data.last_updated = time.time()
                    
                    # Update cache
                    self.token_cache[token_address] = token_data
                    self.cache_expiry[token_address] = time.time() + self.cache_duration
                    
                    return True
        
        except Exception as e:
            logger.debug(f"Error updating token price for {token_address}: {e}")
        
        return False


class MarketDepthAnalyzer:
    """Analyzes market depth and order book data to optimize trade execution"""

    def __init__(self, http_client):
        self.http_client = http_client
        self.depth_cache = {}
        self.cache_expiry = {}
        self.cache_duration = 10  # seconds

    async def fetch_market_depth(self, token_address: str, pair_address: str) -> Dict:
        """Fetch market depth data for a token"""
        if DEMO_MODE:
            # In demo mode, generate synthetic order book
            depth_data = {"bids": {}, "asks": {}}
            
            # Use deterministic random seed based on token_address for consistent results
            import hashlib
            seed = int(hashlib.md5(token_address.encode()).hexdigest(), 16) % 10000
            random.seed(seed)
            
            # Generate synthetic price and liquidity
            base_price = 0.0001 + (seed % 1000) / 100
            liquidity = 100000 + (seed % 900000)
            
            # Create order book
            pool_depth = liquidity / 2
            
            for i in range(10):
                bid_price = base_price * (1 - (i * 0.005))  # 0.5% decreases
                bid_size = pool_depth * (0.7 ** i) / base_price  # Exponential decay
                depth_data["bids"][bid_price] = bid_size

            for i in range(10):
                ask_price = base_price * (1 + (i * 0.005))  # 0.5% increases
                ask_size = pool_depth * (0.7 ** i) / base_price  # Exponential decay
                depth_data["asks"][ask_price] = ask_size
                
            # Reset random seed
            random.seed()
            
            return depth_data
        
        current_time = time.time()
        cache_key = f"{token_address}:{pair_address}"

        if cache_key in self.depth_cache and current_time - self.cache_expiry.get(cache_key, 0) < self.cache_duration:
            return self.depth_cache[cache_key]

        depth_data = {"bids": {}, "asks": {}}

        try:
            url = f"https://api.dexscreener.com/latest/dex/pairs/solana/{pair_address}"
            response = self.http_client.get(url, timeout=2)

            if response.status_code == 200:
                data = response.json()
                if "pairs" in data and len(data["pairs"]) > 0:
                    pair = data["pairs"][0]
                    liquidity = pair.get("liquidity", {}).get("usd", 0)
                    price = float(pair.get("priceUsd", 0))

                    if price > 0 and liquidity > 0:
                        pool_depth = liquidity / 2

                        # Create synthetic order book based on liquidity
                        for i in range(10):
                            bid_price = price * (1 - (i * 0.005))  # 0.5% decreases
                            bid_size = pool_depth * (0.7 ** i) / price  # Exponential decay
                            depth_data["bids"][bid_price] = bid_size

                        for i in range(10):
                            ask_price = price * (1 + (i * 0.005))  # 0.5% increases
                            ask_size = pool_depth * (0.7 ** i) / price  # Exponential decay
                            depth_data["asks"][ask_price] = ask_size

            self.depth_cache[cache_key] = depth_data
            self.cache_expiry[cache_key] = current_time

            return depth_data

        except Exception as e:
            logger.debug(f"Error fetching market depth for {token_address}: {e}")
            return depth_data

    def calculate_price_impact(self, depth_data: Dict, price: float, amount_usd: float) -> float:
        """Calculate estimated price impact for a trade"""
        if not depth_data or not depth_data.get("asks"):
            return 10.0  # Default high impact if no data

        asks = sorted(depth_data.get("asks", {}).items())
        if not asks:
            return 10.0

        remaining_amount = amount_usd
        weighted_price = 0
        total_filled = 0

        for ask_price, ask_size in asks:
            ask_value = ask_price * ask_size

            if remaining_amount <= ask_value:
                fill_size = remaining_amount / ask_price
                weighted_price += ask_price * fill_size
                total_filled += fill_size
                remaining_amount = 0
                break
            else:
                weighted_price += ask_price * ask_size
                total_filled += ask_size
                remaining_amount -= ask_value

        if remaining_amount > 0:
            return 20.0  # Very high impact if not fully filled

        if total_filled > 0:
            avg_price = weighted_price / total_filled
            impact = ((avg_price / price) - 1) * 100
            return min(20.0, max(0.0, impact))

        return 10.0


class SolanaHighFrequencyTrader:
    """High-frequency trading bot for Solana tokens with enhanced signal detection"""

    def __init__(self):
        self.data_source = TokenDataSource()
        self.trader = None
        self.wallet_address = None

        self.running = False
        self.paused = False
        self.startup_time = time.time()
        self.last_scan_time = 0
        self.last_position_check = 0
        self.scan_count = 0
        self.recovery_mode = False
        self.recovery_end_time = 0

        self.active_positions = {}  # token_address -> TradePosition
        self.closed_positions = []  # List of closed positions
        self.available_tokens = []  # List of available TokenData objects
        self.high_potential_tokens = []  # List of tokens to monitor more frequently
        self.blacklist = set(PERMANENT_BLACKLIST)
        self.temp_blacklist = {}  # address -> expiry time
        self.loss_tokens = {}
        self.token_last_traded = {}
        self.known_tokens = {}
        self.last_signal_time = time.time()

        self.initial_balance = 0.0
        self.current_balance = 0.0
        self.total_profit_sol = 0.0
        self.trade_count = 0
        self.win_count = 0
        self.loss_count = 0
        self.consecutive_losses = 0
        self.last_trade_time = 0

        self.daily_start_time = time.time()
        self.daily_start_balance = 0.0
        self.daily_high_balance = 0.0
        self.daily_low_balance = 0.0
        self.daily_trade_count = 0
        self.day_trades_by_hour = {}

        self.sol_price_history = deque(maxlen=30)
        self.market_trend = 0
        self.current_momentum_threshold = MIN_SIGNAL_STRENGTH * 5  # Lower threshold for more signals
        self.current_take_profit = TAKE_PROFIT_PERCENT

        self.http_client = requests.Session()
        self.http_client.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
            'Accept': 'application/json'
        })

        self.depth_analyzer = MarketDepthAnalyzer(self.http_client)
        self.thread_pool = ThreadPoolExecutor(max_workers=16)
        self.shutdown_event = threading.Event()

        self.cached_volatile_tokens = []
        self.last_full_scan_time = 0
        self.min_tokens_before_recovery = 3
        self.no_signals_timer = time.time()
        
        # Dynamically adjustable parameters
        self.dynamic_params = {
            "take_profit_percent": TAKE_PROFIT_PERCENT,
            "stop_loss_percent": STOP_LOSS_PERCENT,
            "min_price_change": MIN_PRICE_CHANGE_5M,
            "max_hold_time": MAX_POSITION_HOLD_TIME,
            "momentum_threshold": self.current_momentum_threshold
        }
        
        self.original_params = self.dynamic_params.copy()
        
        # Store UI messages to avoid repetition
        self.last_ui_messages = {
            "status": "",
            "market_scan": "",
            "active_positions": {},
            "token_candidates": []
        }
        
        # Message log for UI (circular buffer)
        self.message_log = []
        self.max_messages = 10
        
        # Live UI state
        self.live_ui = None
        
        # Populate with demo data in demo mode
        if DEMO_MODE:
            if RICH_ENABLED:
                console.print("[bold yellow]Initializing with demo data for UI demonstration[/]")
            self._create_demo_data()
        
    def _create_demo_data(self):
        """Create demo data for UI testing"""
        if not DEMO_MODE:
            return
            
        # Set initial balance
        self.initial_balance = 5.0
        self.current_balance = 5.0
        self.daily_start_balance = 5.0
        self.daily_high_balance = 5.0
        self.daily_low_balance = 5.0
        
        # Add fake SOL price history
        for i in range(30):
            self.sol_price_history.append(150.0 + random.uniform(-5.0, 5.0))
            
        # Add some sample tokens to known_tokens
        tokens = self.data_source.get_volatile_tokens(min_price_change=2.0, max_tokens=10)
        for token in tokens:
            # Convert to our TokenData class
            token_data = TokenData(
                symbol=token.symbol,
                name=token.name,
                address=token.address,
                price_usd=token.prices.get("dexscreener", 0),
                price_change_5m=token.price_change_5m,
                price_change_1h=getattr(token, 'price_change_1h', 0),
                liquidity_usd=token.liquidity_usd if hasattr(token, 'liquidity_usd') else 0,
                volume_usd_24h=token.volume_24h if hasattr(token, 'volume_24h') else 0,
                pair_address=token.pair_addresses.get("dexscreener", ""),
                buys_5m=token.buys_5m if hasattr(token, 'buys_5m') else 0,
                sells_5m=token.sells_5m if hasattr(token, 'sells_5m') else 0,
                buy_sell_ratio_5m=token.buy_sell_ratio_5m if hasattr(token, 'buy_sell_ratio_5m') else 1.0,
                txns=token.txns if hasattr(token, 'txns') else {}
            )
            
            # Calculate scores
            token_data.calculate_scores()
            
            # Add to known tokens
            self.known_tokens[token_data.address] = token_data
            
            # Add to available tokens if it looks good
            if token_data.momentum_score > 5 and token_data.price_change_5m > 0:
                self.available_tokens.append(token_data)
                
        # Sort available tokens by momentum
        self.available_tokens.sort(key=lambda t: t.momentum_score, reverse=True)
        
        # Add sample active positions
        if len(self.available_tokens) >= 2:
            # Create two active positions from available tokens
            for i in range(min(2, len(self.available_tokens))):
                token = self.available_tokens[i]
                
                # Create a position
                position = TradePosition(
                    token_symbol=token.symbol,
                    token_name=token.name,
                    token_address=token.address,
                    pair_address=token.pair_address,
                    entry_price=token.price_usd,
                    position_size_sol=0.5,
                    entry_time=time.time() - random.uniform(20, 80),  # Started 20-80 seconds ago
                    token_volatility=token.volatility_score,
                    momentum_score=token.momentum_score
                )
                
                # Simulate some price updates
                for _ in range(random.randint(3, 8)):
                    price_change = random.uniform(-1.0, 2.0)  # Bias slightly positive
                    new_price = position.current_price * (1 + price_change / 100)
                    position.update_price(new_price)
                
                # Add to active positions
                self.active_positions[token.address] = position
                
        # Add sample closed positions
        for i in range(5):
            # Create random token data for closed positions
            symbol = f"TOKEN{i+1}"
            token_address = hashlib.sha256(symbol.encode()).hexdigest()[:32]
            
            # Create position
            position = TradePosition(
                token_symbol=symbol,
                token_name=f"Token {i+1}",
                token_address=token_address,
                pair_address="fakeaddr",
                entry_price=0.001 * random.uniform(0.5, 5.0),
                position_size_sol=0.2,
                entry_time=time.time() - random.uniform(300, 1800),  # Started 5-30 minutes ago
                token_volatility=random.uniform(30, 80),
                momentum_score=random.uniform(4, 12)
            )
            
            # Determine a random P/L
            profit_pct = random.uniform(-5.0, 10.0)  # Bias toward profit
            exit_price = position.entry_price * (1 + profit_pct / 100)
            
            # Choose a random exit reason
            exit_reasons = ["TAKE_PROFIT", "STOP_LOSS", "TRAILING_STOP", "MAX_HOLD_TIME", "MOMENTUM_LOSS"]
            exit_reason = random.choice(exit_reasons)
            if profit_pct > 0:
                exit_reason = "TAKE_PROFIT" if profit_pct > 5 else "TRAILING_STOP"
            else:
                exit_reason = "STOP_LOSS" if profit_pct < -2 else "MAX_HOLD_TIME"
                
            position.exit_reason = f"{exit_reason} ({profit_pct:.2f}%)"
            
            # Close position
            position.close_position(exit_price)
            self.closed_positions.append(position)
            
            # Update win/loss counts
            if profit_pct > 0:
                self.win_count += 1
            else:
                self.loss_count += 1
                
            self.trade_count += 1
            
        # Update daily trade count
        self.daily_trade_count = self.trade_count
        
        # Add some log messages
        log_messages = [
            ("Starting Solana High-Frequency Trader...", "INFO"),
            ("Connected to API with API key ending in ...ca2", "INFO"),
            ("Initial SOL price: $150.23", "INFO"),
            ("Found 8 tokens ready for trading", "SUCCESS"),
            ("Market trend: NEUTRAL (SOL $150.23, change: +0.13%)", "INFO")
        ]
        
        for msg, msg_type in log_messages:
            self.add_log_message(msg, msg_type)
            
    def add_log_message(self, message: str, message_type: str = "INFO"):
        """Add a message to the log with timestamp"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        if message_type == "INFO":
            color = "blue"
        elif message_type == "SUCCESS":
            color = "green"
        elif message_type == "WARNING":
            color = "yellow"
        elif message_type == "ERROR":
            color = "red"
        else:
            color = "white"
            
        if RICH_ENABLED:
            log_entry = Text(f"[{timestamp}] ", style="dim")
            log_entry.append(message, style=f"bold {color}")
        else:
            log_entry = f"[{timestamp}] {message}"
            
        self.message_log.append((message_type, log_entry))
        
        # Keep log at max size
        if len(self.message_log) > self.max_messages:
            self.message_log.pop(0)
            
        # Log to file also
        logger.info(message)
        
        # Print to console in non-live UI mode
        if RICH_ENABLED and not self.live_ui:
            style = f"bold {color}"
            console.print(f"[dim][{timestamp}][/] [{style}]{message}[/]")
        elif not RICH_ENABLED:
            print(f"[{timestamp}] {message}")
    
    def log_parameters(self):
        """Log current trading parameters"""
        self.add_log_message(f"Take profit: {self.dynamic_params['take_profit_percent']:.2f}% | "
                          f"Stop loss: {self.dynamic_params['stop_loss_percent']:.2f}% | "
                          f"Min price change: {self.dynamic_params['min_price_change']:.2f}%")
        self.add_log_message(f"Max hold time: {self.dynamic_params['max_hold_time']} seconds | "
                          f"Momentum threshold: {self.dynamic_params['momentum_threshold']:.2f}")
        
        if self.recovery_mode:
            self.add_log_message("Recovery mode active - using relaxed parameters", "WARNING")

    async def initialize(self):
        """Initialize trader with RPC connection and wallet setup"""
        self.add_log_message("Initializing Solana High-Frequency Trader...", "INFO")
        
        # In demo mode, we don't need to connect to real Solana network
        if DEMO_MODE:
            self.trader = SolanaTrader("dummy", "dummy", "dummy", 0, "dummy") 
            self.wallet_address = self.trader.get_address()
            self.initial_balance = self.trader.get_sol_balance()
            self.current_balance = self.initial_balance
            self.daily_start_balance = self.initial_balance
            self.daily_high_balance = self.initial_balance
            self.daily_low_balance = self.initial_balance
            
            self.running = True
            self.paused = False
            
            # Get SOL price
            sol_price = self.data_source.get_sol_price()
            if sol_price:
                self.sol_price_history.append(sol_price)
            
            self.add_log_message("Demo mode initialization complete", "SUCCESS")
            return True
            
        try:
            retry_count = 0
            max_retries = 5
            
            # Connect to Solana RPC with retries
            while retry_count < max_retries:
                try:
                    self.add_log_message(f"Connecting to RPC: {RPC_URL}")
                    self.trader = SolanaTrader(RPC_URL, WS_URL, KEYPAIR_PATH, COMPUTE_LIMIT, API_KEY)
                    break
                except Exception as e:
                    retry_count += 1
                    self.add_log_message(f"Error connecting to RPC (attempt {retry_count}/{max_retries}): {e}", "ERROR")
                    if retry_count >= max_retries:
                        # Try fallback RPC
                        self.add_log_message(f"Trying fallback RPC: {FALLBACK_RPC_URL}", "WARNING")
                        try:
                            self.trader = SolanaTrader(FALLBACK_RPC_URL, FALLBACK_WS_URL, KEYPAIR_PATH, COMPUTE_LIMIT, API_KEY)
                            break
                        except Exception as e2:
                            self.add_log_message(f"Error connecting to fallback RPC: {e2}", "ERROR")
                            return False
                    await asyncio.sleep(1)

            # Get wallet info and initial balance
            self.wallet_address = self.trader.get_address()
            self.add_log_message(f"Wallet address: {self.wallet_address}", "INFO")

            blockhash = self.trader.force_update_blockhash()
            self.add_log_message(f"Blockhash cached: {blockhash[:16]}...", "INFO")

            self.initial_balance = self.trader.get_sol_balance()
            self.current_balance = self.initial_balance
            self.daily_start_balance = self.initial_balance
            self.daily_high_balance = self.initial_balance
            self.daily_low_balance = self.initial_balance
            self.add_log_message(f"Initial SOL balance: {self.initial_balance:.6f}", "SUCCESS")

            if self.initial_balance < POSITION_SIZE_SOL:
                self.add_log_message(f"Insufficient balance! Need at least {POSITION_SIZE_SOL} SOL", "ERROR")
                return False

            self.running = True
            self.paused = False

            # Get initial SOL price
            sol_price = self.data_source.get_sol_price()
            if sol_price:
                self.sol_price_history.append(sol_price)
                self.add_log_message(f"Initial SOL price: ${sol_price:.2f}", "INFO")
            
            # Log trading parameters
            self.log_parameters()

            self.add_log_message("Solana High-Frequency Trader initialization complete", "SUCCESS")
            return True

        except Exception as e:
            self.add_log_message(f"Initialization error: {e}", "ERROR")
            logger.error(traceback.format_exc())
            return False

    async def scan_market(self):
        """Scan market for volatile tokens and potential trading opportunities"""
        try:
            current_time = time.time()
            refresh_cache = False
            
            # Check if we need to refresh the cache
            if not self.cached_volatile_tokens or (current_time - self.last_full_scan_time > 30):
                refresh_cache = True
            
            # Force refresh if in recovery mode
            if self.recovery_mode:
                refresh_cache = True
            
            if refresh_cache:
                self.add_log_message("Starting full market scan...", "INFO")
                external_tokens = self.data_source.get_volatile_tokens(
                    min_price_change=self.dynamic_params["min_price_change"] * 0.8
                )

                volatile_tokens = []
                for ext_token in external_tokens:
                    # Skip blacklisted tokens
                    blacklisted = False
                    for term in PERMANENT_BLACKLIST:
                        if term.lower() in ext_token.symbol.lower() or term.lower() in ext_token.name.lower():
                            blacklisted = True
                            break
                    if blacklisted:
                        continue

                    # Skip tokens with invalid or zero prices
                    if not hasattr(ext_token, 'prices') or not ext_token.prices.get("dexscreener", 0):
                        continue
                    
                    # Create TokenData object
                    token = TokenData(
                        symbol=ext_token.symbol,
                        name=ext_token.name,
                        address=ext_token.address,
                        price_usd=ext_token.prices.get("dexscreener", 0),
                        price_change_5m=ext_token.price_change_5m,
                        price_change_1h=getattr(ext_token, 'price_change_1h', 0),
                        liquidity_usd=getattr(ext_token, 'liquidity_usd', 0),
                        volume_usd_24h=getattr(ext_token, 'volume_24h', 0),
                        pair_address=ext_token.pair_addresses.get("dexscreener", ""),
                        buys_5m=getattr(ext_token, 'buys_5m', 0),
                        sells_5m=getattr(ext_token, 'sells_5m', 0),
                        buy_sell_ratio_5m=getattr(ext_token, 'buy_sell_ratio_5m', 1.0),
                        txns=getattr(ext_token, 'txns', {}),
                        last_updated=getattr(ext_token, 'last_updated', time.time())
                    )

                    # Calculate scores and store token
                    token.calculate_scores()
                    self.known_tokens[token.address] = token
                    volatile_tokens.append(token)

                self.cached_volatile_tokens = volatile_tokens
                self.last_full_scan_time = current_time
                
                scan_message = f"Found {len(volatile_tokens)} potential tokens matching criteria"
                if self.last_ui_messages.get("market_scan") != scan_message:
                    self.add_log_message(scan_message, "INFO")
                    self.last_ui_messages["market_scan"] = scan_message
            
            # Reset available tokens and re-filter
            current_time = time.time()
            self.available_tokens = []
            
            # Lower threshold in recovery mode
            momentum_threshold = self.dynamic_params["momentum_threshold"]
            min_price_change = self.dynamic_params["min_price_change"] 
            if self.recovery_mode:
                momentum_threshold *= 0.7
                min_price_change *= 0.7
                
            rejection_counts = {
                "blacklist": 0,
                "low_price_change": 0,
                "low_liquidity": 0,
                "low_momentum": 0, 
                "high_suspicious": 0,
                "high_impact": 0,
                "cooldown": 0,
                "loss_cooldown": 0
            }
            
            # Filter tokens for trading eligibility
            for token in self.cached_volatile_tokens:
                token.rejection_reasons = []
                
                # Check if token is blacklisted
                if token.address in self.blacklist or token.address in self.active_positions:
                    rejection_counts["blacklist"] += 1
                    token.rejection_reasons.append("blacklisted")
                    continue
                
                # Check if token is temporarily blacklisted
                if token.address in self.temp_blacklist:
                    expiry = self.temp_blacklist[token.address]
                    # Allow high momentum tokens to exit blacklist early
                    if token.momentum_score > momentum_threshold * 1.5:
                        remaining_time = expiry - current_time
                        if remaining_time < 900:  # If less than 15 minutes remaining
                            self.add_log_message(f"Early blacklist removal for high momentum token: {token.symbol}", "INFO")
                            del self.temp_blacklist[token.address]
                        else:
                            rejection_counts["blacklist"] += 1
                            token.rejection_reasons.append("temp_blacklisted")
                            continue
                    else:
                        rejection_counts["blacklist"] += 1
                        token.rejection_reasons.append("temp_blacklisted")
                        continue
                
                # Check price change threshold
                if abs(token.price_change_5m) < min_price_change:
                    rejection_counts["low_price_change"] += 1
                    token.rejection_reasons.append(f"price_change too low: {token.price_change_5m:.2f}%")
                    continue
                
                # Check liquidity requirements
                if token.liquidity_usd < MIN_LIQUIDITY_USD or token.liquidity_usd > MAX_LIQUIDITY_USD:
                    rejection_counts["low_liquidity"] += 1
                    token.rejection_reasons.append(f"liquidity outside range: ${token.liquidity_usd:.0f}")
                    continue
                
                # Check momentum score
                if token.momentum_score < momentum_threshold:
                    rejection_counts["low_momentum"] += 1
                    token.rejection_reasons.append(f"momentum too low: {token.momentum_score:.1f}")
                    continue
                
                # Check suspicious score
                if token.suspicious_score >= 7:
                    rejection_counts["high_suspicious"] += 1
                    token.rejection_reasons.append(f"suspicious score high: {token.suspicious_score}")
                    continue
                
                # Check price impact
                if token.price_impact_estimate > MAX_PRICE_IMPACT_PCT:
                    rejection_counts["high_impact"] += 1
                    token.rejection_reasons.append(f"impact too high: {token.price_impact_estimate:.2f}%")
                    continue
                
                # Check cooldown period
                last_traded = self.token_last_traded.get(token.address, 0)
                if current_time - last_traded < 300:  # 5 minute cooldown
                    rejection_counts["cooldown"] += 1
                    token.rejection_reasons.append(f"on cooldown: {(300-(current_time-last_traded))/60:.1f}m left")
                    continue
                
                # Check loss token handling
                if token.address in self.loss_tokens:
                    loss_time = self.loss_tokens[token.address]["time"]
                    loss_amount = self.loss_tokens[token.address]["percent"]
                    
                    # Reduce cooldown for small losses
                    cooldown_time = 1800  # Default 30 minutes
                    if loss_amount > -5.0:  # Less than 5% loss
                        cooldown_time = 900  # Only 15 minutes for small losses
                        
                    if current_time - loss_time < cooldown_time:
                        rejection_counts["loss_cooldown"] += 1
                        token.rejection_reasons.append(f"previous loss cooldown: {(cooldown_time-(current_time-loss_time))/60:.1f}m left")
                        continue
                    if token.momentum_score < momentum_threshold * 1.2:
                        rejection_counts["low_momentum"] += 1
                        token.rejection_reasons.append(f"needs higher momentum after loss: {token.momentum_score:.1f}")
                        continue
                
                # Token passed all filters, add to available tokens
                self.available_tokens.append(token)
            
            # Sort available tokens by momentum score
            self.available_tokens.sort(key=lambda t: t.momentum_score, reverse=True)
            
            # Update high potential tokens list (for monitoring)
            self.high_potential_tokens = self.available_tokens[:10]  # Top 10 tokens
            
            if self.available_tokens:
                avail_message = f"Found {len(self.available_tokens)} tokens ready for trading"
                if self.last_ui_messages.get("available_tokens") != avail_message:
                    self.add_log_message(avail_message, "SUCCESS")
                    self.last_ui_messages["available_tokens"] = avail_message
                    
                if self.recovery_mode:
                    self.add_log_message("Exiting recovery mode as tokens are now available", "SUCCESS")
                    self.recovery_mode = False
                    self.restore_original_parameters()
                
                # Reset no signals timer
                self.last_signal_time = current_time

            else:
                # Check if we need to enter recovery mode
                if not self.recovery_mode and current_time - self.last_signal_time > 600:  # 10 minutes with no signals
                    self.add_log_message("No trading signals for 10 minutes - activating recovery mode", "WARNING")
                    self.activate_recovery_mode()

            return self.cached_volatile_tokens

        except Exception as e:
            self.add_log_message(f"Error in scan_market: {e}", "ERROR")
            logger.error(traceback.format_exc())
            return []

    async def check_market_conditions(self):
        """Check overall market conditions to adjust trading parameters"""
        try:
            current_sol_price = self.data_source.get_sol_price()
            if not current_sol_price:
                return

            self.sol_price_history.append(current_sol_price)

            if len(self.sol_price_history) >= 10:
                avg_price = sum(self.sol_price_history) / len(self.sol_price_history)
                price_change = ((current_sol_price / avg_price) - 1) * 100

                # Determine market trend
                if price_change > 0.5:
                    new_trend = 1  # Bullish
                    self.dynamic_params["momentum_threshold"] = self.original_params["momentum_threshold"] * 0.8
                    self.dynamic_params["take_profit_percent"] = self.original_params["take_profit_percent"] * 1.2
                elif price_change < -0.5:
                    new_trend = -1  # Bearish
                    self.dynamic_params["momentum_threshold"] = self.original_params["momentum_threshold"] * 1.3
                    self.dynamic_params["take_profit_percent"] = self.original_params["take_profit_percent"] * 0.8
                else:
                    new_trend = 0  # Neutral
                    self.dynamic_params["momentum_threshold"] = self.original_params["momentum_threshold"]
                    self.dynamic_params["take_profit_percent"] = self.original_params["take_profit_percent"]
                
                # Log if trend changed
                if new_trend != self.market_trend:
                    trend_str = "BULLISH" if new_trend > 0 else "BEARISH" if new_trend < 0 else "NEUTRAL"
                    self.add_log_message(f"Market trend: {trend_str} (SOL ${current_sol_price:.2f}, change: {price_change:.2f}%)", "INFO")
                    
                self.market_trend = new_trend
                
                # Adjust trading parameters based on performance
                self.adjust_parameters_based_on_performance()

        except Exception as e:
            self.add_log_message(f"Error checking market conditions: {e}", "ERROR")

    def adjust_parameters_based_on_performance(self):
        """Dynamically adjust trading parameters based on recent performance"""
        if self.trade_count < 3:
            return  # Not enough trades to adjust
        
        # Calculate recent win rate
        win_rate = self.win_count / max(1, self.trade_count) * 100
        
        # Adjust take profit based on win rate
        if win_rate > 60 and self.consecutive_losses == 0:
            # Good performance: can be slightly more aggressive
            self.dynamic_params["take_profit_percent"] = min(
                self.original_params["take_profit_percent"] * 1.2,
                5.0  # Cap at 5%
            )
            self.dynamic_params["max_hold_time"] = min(
                self.original_params["max_hold_time"] * 0.8,
                60  # Min 60 seconds
            )
        elif win_rate < 40 or self.consecutive_losses >= 2:
            # Poor performance: be more conservative
            self.dynamic_params["take_profit_percent"] = max(
                self.original_params["take_profit_percent"] * 0.8,
                1.5  # Floor at 1.5%
            )
            self.dynamic_params["max_hold_time"] = max(
                self.original_params["max_hold_time"] * 1.2,
                120  # Max 120 seconds
            )
        else:
            # Average performance: use default parameters
            self.dynamic_params["take_profit_percent"] = self.original_params["take_profit_percent"]
            self.dynamic_params["max_hold_time"] = self.original_params["max_hold_time"]
    
    def activate_recovery_mode(self):
        """Activate recovery mode to find more trading signals"""
        self.add_log_message("Activating recovery mode - loosening criteria temporarily", "WARNING")
        
        # Store original parameters
        self.original_params = self.dynamic_params.copy()
        
        # Loosen criteria
        self.dynamic_params["momentum_threshold"] *= 0.6  # 40% reduction
        self.dynamic_params["min_price_change"] *= 0.7  # 30% reduction
        self.dynamic_params["take_profit_percent"] *= 0.9  # 10% reduction
        
        # Force refresh
        self.cached_volatile_tokens = []
        self.last_full_scan_time = 0
        
        # Set recovery mode
        self.recovery_mode = True
        self.recovery_end_time = time.time() + 300  # 5 minutes in recovery mode
        
        # Log updated parameters
        self.log_parameters()
    
    def restore_original_parameters(self):
        """Restore original parameters after recovery mode"""
        if not hasattr(self, 'original_params'):
            return
            
        self.add_log_message("Restoring original trading parameters", "INFO")
        self.dynamic_params = self.original_params.copy()
        self.recovery_mode = False
        
        # Log restored parameters
        self.log_parameters()

    async def update_positions(self):
        """Update and monitor active positions"""
        if not self.active_positions:
            return

        for token_address, position in list(self.active_positions.items()):
            try:
                if position.pair_address:
                    token_data = self.known_tokens.get(token_address)
                    if token_data:
                        # Get updated price data
                        updated = self.data_source.update_token_price(
                            type('TokenData', (), {
                                "symbol": token_data.symbol,
                                "address": token_address,
                                "name": token_data.name,
                                "prices": {"dexscreener": token_data.price_usd},
                                "pair_addresses": {"dexscreener": position.pair_address}
                            })
                        )
                        
                        if updated:
                            ext_token = self.data_source.get_token_data(token_address)
                            if ext_token:
                                # Update token data
                                token_data.price_usd = ext_token.prices.get("dexscreener", token_data.price_usd)
                                token_data.price_change_5m = getattr(ext_token, 'price_change_5m', token_data.price_change_5m)
                                token_data.liquidity_usd = getattr(ext_token, 'liquidity_usd', token_data.liquidity_usd)
                                token_data.volume_usd_24h = getattr(ext_token, 'volume_24h', token_data.volume_usd_24h)
                                token_data.last_updated = time.time()
                                token_data.buys_5m = getattr(ext_token, 'buys_5m', token_data.buys_5m)
                                token_data.sells_5m = getattr(ext_token, 'sells_5m', token_data.sells_5m)
                                
                                if token_data.sells_5m > 0:
                                    token_data.buy_sell_ratio_5m = token_data.buys_5m / token_data.sells_5m
                                else:
                                    token_data.buy_sell_ratio_5m = token_data.buys_5m

                                # Check if position should exit
                                should_exit, reason = position.update_price(token_data.price_usd)
                                if should_exit:
                                    self.add_log_message(f"Exit signal for {position.token_symbol}: {reason}", "INFO")
                                    position.exit_reason = reason
                                    await self.execute_sell(token_address)
                            else:
                                # Handle missing data
                                position.no_data_count += 1
                                hold_time = position.get_hold_time()
                                
                                # Force exit if position is stale or no data available
                                if hold_time >= position.target_hold_time or position.no_data_count >= 5:
                                    self.add_log_message(f"Position for {position.token_symbol} is stale or missing data. Forcing exit.", "WARNING")
                                    position.exit_reason = "DATA_UNAVAILABLE"
                                    await self.execute_sell(token_address)
                    else:
                        # Unknown token - should never happen but handle it
                        self.add_log_message(f"Unknown token in active positions: {token_address}", "ERROR")
                        position.exit_reason = "UNKNOWN_TOKEN"
                        await self.execute_sell(token_address)
            except Exception as e:
                self.add_log_message(f"Error updating position {position.token_symbol}: {e}", "ERROR")
                # Don't force exit here - we'll try again next cycle

    async def check_for_entry_signals(self):
        """Check for trading entry signals among available tokens"""
        if len(self.active_positions) >= MAX_ACTIVE_POSITIONS:
            return  # All positions are full

        # Calculate available slots and capital
        available_slots = MAX_ACTIVE_POSITIONS - len(self.active_positions)
        available_sol = self.current_balance - (len(self.active_positions) * POSITION_SIZE_SOL)

        if available_sol < POSITION_SIZE_SOL:
            # Don't spam this message
            if self.last_ui_messages.get("balance_warning") != available_sol:
                self.add_log_message(f"Insufficient balance for new positions: {available_sol:.6f} SOL", "WARNING")
                self.last_ui_messages["balance_warning"] = available_sol
            return

        # Determine how many positions we can open
        positions_possible = min(available_slots, int(available_sol / POSITION_SIZE_SOL))
        if positions_possible <= 0:
            return
            
        # If we have no available tokens, try to fetch fresh data
        if not self.available_tokens:
            # Only do this occasionally to avoid excessive API calls
            current_time = time.time()
            if current_time - self.last_full_scan_time > 30:
                await self.scan_market()

        # Don't spam this message
        if self.last_ui_messages.get("entry_signal") != positions_possible:
            self.add_log_message(f"Looking for trading opportunities ({positions_possible} positions available)", "INFO")
            self.last_ui_messages["entry_signal"] = positions_possible

        opened_count = 0
        top_tokens = sorted(self.available_tokens, key=lambda t: t.momentum_score, reverse=True)[:positions_possible*2]

        for token in top_tokens:
            # Skip if we've opened enough positions
            if opened_count >= positions_possible:
                break
                
            try:
                # Fetch fresh market depth data
                if token.pair_address:
                    depth_data = await self.depth_analyzer.fetch_market_depth(token.address, token.pair_address)
                    if depth_data and (depth_data["bids"] or depth_data["asks"]):
                        token.depth_map = depth_data
                        price = token.price_usd
                        amount_usd = POSITION_SIZE_SOL * self.sol_price_history[-1] if self.sol_price_history else POSITION_SIZE_SOL * 150.0
                        token.price_impact_estimate = self.depth_analyzer.calculate_price_impact(depth_data, price, amount_usd)

                # Verify price impact is acceptable
                if token.price_impact_estimate > MAX_PRICE_IMPACT_PCT:
                    continue

                # Calculate optimal position size
                sol_price = self.sol_price_history[-1] if self.sol_price_history else 150.0
                optimal_size = token.calculate_optimal_position_size(sol_price=sol_price, max_size=POSITION_SIZE_SOL)
                if optimal_size < 0.05:
                    continue

                # Check momentum and execute buy if conditions are met
                if token.momentum_score >= self.dynamic_params["momentum_threshold"] and token.price_change_5m != 0:
                    if token.price_change_5m > 0 and token.liquidity_usd >= MIN_LIQUIDITY_USD:
                        # Determine buy reason based on momentum and price action
                        if token.price_change_5m > 3.0 and token.buy_sell_ratio_5m > 1.5:
                            reason = f"STRONG_UPTREND: +{token.price_change_5m:.2f}% with buy pressure {token.buy_sell_ratio_5m:.1f}x"
                        elif token.price_acceleration() > 0:
                            reason = f"ACCELERATING_MOMENTUM: +{token.price_change_5m:.2f}% with rising velocity"
                        else:
                            reason = f"POSITIVE_MOMENTUM: +{token.price_change_5m:.2f}% movement"
                            
                        # Execute buy
                        success = await self.execute_buy(token, reason, optimal_size)
                        if success:
                            opened_count += 1
                            self.last_trade_time = time.time()
                            self.token_last_traded[token.address] = time.time()
                            break  # Focus on one position at a time for HFT
                    elif token.price_change_5m < -3.0 and token.momentum_score > self.dynamic_params["momentum_threshold"] * 1.3:
                        # Potential dip buying opportunity
                        if token.price_history and len(token.price_history) >= 3 and token.price_history[-1] > token.price_history[-2]:
                            # Price is recovering from dip
                            reason = f"DIP_RECOVERY: {token.price_change_5m:.2f}% dip with reversal signs"
                            dip_size = optimal_size * 0.7  # Smaller position for dip buys
                            success = await self.execute_buy(token, reason, dip_size)
                            if success:
                                opened_count += 1
                                self.last_trade_time = time.time()
                                self.token_last_traded[token.address] = time.time()
                                break
            except Exception as e:
                self.add_log_message(f"Error processing entry signal for {token.symbol}: {e}", "ERROR")
                continue  # Skip this token and try the next one
        
        if opened_count > 0:
            self.add_log_message(f"Opened {opened_count} new positions", "SUCCESS")
        
        # Special case: if no tokens were found for a long time, try recovery mode
        current_time = time.time()
        if opened_count == 0 and len(self.active_positions) == 0 and current_time - self.last_trade_time > 600:
            # No trades for 10 minutes
            if not self.recovery_mode and current_time - self.no_signals_timer > 300:
                self.add_log_message("No trades for 10 minutes - activating recovery mode", "WARNING")
                self.activate_recovery_mode()
                self.no_signals_timer = current_time

    async def execute_buy(self, token: TokenData, reason: str, position_size: float) -> bool:
        """Execute a buy order for a token"""
        if token.address in self.active_positions:
            return False
            
        if self.current_balance < position_size:
            self.add_log_message(f"Insufficient balance: {self.current_balance:.6f} SOL", "WARNING")
            return False
            
        if self.paused:
            self.add_log_message("Trading is paused - skipping buy", "WARNING")
            return False

        # Check cooldown period
        current_time = time.time()
        last_traded = self.token_last_traded.get(token.address, 0)
        if current_time - last_traded < 300:  # 5 minute cooldown
            self.add_log_message(f"Skipping {token.symbol} - on cooldown for {(300 - (current_time - last_traded))/60:.1f} more minutes", "INFO")
            return False

        # Extra check for tokens that previously resulted in losses
        if token.address in self.loss_tokens:
            loss_time = self.loss_tokens[token.address]["time"]
            loss_amount = self.loss_tokens[token.address]["percent"]
            cooldown_time = 1800  # 30 minutes default
            
            # Shorter cooldown for small losses
            if loss_amount > -5.0:
                cooldown_time = 900  # 15 minutes
                
            if current_time - loss_time < cooldown_time:
                self.add_log_message(f"Skipping {token.symbol} - previous loss of {loss_amount:.2f}% (in cooldown)", "INFO")
                return False
                
            # Require higher momentum for tokens with previous losses
            if token.momentum_score < self.dynamic_params["momentum_threshold"] * 1.2:
                self.add_log_message(f"Skipping {token.symbol} - needs higher momentum after previous loss", "INFO")
                return False

        # SIMULATION MODE or DEMO_MODE
        if SIMULATION_MODE or DEMO_MODE:
            self.add_log_message(f"SIMULATION: Buying {token.symbol} ({reason})", "SUCCESS")
            
            # Create transaction panel
            if RICH_ENABLED:
                buy_panel = Panel(
                    f"[bold green]SIMULATED BUY TRADE[/]\n\n"
                    f"[bold cyan]Token:[/] {token.symbol} ({token.name})\n"
                    f"[bold cyan]Reason:[/] {reason}\n"
                    f"[bold cyan]Price:[/] ${token.price_usd:.6f}\n"
                    f"[bold cyan]5m Change:[/] [{'green' if token.price_change_5m > 0 else 'red'}]{token.price_change_5m:+.2f}%[/]\n"
                    f"[bold cyan]Position Size:[/] {position_size} SOL\n"
                    f"[bold cyan]Est. Price Impact:[/] {token.price_impact_estimate:.2f}%",
                    title="Transaction",
                    border_style="green"
                )
                console.print(buy_panel)
            else:
                print(f"\n=== SIMULATED BUY TRADE ===")
                print(f"Token: {token.symbol} ({token.name})")
                print(f"Reason: {reason}")
                print(f"Price: ${token.price_usd:.6f}")
                print(f"5m Change: {token.price_change_5m:+.2f}%")
                print(f"Position Size: {position_size} SOL (Optimal size)")
                print(f"Estimated Price Impact: {token.price_impact_estimate:.2f}%")

            # Create position object
            position = TradePosition(
                token_symbol=token.symbol,
                token_name=token.name,
                token_address=token.address,
                pair_address=token.pair_address,
                entry_price=token.price_usd,
                position_size_sol=position_size,
                entry_time=time.time(),
                token_volatility=token.volatility_score,
                momentum_score=token.momentum_score,
                target_hold_time=self.dynamic_params["max_hold_time"]
            )

            # Set take profit based on current settings
            position.take_profit_price = token.price_usd * (1 + (self.dynamic_params["take_profit_percent"] / 100))
            position.stop_loss_price = token.price_usd * (1 - (self.dynamic_params["stop_loss_percent"] / 100))

            # Add to active positions
            self.active_positions[token.address] = position
            self.trade_count += 1
            self.daily_trade_count += 1
            
            # Update daily statistics
            hour = datetime.now().hour
            self.day_trades_by_hour[hour] = self.day_trades_by_hour.get(hour, 0) + 1
            
            # Update balance
            self.current_balance -= position_size

            # Display trade details
            if RICH_ENABLED:
                details_panel = Panel(
                    f"[bold cyan]Take profit:[/] ${position.take_profit_price:.6f} (+{self.dynamic_params['take_profit_percent']:.1f}%)\n"
                    f"[bold cyan]Stop loss:[/] ${position.stop_loss_price:.6f} (-{self.dynamic_params['stop_loss_percent']:.1f}%)\n"
                    f"[bold cyan]Max hold time:[/] {position.target_hold_time} seconds\n"
                    f"[bold cyan]Market conditions:[/] [{'green' if self.market_trend > 0 else 'red' if self.market_trend < 0 else 'yellow'}]"
                    f"{'BULLISH' if self.market_trend > 0 else 'BEARISH' if self.market_trend < 0 else 'NEUTRAL'}[/]",
                    title="Trade Details",
                    border_style="cyan"
                )
                console.print(details_panel)
            else:
                print(f"Take profit: ${position.take_profit_price:.6f} (+{self.dynamic_params['take_profit_percent']:.1f}%)")
                print(f"Stop loss: ${position.stop_loss_price:.6f} (-{self.dynamic_params['stop_loss_percent']:.1f}%)")
                print(f"Max hold time: {position.target_hold_time} seconds")
                market_state = "Bullish" if self.market_trend > 0 else "Bearish" if self.market_trend < 0 else "Neutral"
                print(f"Market conditions: {market_state}")
                print("=========================\n")

            return True
            
        # LIVE TRADING MODE
        else:
            self.add_log_message(f"Executing buy for {token.symbol} ({reason})", "INFO")
            
            # Create transaction panel
            if RICH_ENABLED:
                buy_panel = Panel(
                    f"[bold red]🚨 EXECUTING LIVE BUY 🚨[/]\n\n"
                    f"[bold cyan]Token:[/] {token.symbol} ({token.name})\n"
                    f"[bold cyan]Reason:[/] {reason}\n"
                    f"[bold cyan]Price:[/] ${token.price_usd:.6f}\n"
                    f"[bold cyan]Amount:[/] {position_size} SOL (${position_size * self.sol_price_history[-1] if self.sol_price_history else position_size * 150:.2f})\n"
                    f"[bold cyan]Est. Price Impact:[/] {token.price_impact_estimate:.2f}%",
                    title="Live Transaction",
                    border_style="red"
                )
                console.print(buy_panel)
            else:
                print(f"\n🚨 EXECUTING LIVE BUY 🚨")
                print(f"Token: {token.symbol} ({token.name})")
                print(f"Reason: {reason}")
                print(f"Price: ${token.price_usd:.6f}")
                print(f"Amount: {position_size} SOL (${position_size * self.sol_price_history[-1] if self.sol_price_history else position_size * 150:.2f})")
                print(f"Estimated Price Impact: {token.price_impact_estimate:.2f}%")

            try:
                # Update blockhash before transaction
                blockhash = self.trader.force_update_blockhash()
                self.add_log_message(f"Updated blockhash: {blockhash[:16]}...", "INFO")

                # Execute trade via Jupiter swap
                start_time = time.time()
                
                # Show progress if using rich
                if RICH_ENABLED:
                    with Progress(
                        SpinnerColumn(),
                        TextColumn("[bold blue]Transaction:"),
                        BarColumn(bar_width=40),
                        TextColumn("[bold cyan]Executing..."),
                        console=console
                    ) as progress:
                        task = progress.add_task("Executing buy...", total=1.0)
                        
                        # Execute the swap
                        tx_sig = self.trader.execute_jupiter_swap(
                            WSOL_ADDRESS,
                            token.address,
                            position_size,
                            slippage_percent=SLIPPAGE_PERCENT,
                            priority_multiplier=PRIORITY_MULTIPLIER
                        )
                        
                        # Complete the task
                        progress.update(task, completed=1.0)
                else:
                    # Execute without visual progress
                    tx_sig = self.trader.execute_jupiter_swap(
                        WSOL_ADDRESS,
                        token.address,
                        position_size,
                        slippage_percent=SLIPPAGE_PERCENT,
                        priority_multiplier=PRIORITY_MULTIPLIER
                    )
                
                exec_time = time.time() - start_time
                self.add_log_message(f"Buy tx sent for {token.symbol} in {exec_time:.3f}s: {tx_sig[:16]}...", "INFO")

                # Wait for confirmation
                if RICH_ENABLED:
                    with Progress(
                        SpinnerColumn(),
                        TextColumn("[bold blue]Confirmation:"),
                        BarColumn(bar_width=40),
                        TimeElapsedColumn(),
                        TextColumn("[bold cyan]Waiting..."),
                        console=console
                    ) as progress:
                        task = progress.add_task("Waiting for confirmation...", total=None)
                        confirmed = self.trader.confirm_transaction(tx_sig, 15)  # 15 second timeout
                        progress.update(task, completed=1.0)
                else:
                    print("Waiting for confirmation...")
                    confirmed = self.trader.confirm_transaction(tx_sig, 15)  # 15 second timeout

                if confirmed:
                    self.add_log_message(f"Buy confirmed for {token.symbol}", "SUCCESS")
                    
                    if RICH_ENABLED:
                        console.print("[bold green]✅ Transaction confirmed![/]")
                    else:
                        print(f"✅ Transaction confirmed!")

                    # Create position
                    position = TradePosition(
                        token_symbol=token.symbol,
                        token_name=token.name,
                        token_address=token.address,
                        pair_address=token.pair_address,
                        entry_price=token.price_usd,
                        position_size_sol=position_size,
                        entry_time=time.time(),
                        token_volatility=token.volatility_score,
                        momentum_score=token.momentum_score,
                        transaction_id=tx_sig,
                        target_hold_time=self.dynamic_params["max_hold_time"]
                    )

                    # Set take profit based on current settings
                    position.take_profit_price = token.price_usd * (1 + (self.dynamic_params["take_profit_percent"] / 100))
                    position.stop_loss_price = token.price_usd * (1 - (self.dynamic_params["stop_loss_percent"] / 100))

                    # Add to active positions
                    self.active_positions[token.address] = position
                    self.trade_count += 1
                    self.daily_trade_count += 1
                    
                    # Update hourly stats
                    hour = datetime.now().hour
                    self.day_trades_by_hour[hour] = self.day_trades_by_hour.get(hour, 0) + 1
                    
                    # Update balance
                    self.current_balance = self.trader.get_sol_balance()

                    # Display trade details
                    if RICH_ENABLED:
                        details_panel = Panel(
                            f"[bold cyan]Take profit:[/] ${position.take_profit_price:.6f} (+{self.dynamic_params['take_profit_percent']:.1f}%)\n"
                            f"[bold cyan]Stop loss:[/] ${position.stop_loss_price:.6f} (-{self.dynamic_params['stop_loss_percent']:.1f}%)\n"
                            f"[bold cyan]Max hold time:[/] {position.target_hold_time} seconds\n"
                            f"[bold cyan]Market conditions:[/] [{'green' if self.market_trend > 0 else 'red' if self.market_trend < 0 else 'yellow'}]"
                            f"{'BULLISH' if self.market_trend > 0 else 'BEARISH' if self.market_trend < 0 else 'NEUTRAL'}[/]",
                            title="Trade Details",
                            border_style="cyan"
                        )
                        console.print(details_panel)
                    else:
                        print(f"Take profit: ${position.take_profit_price:.6f} (+{self.dynamic_params['take_profit_percent']:.1f}%)")
                        print(f"Stop loss: ${position.stop_loss_price:.6f} (-{self.dynamic_params['stop_loss_percent']:.1f}%)")
                        print(f"Max hold time: {position.target_hold_time} seconds")
                        market_state = "Bullish" if self.market_trend > 0 else "Bearish" if self.market_trend < 0 else "Neutral"
                        print(f"Market conditions: {market_state}")
                        print("=========================\n")

                    return True
                else:
                    self.add_log_message(f"Buy confirmation timeout for {token.symbol}", "ERROR")
                    if RICH_ENABLED:
                        console.print("[bold red]❌ Transaction confirmation timed out![/]")
                    else:
                        print("❌ Transaction confirmation timed out!")
                    return False

            except Exception as e:
                self.add_log_message(f"Error executing buy for {token.symbol}: {e}", "ERROR")
                if RICH_ENABLED:
                    console.print(f"[bold red]❌ Error:[/] {str(e)}")
                else:
                    print(f"❌ Error: {str(e)}")
                return False

    async def execute_sell(self, token_address: str) -> bool:
        """Execute a sell order for a token"""
        if token_address not in self.active_positions:
            return False

        position = self.active_positions[token_address]
        token = self.known_tokens.get(token_address)

        # SIMULATION MODE or DEMO_MODE
        if SIMULATION_MODE or DEMO_MODE:
            self.add_log_message(f"SIMULATION: Selling {position.token_symbol} ({position.exit_reason})", "SUCCESS")
            
            # Create transaction panel
            if RICH_ENABLED:
                sell_panel = Panel(
                    f"[bold green]SIMULATED SELL TRADE[/]\n\n"
                    f"[bold cyan]Token:[/] {position.token_symbol}\n"
                    f"[bold cyan]Reason:[/] {position.exit_reason}",
                    title="Transaction",
                    border_style="green"
                )
                console.print(sell_panel)
            else:
                print(f"\n=== SIMULATED SELL TRADE ===")
                print(f"Token: {position.token_symbol}")
                print(f"Reason: {position.exit_reason}")

            # Use current token price or position price if token not found
            exit_price = token.price_usd if token else position.current_price

            # Close position
            result = position.close_position(exit_price)
            self.closed_positions.append(position)
            del self.active_positions[token_address]

            # Update trading statistics
            if position.profit_loss_percent > 0:
                self.win_count += 1
                self.consecutive_losses = 0
            else:
                self.loss_count += 1
                self.consecutive_losses += 1
                self.loss_tokens[token_address] = {
                    "time": time.time(),
                    "symbol": position.token_symbol,
                    "percent": position.profit_loss_percent
                }

            # Update balance
            profit_loss_sol = position.position_size_sol * (position.profit_loss_percent / 100)
            self.current_balance += position.position_size_sol + profit_loss_sol
            self.total_profit_sol += profit_loss_sol

            # Update daily high/low balance
            if self.current_balance > self.daily_high_balance:
                self.daily_high_balance = self.current_balance
            if self.current_balance < self.daily_low_balance:
                self.daily_low_balance = self.current_balance

            # Add to temporary blacklist for losses
            if position.profit_loss_percent < 0:
                blacklist_seconds = min(1800, int(abs(position.profit_loss_percent) * 100))  # Scale with loss size
                self.temp_blacklist[token_address] = time.time() + blacklist_seconds
                self.add_log_message(f"Added {position.token_symbol} to blacklist for {blacklist_seconds/60:.1f} minutes", "INFO")

            # Display trade results
            if RICH_ENABLED:
                result_style = "green" if position.profit_loss_percent > 0 else "red"
                result_panel = Panel(
                    f"[bold cyan]Entry price:[/] ${position.entry_price:.6f}\n"
                    f"[bold cyan]Exit price:[/] ${position.exit_price:.6f}\n"
                    f"[bold cyan]P/L:[/] [{result_style}]{position.profit_loss_percent:+.2f}%[/]\n"
                    f"[bold cyan]P/L SOL:[/] [{result_style}]{profit_loss_sol:+.6f}[/]\n"
                    f"[bold cyan]Hold time:[/] {result['hold_time']:.1f} seconds",
                    title="Trade Results",
                    border_style=result_style
                )
                console.print(result_panel)
            else:
                print(f"Entry price: ${position.entry_price:.6f}")
                print(f"Exit price: ${position.exit_price:.6f}")
                print(f"P/L: {position.profit_loss_percent:+.2f}%")
                print(f"P/L SOL: {profit_loss_sol:+.6f}")
                print(f"Hold time: {result['hold_time']:.1f} seconds")
                print("===========================\n")

            return True
            
        # LIVE TRADING MODE
        else:
            self.add_log_message(f"Executing sell for {position.token_symbol} ({position.exit_reason})", "INFO")
            
            # Create transaction panel
            if RICH_ENABLED:
                sell_panel = Panel(
                    f"[bold red]🚨 EXECUTING LIVE SELL 🚨[/]\n\n"
                    f"[bold cyan]Token:[/] {position.token_symbol}\n"
                    f"[bold cyan]Reason:[/] {position.exit_reason}\n"
                    f"[bold cyan]Current P/L:[/] [{'green' if position.profit_loss_percent > 0 else 'red'}]{position.profit_loss_percent:+.2f}%[/]",
                    title="Live Transaction",
                    border_style="red"
                )
                console.print(sell_panel)
            else:
                print(f"\n🚨 EXECUTING LIVE SELL 🚨")
                print(f"Token: {position.token_symbol}")
                print(f"Reason: {position.exit_reason}")
                print(f"Current P/L: {position.profit_loss_percent:+.2f}%")

            try:
                # Get token balance to sell
                token_balance = self.trader.get_token_balance(token_address)

                if token_balance <= 0:
                    self.add_log_message(f"Zero balance for {position.token_symbol}", "ERROR")
                    if RICH_ENABLED:
                        console.print("[bold red]❌ Error:[/] No token balance found")
                    else:
                        print(f"❌ Error: No token balance found")

                    position.exit_reason = "ZERO_BALANCE"
                    result = position.close_position(position.current_price)
                    self.closed_positions.append(position)
                    del self.active_positions[token_address]
                    return False

                # Update blockhash before transaction
                blockhash = self.trader.force_update_blockhash()
                self.add_log_message(f"Updated blockhash: {blockhash[:16]}...", "INFO")

                # Sell slightly less than full balance to account for potential rounding issues
                amount_to_sell = token_balance * 0.98

                # Execute sell via Jupiter
                start_time = time.time()
                
                # Show progress if using rich
                if RICH_ENABLED:
                    with Progress(
                        SpinnerColumn(),
                        TextColumn("[bold blue]Transaction:"),
                        BarColumn(bar_width=40),
                        TextColumn("[bold cyan]Executing..."),
                        console=console
                    ) as progress:
                        task = progress.add_task("Executing sell...", total=1.0)
                        
                        # Execute the swap
                        tx_sig = self.trader.sell_token_for_sol_via_jupiter(
                            token_address,
                            amount_to_sell,
                            slippage_percent=SLIPPAGE_PERCENT,
                            priority_multiplier=PRIORITY_MULTIPLIER
                        )
                        
                        # Complete the task
                        progress.update(task, completed=1.0)
                else:
                    # Execute without visual progress
                    tx_sig = self.trader.sell_token_for_sol_via_jupiter(
                        token_address,
                        amount_to_sell,
                        slippage_percent=SLIPPAGE_PERCENT,
                        priority_multiplier=PRIORITY_MULTIPLIER
                    )
                
                exec_time = time.time() - start_time
                self.add_log_message(f"Sell tx sent for {position.token_symbol} in {exec_time:.3f}s: {tx_sig[:16]}...", "INFO")

                # Wait for confirmation
                if RICH_ENABLED:
                    with Progress(
                        SpinnerColumn(),
                        TextColumn("[bold blue]Confirmation:"),
                        BarColumn(bar_width=40),
                        TimeElapsedColumn(),
                        TextColumn("[bold cyan]Waiting..."),
                        console=console
                    ) as progress:
                        task = progress.add_task("Waiting for confirmation...", total=None)
                        confirmed = self.trader.confirm_transaction(tx_sig, 15)  # 15 second timeout
                        progress.update(task, completed=1.0)
                else:
                    print("Waiting for confirmation...")
                    confirmed = self.trader.confirm_transaction(tx_sig, 15)  # 15 second timeout

                if confirmed:
                    self.add_log_message(f"Sell confirmed for {position.token_symbol}", "SUCCESS")
                    if RICH_ENABLED:
                        console.print("[bold green]✅ Transaction confirmed![/]")
                    else:
                        print(f"✅ Transaction confirmed!")

                    # Use current token price or position price if token not found
                    exit_price = token.price_usd if token else position.current_price

                    # Close position
                    result = position.close_position(exit_price, tx_sig)
                    self.closed_positions.append(position)
                    del self.active_positions[token_address]

                    # Update trading statistics
                    if position.profit_loss_percent > 0:
                        self.win_count += 1
                        self.consecutive_losses = 0
                    else:
                        self.loss_count += 1
                        self.consecutive_losses += 1
                        self.loss_tokens[token_address] = {
                            "time": time.time(),
                            "symbol": position.token_symbol,
                            "percent": position.profit_loss_percent
                        }

                    # Update balance
                    self.current_balance = self.trader.get_sol_balance()
                    profit_loss_sol = position.position_size_sol * (position.profit_loss_percent / 100)
                    self.total_profit_sol += profit_loss_sol

                    # Update daily high/low balance
                    if self.current_balance > self.daily_high_balance:
                        self.daily_high_balance = self.current_balance
                    if self.current_balance < self.daily_low_balance:
                        self.daily_low_balance = self.current_balance

                    # Add to temporary blacklist for losses
                    if position.profit_loss_percent < 0:
                        blacklist_seconds = min(1800, int(abs(position.profit_loss_percent) * 100))  # Scale with loss size
                        self.temp_blacklist[token_address] = time.time() + blacklist_seconds
                        self.add_log_message(f"Added {position.token_symbol} to blacklist for {blacklist_seconds/60:.1f} minutes", "INFO")

                    # Display trade results
                    if RICH_ENABLED:
                        result_style = "green" if position.profit_loss_percent > 0 else "red"
                        result_panel = Panel(
                            f"[bold cyan]Entry price:[/] ${position.entry_price:.6f}\n"
                            f"[bold cyan]Exit price:[/] ${position.exit_price:.6f}\n"
                            f"[bold cyan]P/L:[/] [{result_style}]{position.profit_loss_percent:+.2f}%[/]\n"
                            f"[bold cyan]P/L SOL:[/] [{result_style}]{profit_loss_sol:+.6f}[/]\n"
                            f"[bold cyan]Hold time:[/] {result['hold_time']:.1f} seconds",
                            title="Trade Results",
                            border_style=result_style
                        )
                        console.print(result_panel)
                    else:
    async def main():
    """Main function to run the Solana High-Frequency Trading bot"""
    # Create and initialize the trader
    trader = SolanaHighFrequencyTrader()
    initialization_success = await trader.initialize()
    
    if not initialization_success:
        logger.error("Failed to initialize trader. Exiting.")
        return
    
    # Set up Live UI with Rich if available
    if RICH_ENABLED:
        # Create layout for Live UI
        layout = Layout()
        layout.split(
            Layout(name="header", size=3),
            Layout(name="main", ratio=1),
            Layout(name="footer", size=7)
        )
        
        # Split main area into three columns
        layout["main"].split_row(
            Layout(name="left", ratio=2),
            Layout(name="right", ratio=3)
        )
        
        # Split left column into market stats and positions
        layout["left"].split(
            Layout(name="market_stats", ratio=1),
            Layout(name="positions", ratio=2)
        )
        
        # Split right column into tokens and logs
        layout["right"].split(
            Layout(name="tokens", ratio=1),
            Layout(name="logs", ratio=1)
        )
        
        # Create Live display
        trader.live_ui = Live(layout, refresh_per_second=2, screen=True)
        trader.live_ui.start()
    
    try:
        # Log startup
        trader.add_log_message("Solana HFT Bot started successfully", "SUCCESS")
        trader.add_log_message(f"Using {'SIMULATION' if SIMULATION_MODE else 'LIVE'} trading mode", 
                              "WARNING" if SIMULATION_MODE else "INFO")
        
        # Main event loop
        last_market_check = 0
        last_ui_update = 0
        
        while trader.running and not trader.shutdown_event.is_set():
            current_time = time.time()
            
            # Update UI
            if RICH_ENABLED and trader.live_ui and current_time - last_ui_update >= UI_UPDATE_INTERVAL:
                layout["header"].update(render_header(trader))
                layout["market_stats"].update(render_market_stats(trader))
                layout["positions"].update(render_positions(trader))
                layout["tokens"].update(render_token_list(trader))
                layout["logs"].update(render_log_messages(trader))
                last_ui_update = current_time
            
            # Check market conditions occasionally
            if current_time - last_market_check >= 60:  # Every minute
                await trader.check_market_conditions()
                last_market_check = current_time
            
            # Always check positions frequently
            if trader.active_positions and current_time - trader.last_position_check >= POSITION_CHECK_INTERVAL:
                await trader.update_positions()
                trader.last_position_check = current_time
            
            # Scan market for new opportunities
            if current_time - trader.last_scan_time >= SCAN_INTERVAL:
                await trader.scan_market()
                trader.last_scan_time = current_time
                
                # Look for entry signals
                await trader.check_for_entry_signals()
            
            # Check for day reset if it's past midnight
            if datetime.now().hour == 0 and datetime.now().minute == 0:
                if current_time - trader.daily_start_time > 3600:  # Only reset once per hour
                    trader.add_log_message("New trading day started, resetting daily stats", "INFO")
                    trader.daily_start_time = current_time
                    trader.daily_start_balance = trader.current_balance
                    trader.daily_high_balance = trader.current_balance
                    trader.daily_low_balance = trader.current_balance
                    trader.daily_trade_count = 0
                    trader.day_trades_by_hour = {}
            
            # Small sleep to prevent high CPU usage
            await asyncio.sleep(0.1)
    
    except KeyboardInterrupt:
        trader.add_log_message("Shutdown requested by user", "WARNING")
    except Exception as e:
        trader.add_log_message(f"Fatal error: {e}", "ERROR")
        logger.error(traceback.format_exc())
    finally:
        # Clean shutdown
        trader.running = False
        trader.shutdown_event.set()
        
        # Close all positions if requested
        if trader.active_positions:
            trader.add_log_message("Closing all active positions before shutdown", "WARNING")
            for token_address in list(trader.active_positions.keys()):
                try:
                    # Add "SHUTDOWN" as reason
                    trader.active_positions[token_address].exit_reason = "SHUTDOWN"
                    await trader.execute_sell(token_address)
                except Exception as e:
                    trader.add_log_message(f"Error closing position: {e}", "ERROR")
        
        # Display final statistics
        trader.add_log_message(f"Session summary: {trader.win_count} wins, {trader.loss_count} losses", "INFO")
        profit_loss = trader.current_balance - trader.initial_balance
        trader.add_log_message(f"Total P/L: {profit_loss:.6f} SOL ({(profit_loss/trader.initial_balance)*100:.2f}%)", 
                              "SUCCESS" if profit_loss >= 0 else "ERROR")
        
        # Stop live UI
        if RICH_ENABLED and trader.live_ui:
            trader.live_ui.stop()
        
        trader.add_log_message("Bot shutdown complete", "INFO")
        
        # Final stats display for non-live mode
        if RICH_ENABLED and not trader.live_ui:
            display_final_statistics(trader)
        else:
            print("\n=== Final Statistics ===")
            print(f"Total trades: {trader.trade_count}")
            print(f"Win/Loss: {trader.win_count}/{trader.loss_count}")
            print(f"Win rate: {(trader.win_count/max(1, trader.trade_count))*100:.2f}%")
            print(f"Starting balance: {trader.initial_balance:.6f} SOL")
            print(f"Final balance: {trader.current_balance:.6f} SOL")
            print(f"Profit/Loss: {profit_loss:.6f} SOL ({(profit_loss/trader.initial_balance)*100:.2f}%)")
            print("=======================")


def render_header(trader):
    """Render the header panel with bot status"""
    if not RICH_ENABLED:
        return None
        
    status = "RUNNING" if trader.running and not trader.paused else "PAUSED" if trader.paused else "STOPPED"
    status_color = "green" if status == "RUNNING" else "yellow" if status == "PAUSED" else "red"
    
    # Create header panel
    mode = "DEMO" if DEMO_MODE else "SIMULATION" if SIMULATION_MODE else "LIVE TRADING"
    mode_color = "yellow" if mode == "DEMO" or mode == "SIMULATION" else "red"
    
    header = Panel(
        f"[bold white]Solana High-Frequency Trading Bot[/] | "
        f"Status: [bold {status_color}]{status}[/] | "
        f"Mode: [bold {mode_color}]{mode}[/] | "
        f"Balance: [bold green]{trader.current_balance:.4f} SOL[/] | "
        f"P/L: [bold {'green' if trader.current_balance > trader.initial_balance else 'red'}]"
        f"{trader.current_balance - trader.initial_balance:+.4f} SOL "
        f"({((trader.current_balance / trader.initial_balance) - 1) * 100:+.2f}%)[/]",
        border_style="blue",
        title="[bold cyan]HFT Bot[/]"
    )
    
    return header


def render_market_stats(trader):
    """Render market statistics panel"""
    if not RICH_ENABLED:
        return None
        
    # Get current SOL price
    sol_price = trader.sol_price_history[-1] if trader.sol_price_history else 0
    
    # Create market stats panel
    market_trend = "BULLISH" if trader.market_trend > 0 else "BEARISH" if trader.market_trend < 0 else "NEUTRAL"
    trend_color = "green" if market_trend == "BULLISH" else "red" if market_trend == "BEARISH" else "yellow"
    
    # Calculate win rate
    win_rate = (trader.win_count / max(1, trader.trade_count)) * 100
    
    stats_text = Text()
    stats_text.append("Market Stats\n", style="bold cyan")
    stats_text.append(f"SOL Price: ", style="dim")
    stats_text.append(f"${sol_price:.2f}\n", style="bold white")
    stats_text.append(f"Market Trend: ", style="dim")
    stats_text.append(f"{market_trend}\n", style=f"bold {trend_color}")
    stats_text.append(f"Today's Trades: ", style="dim")
    stats_text.append(f"{trader.daily_trade_count}\n", style="bold white")
    stats_text.append(f"Win Rate: ", style="dim")
    stats_text.append(f"{win_rate:.1f}%\n", style=f"bold {'green' if win_rate >= 50 else 'red'}")
    stats_text.append(f"Active Positions: ", style="dim")
    stats_text.append(f"{len(trader.active_positions)}/{MAX_ACTIVE_POSITIONS}\n", style="bold white")
    
    stats_panel = Panel(
        stats_text,
        border_style="blue",
        title="[bold blue]Market Overview[/]",
        padding=(1, 2)
    )
    
    return stats_panel


def render_positions(trader):
    """Render active positions panel"""
    if not RICH_ENABLED:
        return None
        
    positions_text = Text()
    
    if not trader.active_positions:
        positions_text.append("\n No active positions\n\n", style="italic")
    else:
        # Create a table for positions
        table = Table(show_header=True, header_style="bold blue", box=box.SIMPLE)
        table.add_column("Token", style="cyan", no_wrap=True)
        table.add_column("Entry", justify="right")
        table.add_column("Current", justify="right")
        table.add_column("P/L %", justify="right")
        table.add_column("Time", justify="right")
        
        for addr, pos in trader.active_positions.items():
            # Calculate values
            profit_pct = pos.profit_loss_percent
            profit_color = "green" if profit_pct > 0 else "red"
            hold_time = time.time() - pos.entry_time
            hold_pct = min(100, (hold_time / pos.target_hold_time) * 100)
            
            # Add row
            table.add_row(
                pos.token_symbol,
                f"${pos.entry_price:.6f}",
                f"${pos.current_price:.6f}",
                f"[{profit_color}]{profit_pct:+.2f}%[/]",
                f"{int(hold_time)}s/{pos.target_hold_time}s"
            )
        
        positions_text.append(table)
    
    positions_panel = Panel(
        positions_text,
        border_style="green",
        title=f"[bold green]Active Positions ({len(trader.active_positions)})[/]",
        padding=(1, 1)
    )
    
    return positions_panel


def render_token_list(trader):
    """Render token list panel"""
    if not RICH_ENABLED:
        return None
        
    tokens_text = Text()
    
    if not trader.high_potential_tokens:
        tokens_text.append("\n No trading opportunities found\n\n", style="italic")
    else:
        # Create table for tokens
        table = Table(show_header=True, header_style="bold magenta", box=box.SIMPLE)
        table.add_column("Token", style="cyan", no_wrap=True)
        table.add_column("Price", justify="right")
        table.add_column("5m Chg", justify="right")
        table.add_column("Momentum", justify="right")
        
        # Show up to 10 tokens
        for token in trader.high_potential_tokens[:10]:
            momentum_color = "green" if token.momentum_score > 6 else "yellow"
            price_change_color = "green" if token.price_change_5m > 0 else "red"
            
            table.add_row(
                token.symbol,
                f"${token.price_usd:.6f}",
                f"[{price_change_color}]{token.price_change_5m:+.2f}%[/]",
                f"[{momentum_color}]{token.momentum_score:.1f}[/]"
            )
            
        tokens_text.append(table)
    
    tokens_panel = Panel(
        tokens_text,
        border_style="magenta",
        title=f"[bold magenta]Top Trading Opportunities ({len(trader.high_potential_tokens)})[/]",
        padding=(1, 1)
    )
    
    return tokens_panel


def render_log_messages(trader):
    """Render log messages panel"""
    if not RICH_ENABLED:
        return None
    
    log_panel = Panel(
        "\n".join([str(msg[1]) for msg in trader.message_log]),
        border_style="cyan",
        title="[bold cyan]Activity Log[/]",
        padding=(1, 1)
    )
    
    return log_panel


def display_final_statistics(trader):
    """Display final statistics at the end of a session"""
    if not RICH_ENABLED:
        return
        
    # Create summary panel
    profit_loss = trader.current_balance - trader.initial_balance
    win_rate = (trader.win_count / max(1, trader.trade_count)) * 100
    
    summary = Panel(
        f"[bold cyan]Session Duration:[/] {time.strftime('%H:%M:%S', time.gmtime(time.time() - trader.startup_time))}\n"
        f"[bold cyan]Total Trades:[/] {trader.trade_count}\n"
        f"[bold cyan]Wins/Losses:[/] {trader.win_count}/{trader.loss_count}\n"
        f"[bold cyan]Win Rate:[/] [bold {'green' if win_rate >= 50 else 'red'}]{win_rate:.2f}%[/]\n"
        f"[bold cyan]Starting Balance:[/] {trader.initial_balance:.6f} SOL\n"
        f"[bold cyan]Final Balance:[/] {trader.current_balance:.6f} SOL\n"
        f"[bold cyan]Profit/Loss:[/] [bold {'green' if profit_loss >= 0 else 'red'}]{profit_loss:+.6f} SOL "
        f"({((trader.current_balance / trader.initial_balance) - 1) * 100:+.2f}%)[/]",
        title="[bold white]Trading Session Summary[/]",
        border_style="cyan",
        padding=(1, 2)
    )
    
    console.print(summary)
    
    # Display closed positions if there are any
    if trader.closed_positions:
        # Create table for positions
        table = Table(title="Closed Positions", show_header=True, header_style="bold blue", box=box.SIMPLE)
        table.add_column("Token", style="cyan", no_wrap=True)
        table.add_column("Entry Price", justify="right")
        table.add_column("Exit Price", justify="right")
        table.add_column("P/L %", justify="right")
        table.add_column("Hold Time", justify="right")
        table.add_column("Exit Reason", no_wrap=True)
        
        # Sort by profit/loss
        sorted_positions = sorted(trader.closed_positions, key=lambda p: p.profit_loss_percent, reverse=True)
        
        for pos in sorted_positions:
            # Calculate values
            profit_color = "green" if pos.profit_loss_percent > 0 else "red"
            hold_time = pos.exit_time - pos.entry_time if pos.exit_time > 0 else 0
            
            # Add row
            table.add_row(
                pos.token_symbol,
                f"${pos.entry_price:.6f}",
                f"${pos.exit_price:.6f}",
                f"[{profit_color}]{pos.profit_loss_percent:+.2f}%[/]",
                f"{int(hold_time)}s",
                pos.exit_reason
            )
        
        console.print(table)


if __name__ == "__main__":
    try:
        # Run the main function using asyncio
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\nShutdown requested. Exiting...")
    except Exception as e:
        print(f"\nFatal error: {e}")
        logger.error(traceback.format_exc())
        if RICH_ENABLED:
            console.print_exception() write the full entire script back just fix the spacing if you dont write it all every line of code i will be in the same situation as i am now the whole idea is so that when i copy paste it theres no spacing iissues okay ? so write all of it please my eyes are going back