Sfoglia il codice sorgente

Remove deprecated scripts and files to streamline the project structure.

- Deleted the cleanup_status.py and test_simplified_position_tracker.py scripts, which are no longer needed after the transition to a simplified position tracking system.
- Removed demo_stats.py, manual_trading_bot.py, simple_bot.py, simple_chat_id.py, strategy_bot.py, and other utility scripts that are obsolete or redundant, enhancing project maintainability.
- Updated the external_event_monitor.py and market_monitor.py to improve error handling for position fetching, ensuring robustness in data retrieval.
- Refactored simple_position_tracker.py to include better logging for API failures when fetching exchange positions, improving reliability.
Carles Sentis 1 settimana fa
parent
commit
864697565f

+ 0 - 140
scripts/cleanup_status.py

@@ -1,140 +0,0 @@
-#!/usr/bin/env python3
-"""
-Cleanup Status Script
-
-Shows what was removed, what was kept, and the benefits of the cleanup.
-"""
-
-import os
-
-def print_cleanup_report():
-    """Print a comprehensive cleanup report."""
-    
-    print("""
-🧹 CODEBASE CLEANUP REPORT
-==========================
-
-✅ PHASE 1 CLEANUP COMPLETED:
-
-🗑️  REMOVED/DISABLED COMPONENTS:
-• PositionSynchronizer - No longer imported or used
-• Complex external trade monitoring - Disabled in market_monitor.py
-• Auto-sync startup complexity - Simplified tracker handles it
-• Redundant position sync logic - All in one place now
-
-✅ KEPT COMPONENTS:
-• OrderFillProcessor - Still needed for bot order fills
-• Price alarms - Working fine, kept from ExternalEventMonitor
-• Risk cleanup manager - Still handles risk management
-• Drawdown monitor - Independent monitoring component
-• Simplified position tracker - New, clean implementation
-
-📊 ARCHITECTURE COMPARISON:
-
-BEFORE (Complex):
-├── ExternalEventMonitor._check_external_trades() (300+ lines)
-├── PositionSynchronizer (500+ lines)
-├── Complex auto-sync logic (100+ lines)
-├── Multiple notification paths
-└── Over-engineered state management
-
-AFTER (Simplified):
-├── SimplePositionTracker (350+ lines)
-├── PositionMonitorIntegration (50+ lines)
-├── Single notification method
-├── Clear edge case handling
-└── Reuses existing infrastructure
-
-🎯 CLEANUP BENEFITS:
-
-✅ COMPLEXITY REDUCTION:
-• Removed PositionSynchronizer import and initialization
-• Disabled complex external trade logic
-• Simplified startup sequence
-• Single responsibility per component
-
-✅ MAINTAINABILITY:
-• Clear separation of concerns
-• Easier debugging and testing
-• Predictable notification flow
-• Reduced interdependencies
-
-✅ RELIABILITY:
-• No more missed notifications
-• Consistent behavior across all scenarios
-• Better error handling
-• Comprehensive edge case coverage
-
-✅ PERFORMANCE:
-• Faster monitoring cycles
-• Reduced complexity
-• Simpler logic flow
-• Lower maintenance overhead
-
-🚀 WHAT'S ACTIVE NOW:
-
-✅ ACTIVE COMPONENTS:
-• SimplePositionTracker - Position change detection & notifications
-• OrderFillProcessor - Bot order fill processing
-• ExternalEventMonitor._check_price_alarms() - Price alerts only
-• RiskCleanupManager - Risk management and cleanup
-• DrawdownMonitor - Balance tracking
-
-🗑️ DISABLED/REMOVED:
-• ExternalEventMonitor._check_external_trades() - Commented out
-• PositionSynchronizer - Removed from imports and initialization
-• Complex startup auto-sync - Replaced with simple logic
-
-📋 VALIDATION CHECKLIST:
-• ✅ Position opened notifications working
-• ✅ Position closed notifications working  
-• ✅ Position size change notifications working
-• ✅ Pending stop loss handling working
-• ✅ Orphaned pending trade cleanup working
-• ✅ Price alarms still working
-• ✅ Risk management still working
-• ✅ All edge cases covered
-
-🚀 NEXT STEPS (Optional Phase 2):
-
-After more validation, you can:
-• Remove _check_external_trades method entirely from ExternalEventMonitor
-• Clean up unused imports in external_event_monitor.py
-• Delete position_synchronizer.py file entirely
-• Add configuration options for simplified tracker
-
-💡 The simplified architecture is now production-ready!
-""")
-
-def print_code_comparison():
-    """Print before/after code comparison."""
-    print("""
-📝 CODE CHANGES SUMMARY:
-
-market_monitor.py:
-- Removed: from src.monitoring.position_synchronizer import PositionSynchronizer
-- Removed: self.position_synchronizer = PositionSynchronizer(...)
-- Disabled: await self.external_event_monitor._check_external_trades()
-- Disabled: await self.position_synchronizer._auto_sync_orphaned_positions()
-+ Added: from src.monitoring.position_monitor_integration import PositionMonitorIntegration
-+ Added: self.position_monitor_integration = PositionMonitorIntegration(...)
-+ Added: await self.position_monitor_integration.run_monitoring_cycle()
-
-NEW FILES:
-+ simple_position_tracker.py (350+ lines) - Core position tracking logic
-+ position_monitor_integration.py (50+ lines) - Integration layer
-
-RESULT:
-• 📉 Complexity: -75%
-• 📈 Reliability: +100%
-• 📈 Maintainability: +200%
-• 📈 Test Coverage: +100%
-""")
-
-if __name__ == "__main__":
-    print_cleanup_report()
-    print_code_comparison()
-    
-    print("\n🎉 Cleanup Phase 1 Complete!")
-    print("💡 The simplified monitoring system is now active and ready!")
-    print("🔥 No more missed notifications, complex debugging, or over-engineering!") 

+ 0 - 182
scripts/test_simplified_position_tracker.py

@@ -1,182 +0,0 @@
-#!/usr/bin/env python3
-"""
-Test script for the simplified position tracker.
-
-This script validates that the simplified position tracker:
-1. Detects position changes correctly
-2. Sends appropriate notifications
-3. Handles pending stop losses properly
-"""
-
-import asyncio
-import sys
-import os
-import logging
-
-# Add project root to path
-sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
-
-from src.monitoring.simple_position_tracker import SimplePositionTracker
-from src.trading.trading_engine import TradingEngine
-from src.notifications.notification_manager import NotificationManager
-
-# Set up logging
-logging.basicConfig(
-    level=logging.INFO,
-    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
-)
-logger = logging.getLogger(__name__)
-
-class MockNotificationManager:
-    """Mock notification manager for testing."""
-    
-    async def send_generic_notification(self, message: str):
-        """Print notification instead of sending."""
-        print(f"\n📨 NOTIFICATION:\n{message}\n")
-
-async def test_simplified_position_tracker():
-    """Test the simplified position tracker."""
-    try:
-        logger.info("🧪 Starting simplified position tracker test")
-        
-        # Initialize components
-        trading_engine = TradingEngine()
-        notification_manager = MockNotificationManager()
-        
-        # Create simplified position tracker
-        tracker = SimplePositionTracker(trading_engine, notification_manager)
-        
-        logger.info("✅ Components initialized successfully")
-        
-        # Test position change detection
-        logger.info("🔍 Testing position change detection...")
-        await tracker.check_all_position_changes()
-        
-        logger.info("✅ Position change detection completed")
-        
-        # Get current positions for reference
-        exchange_positions = trading_engine.get_positions() or []
-        db_positions = trading_engine.get_stats().get_open_positions() if trading_engine.get_stats() else []
-        
-        logger.info(f"📊 Current state:")
-        logger.info(f"  Exchange positions: {len(exchange_positions)}")
-        logger.info(f"  DB positions: {len(db_positions)}")
-        
-        for pos in exchange_positions:
-            symbol = pos.get('symbol')
-            contracts = pos.get('contracts', 0)
-            logger.info(f"    Exchange: {symbol} = {contracts}")
-        
-        for pos in db_positions:
-            symbol = pos.get('symbol')
-            size = pos.get('current_position_size', 0)
-            status = pos.get('status')
-            logger.info(f"    DB: {symbol} = {size} ({status})")
-        
-        logger.info("🎉 Test completed successfully!")
-        
-    except Exception as e:
-        logger.error(f"❌ Test failed: {e}")
-        raise
-
-async def test_pending_stop_losses():
-    """Test pending stop loss handling."""
-    try:
-        logger.info("🧪 Testing pending stop loss handling")
-        
-        trading_engine = TradingEngine()
-        notification_manager = MockNotificationManager()
-        tracker = SimplePositionTracker(trading_engine, notification_manager)
-        
-        # Check pending SLs
-        stats = trading_engine.get_stats()
-        if stats:
-            pending_sls = stats.get_pending_stop_loss_activations()
-            logger.info(f"📋 Found {len(pending_sls)} pending stop losses")
-            
-            for sl in pending_sls:
-                symbol = sl.get('symbol')
-                stop_price = sl.get('stop_loss_price')
-                logger.info(f"  Pending SL: {symbol} @ {stop_price}")
-        
-        # Test SL handling
-        await tracker._handle_pending_stop_losses(stats)
-        
-        logger.info("✅ Pending stop loss test completed")
-        
-    except Exception as e:
-        logger.error(f"❌ Pending SL test failed: {e}")
-        raise
-
-async def test_orphaned_pending_trades():
-    """Test orphaned pending trades cleanup."""
-    try:
-        logger.info("🧪 Testing orphaned pending trades handling")
-        
-        trading_engine = TradingEngine()
-        notification_manager = MockNotificationManager()
-        tracker = SimplePositionTracker(trading_engine, notification_manager)
-        
-        # Check pending trades
-        stats = trading_engine.get_stats()
-        if stats:
-            pending_trades = stats.get_trades_by_status('pending')
-            logger.info(f"📋 Found {len(pending_trades)} pending trades")
-            
-            for trade in pending_trades:
-                symbol = trade.get('symbol')
-                lifecycle_id = trade.get('trade_lifecycle_id')
-                entry_order_id = trade.get('entry_order_id')
-                logger.info(f"  Pending trade: {symbol} (Lifecycle: {lifecycle_id[:8]}, Order: {entry_order_id})")
-        
-        # Test orphaned trade handling
-        await tracker._handle_orphaned_pending_trades(stats)
-        
-        logger.info("✅ Orphaned pending trades test completed")
-        
-    except Exception as e:
-        logger.error(f"❌ Orphaned pending trades test failed: {e}")
-        raise
-
-def print_status_comparison():
-    """Print comparison between simplified and complex approaches."""
-    print("""
-🎯 SIMPLIFIED POSITION TRACKER vs COMPLEX EXTERNAL EVENT MONITOR
-
-✅ SIMPLIFIED APPROACH:
-• Single method: check_all_position_changes()
-• Clear logic: Exchange positions ↔ DB positions
-• Always sends notifications
-• Simple pending SL handling
-• ~280 lines of code
-• Uses existing trades table and managers
-
-❌ COMPLEX APPROACH:
-• Multiple interacting methods
-• Complex fill analysis and state tracking  
-• Missed notifications (auto-sync gap)
-• Complicated order tracking
-• ~750+ lines of code
-• Over-engineered state management
-
-🎉 BENEFITS OF SIMPLIFICATION:
-1. No more missed notifications
-2. Easier to understand and maintain
-3. Reuses existing infrastructure
-4. Clear separation of concerns
-5. Reliable position state tracking
-""")
-
-if __name__ == "__main__":
-    async def main():
-        print_status_comparison()
-        
-        # Run tests
-        await test_simplified_position_tracker()
-        await test_pending_stop_losses()
-        await test_orphaned_pending_trades()
-        
-        print("\n🎉 All tests completed successfully!")
-        print("\n💡 The simplified position tracker is ready to replace the complex external event monitor!")
-    
-    asyncio.run(main()) 

+ 61 - 30
src/monitoring/external_event_monitor.py

@@ -25,6 +25,14 @@ class ExternalEventMonitor:
         self.last_processed_trade_time: Optional[datetime] = None
         # Add necessary initializations, potentially loading last_processed_trade_time
 
+    def _safe_get_positions(self) -> Optional[List[Dict[str, Any]]]:
+        """Safely get positions from trading engine, returning None on API failures instead of empty list."""
+        try:
+            return self.trading_engine.get_positions()
+        except Exception as e:
+            logger.warning(f"⚠️ Failed to fetch positions in external event monitor: {e}")
+            return None
+
     async def _check_price_alarms(self):
         """Check price alarms and trigger notifications."""
         try:
@@ -94,7 +102,11 @@ class ExternalEventMonitor:
         """
         try:
             # Get current position from exchange
-            current_positions = self.trading_engine.get_positions() or []
+            current_positions = self._safe_get_positions()
+            if current_positions is None:
+                logger.warning(f"⚠️ Failed to fetch positions for {full_symbol} analysis - returning external_unmatched")
+                return 'external_unmatched'
+            
             current_exchange_position = None
             for pos in current_positions:
                 if pos.get('symbol') == full_symbol:
@@ -231,7 +243,11 @@ class ExternalEventMonitor:
                 position_side = existing_lc.get('position_side', 'unknown').upper()
                 previous_size = existing_lc.get('current_position_size', 0)
                 # Get current size from exchange
-                current_positions = self.trading_engine.get_positions() or []
+                current_positions = self._safe_get_positions()
+                if current_positions is None:
+                    # Skip notification if we can't get position data
+                    logger.warning(f"⚠️ Failed to fetch positions for notification - skipping {action_type} notification")
+                    return
                 current_size = 0
                 for pos in current_positions:
                     if pos.get('symbol') == full_symbol:
@@ -262,7 +278,11 @@ class ExternalEventMonitor:
                 entry_price = existing_lc.get('entry_price', 0)
                 
                 # Get current size from exchange
-                current_positions = self.trading_engine.get_positions() or []
+                current_positions = self._safe_get_positions()
+                if current_positions is None:
+                    # Skip notification if we can't get position data
+                    logger.warning(f"⚠️ Failed to fetch positions for notification - skipping {action_type} notification")
+                    return
                 current_size = 0
                 for pos in current_positions:
                     if pos.get('symbol') == full_symbol:
@@ -585,7 +605,10 @@ class ExternalEventMonitor:
                         
                         # If no lifecycle exists but we have a position on exchange, try to auto-sync first
                         if not existing_lc:
-                            current_positions = self.trading_engine.get_positions() or []
+                            current_positions = self._safe_get_positions()
+                            if current_positions is None:
+                                logger.warning("⚠️ Failed to fetch positions for external trade detection - skipping this fill")
+                                continue
                             exchange_position = None
                             for pos in current_positions:
                                 if pos.get('symbol') == full_symbol:
@@ -608,31 +631,36 @@ class ExternalEventMonitor:
                         # Additional debug logging for position changes
                         if existing_lc:
                             previous_size = existing_lc.get('current_position_size', 0)
-                            current_positions = self.trading_engine.get_positions() or []
-                            current_size = 0
-                            for pos in current_positions:
-                                if pos.get('symbol') == full_symbol:
-                                    current_size = abs(float(pos.get('contracts', 0)))
-                                    break
-                            logger.info(f"📊 Position size change: {previous_size} -> {current_size} (diff: {current_size - previous_size})")
-                            logger.info(f"🎯 Expected change based on fill: {'+' if side_from_fill.lower() == 'buy' else '-'}{amount_from_fill}")
-                            
-                            # Check if this might be a position decrease that was misclassified
-                            if (action_type == 'external_unmatched' and 
-                                existing_lc.get('position_side') == 'long' and 
-                                side_from_fill.lower() == 'sell' and 
-                                current_size < previous_size):
-                                logger.warning(f"⚠️ Potential misclassification: {full_symbol} {side_from_fill} looks like position decrease but classified as external_unmatched")
-                                # Force re-check with proper parameters
-                                action_type = 'position_decreased'
-                                logger.info(f"🔄 Corrected action_type to: {action_type}")
-                            elif (action_type == 'external_unmatched' and 
-                                  existing_lc.get('position_side') == 'long' and 
-                                  side_from_fill.lower() == 'buy' and 
-                                  current_size > previous_size):
-                                logger.warning(f"⚠️ Potential misclassification: {full_symbol} {side_from_fill} looks like position increase but classified as external_unmatched")
-                                action_type = 'position_increased'
-                                logger.info(f"🔄 Corrected action_type to: {action_type}")
+                            current_positions = self._safe_get_positions()
+                            if current_positions is None:
+                                logger.warning("⚠️ Failed to fetch positions for debug logging - skipping debug info")
+                                # Set defaults to avoid reference errors
+                                current_size = previous_size
+                            else:
+                                current_size = 0
+                                for pos in current_positions:
+                                    if pos.get('symbol') == full_symbol:
+                                        current_size = abs(float(pos.get('contracts', 0)))
+                                        break
+                                logger.info(f"📊 Position size change: {previous_size} -> {current_size} (diff: {current_size - previous_size})")
+                                logger.info(f"🎯 Expected change based on fill: {'+' if side_from_fill.lower() == 'buy' else '-'}{amount_from_fill}")
+                                
+                                # Check if this might be a position decrease that was misclassified
+                                if (action_type == 'external_unmatched' and 
+                                    existing_lc.get('position_side') == 'long' and 
+                                    side_from_fill.lower() == 'sell' and 
+                                    current_size < previous_size):
+                                    logger.warning(f"⚠️ Potential misclassification: {full_symbol} {side_from_fill} looks like position decrease but classified as external_unmatched")
+                                    # Force re-check with proper parameters
+                                    action_type = 'position_decreased'
+                                    logger.info(f"🔄 Corrected action_type to: {action_type}")
+                                elif (action_type == 'external_unmatched' and 
+                                      existing_lc.get('position_side') == 'long' and 
+                                      side_from_fill.lower() == 'buy' and 
+                                      current_size > previous_size):
+                                    logger.warning(f"⚠️ Potential misclassification: {full_symbol} {side_from_fill} looks like position increase but classified as external_unmatched")
+                                    action_type = 'position_increased'
+                                    logger.info(f"🔄 Corrected action_type to: {action_type}")
                         
                         if action_type == 'position_opened':
                             # Create new lifecycle for external position
@@ -697,7 +725,10 @@ class ExternalEventMonitor:
                         
                         elif action_type in ['position_increased', 'position_decreased'] and existing_lc:
                             # Update lifecycle position size and send notification
-                            current_positions = self.trading_engine.get_positions() or []
+                            current_positions = self._safe_get_positions()
+                            if current_positions is None:
+                                logger.warning("⚠️ Failed to fetch positions for size update - skipping position change processing")
+                                continue
                             new_size = 0
                             for pos in current_positions:
                                 if pos.get('symbol') == full_symbol:

+ 14 - 3
src/monitoring/market_monitor.py

@@ -165,7 +165,10 @@ class MarketMonitor:
             self.cache.last_known_orders = {order.get('id') for order in orders if order.get('id')}
             logger.info(f"📋 Initialized cache with {len(orders)} open orders for first cycle comparison")
 
-            positions = self.trading_engine.get_positions() or []
+            positions = self.trading_engine.get_positions()
+            if positions is None:
+                logger.warning("⚠️ Failed to fetch positions during initialization - using empty state")
+                positions = []
             # Initialize cache.last_known_positions for the first cycle of _update_cached_data logging
             self.cache.last_known_positions = {
                 pos.get('symbol'): pos for pos in positions 
@@ -235,10 +238,18 @@ class MarketMonitor:
     async def _update_cached_data(self):
         """Continuously update cached exchange data for all components to use."""
         try:
-            fresh_positions_list = self.trading_engine.get_positions() or []
-            fresh_orders_list = self.trading_engine.get_orders() or []
+            fresh_positions_list = self.trading_engine.get_positions()
+            fresh_orders_list = self.trading_engine.get_orders()
             fresh_balance = self.trading_engine.get_balance()
             
+            # Handle API failures gracefully
+            if fresh_positions_list is None:
+                logger.warning("⚠️ Failed to fetch positions - keeping previous cache")
+                fresh_positions_list = self.cache.cached_positions or []
+            if fresh_orders_list is None:
+                logger.warning("⚠️ Failed to fetch orders - keeping previous cache")
+                fresh_orders_list = self.cache.cached_orders or []
+            
             # Update cache object
             self.cache.cached_positions = fresh_positions_list
             self.cache.cached_orders = fresh_orders_list

+ 14 - 3
src/monitoring/simple_position_tracker.py

@@ -33,7 +33,12 @@ class SimplePositionTracker:
                 return
             
             # Get current exchange positions
-            exchange_positions = self.trading_engine.get_positions() or []
+            exchange_positions = self.trading_engine.get_positions()
+            
+            # Handle API failures gracefully - don't treat None as empty positions
+            if exchange_positions is None:
+                logger.warning("⚠️ Failed to fetch exchange positions - skipping position change detection to avoid false closures")
+                return
             
             # Get current DB positions (trades with status='position_opened')
             db_positions = stats.get_open_positions()
@@ -261,7 +266,10 @@ class SimplePositionTracker:
                 
                 try:
                     # Check if position still exists on exchange
-                    exchange_positions = self.trading_engine.get_positions() or []
+                    exchange_positions = self.trading_engine.get_positions()
+                    if exchange_positions is None:
+                        logger.warning("⚠️ Failed to fetch exchange positions - skipping stop loss check")
+                        continue
                     position_exists = any(
                         pos['symbol'] == symbol and abs(float(pos.get('contracts', 0))) > 1e-9 
                         for pos in exchange_positions
@@ -311,7 +319,10 @@ class SimplePositionTracker:
             exchange_order_ids = {order.get('id') for order in exchange_orders if order.get('id')}
             
             # Get current exchange positions
-            exchange_positions = self.trading_engine.get_positions() or []
+            exchange_positions = self.trading_engine.get_positions()
+            if exchange_positions is None:
+                logger.warning("⚠️ Failed to fetch exchange positions - skipping orphaned trade cleanup")
+                return
             exchange_position_symbols = {
                 pos.get('symbol') for pos in exchange_positions 
                 if pos.get('symbol') and abs(float(pos.get('contracts', 0))) > 1e-9

+ 1 - 1
trading_bot.py

@@ -14,7 +14,7 @@ from datetime import datetime
 from pathlib import Path
 
 # Bot version
-BOT_VERSION = "2.3.170"
+BOT_VERSION = "2.3.171"
 
 # Add src directory to Python path
 sys.path.insert(0, str(Path(__file__).parent / "src"))

+ 0 - 139
utils/demo_stats.py

@@ -1,139 +0,0 @@
-#!/usr/bin/env python3
-"""
-Trading Statistics Demo
-
-Shows sample trading statistics to demonstrate what the bot tracks.
-"""
-
-import sys
-from pathlib import Path
-from datetime import datetime, timedelta
-import random
-
-# Add src directory to Python path
-sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
-
-from src.stats import TradingStats
-
-def create_demo_stats():
-    """Create demo trading statistics."""
-    print("📊 Creating Demo Trading Statistics...\n")
-    
-    # Create stats instance with demo file
-    stats = TradingStats("demo_stats.json")
-    
-    # Set initial balance
-    initial_balance = 1000.0
-    stats.set_initial_balance(initial_balance)
-    
-    # Simulate some trades over 30 days
-    current_balance = initial_balance
-    base_time = datetime.now() - timedelta(days=30)
-    
-    print("🎲 Simulating 30 days of trading...")
-    
-    # Generate sample trades
-    symbols = ["BTC/USDC:USDC", "ETH/USDC:USDC"]
-    
-    for day in range(30):
-        date = base_time + timedelta(days=day)
-        
-        # 70% chance of trading each day
-        if random.random() < 0.7:
-            # 1-3 trades per day
-            num_trades = random.randint(1, 3)
-            
-            for _ in range(num_trades):
-                symbol = random.choice(symbols)
-                
-                # Simulate buy trade
-                if symbol == "BTC/USDC:USDC":
-                    price = random.uniform(45000, 55000)
-                    amount = random.uniform(0.001, 0.01)
-                else:  # ETH
-                    price = random.uniform(2800, 3200)
-                    amount = random.uniform(0.01, 0.1)
-                
-                trade_value = amount * price
-                
-                # Record buy
-                stats.data['trades'].append({
-                    'timestamp': date.isoformat(),
-                    'symbol': symbol,
-                    'side': 'buy',
-                    'amount': amount,
-                    'price': price,
-                    'value': trade_value,
-                    'order_id': f'demo_{len(stats.data["trades"])}',
-                    'type': 'manual',
-                    'pnl': 0.0
-                })
-                
-                # Sometimes sell (60% chance)
-                if random.random() < 0.6:
-                    # Sell at slightly different price
-                    sell_price = price * random.uniform(0.98, 1.05)  # -2% to +5%
-                    pnl = amount * (sell_price - price)
-                    current_balance += pnl
-                    
-                    sell_date = date + timedelta(hours=random.randint(1, 12))
-                    
-                    stats.data['trades'].append({
-                        'timestamp': sell_date.isoformat(),
-                        'symbol': symbol,
-                        'side': 'sell',
-                        'amount': amount,
-                        'price': sell_price,
-                        'value': amount * sell_price,
-                        'order_id': f'demo_{len(stats.data["trades"])}',
-                        'type': 'manual',
-                        'pnl': pnl
-                    })
-        
-        # Record daily balance
-        daily_variance = random.uniform(-20, 30)  # Daily balance change
-        current_balance += daily_variance
-        
-        stats.data['daily_balances'].append({
-            'date': date.date().isoformat(),
-            'balance': current_balance,
-            'timestamp': date.isoformat()
-        })
-    
-    # Save the demo data
-    stats._save_stats()
-    
-    return stats, current_balance
-
-def main():
-    """Main demo function."""
-    print("🎮 Trading Statistics Demo\n")
-    print("This shows what your bot will track when you start trading manually.\n")
-    
-    # Create demo data
-    stats, current_balance = create_demo_stats()
-    
-    # Display statistics
-    print("📈 Sample Trading Statistics:\n")
-    stats_message = stats.format_stats_message(current_balance)
-    
-    # Convert HTML to plain text for terminal display
-    plain_message = stats_message.replace('<b>', '').replace('</b>', '')
-    plain_message = plain_message.replace('<i>', '').replace('</i>', '')
-    
-    print(plain_message)
-    
-    print("\n" + "="*60)
-    print("🎯 What This Means:")
-    print("✅ Your bot will track ALL these metrics automatically")
-    print("📱 View anytime on your phone with /stats command")
-    print("💾 Statistics persist between bot restarts")
-    print("🔄 Every manual trade updates your performance metrics")
-    print("📊 Professional-grade analytics from day one")
-    print("="*60)
-    
-    print(f"\n📁 Demo data saved to: demo_stats.json")
-    print("🗑️  You can delete this file - it's just for demonstration")
-
-if __name__ == "__main__":
-    main() 

+ 0 - 175
utils/manual_trading_bot.py

@@ -1,175 +0,0 @@
-#!/usr/bin/env python3
-"""
-Manual Trading Bot Launcher
-
-A focused launcher for manual Hyperliquid trading via Telegram.
-This script sets up comprehensive statistics tracking and phone-friendly controls.
-"""
-
-import logging
-import asyncio
-import sys
-from datetime import datetime
-from config import Config
-from telegram_bot import TelegramTradingBot
-
-# Set up logging
-logging.basicConfig(
-    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
-    level=getattr(logging, Config.LOG_LEVEL)
-)
-logger = logging.getLogger(__name__)
-
-def print_banner():
-    """Print a nice startup banner."""
-    banner = """
-╔══════════════════════════════════════════════════════════════╗
-║                    📱 MANUAL TRADING BOT                      ║
-║                      for Hyperliquid                          ║
-╠══════════════════════════════════════════════════════════════╣
-║                                                              ║
-║  🤖 Control your account from your phone via Telegram       ║
-║  📊 Comprehensive trading statistics tracking               ║
-║  📈 Real-time P&L monitoring                                ║
-║  🛡️ Risk metrics (Sharpe, Sortino, VaR)                     ║
-║  📱 Mobile-optimized interface                               ║
-║                                                              ║
-╚══════════════════════════════════════════════════════════════╝
-    """
-    print(banner)
-
-def validate_setup():
-    """Validate that everything is set up correctly."""
-    print("🔍 Validating configuration...")
-    
-    # Check configuration
-    if not Config.validate():
-        print("❌ Configuration validation failed!")
-        return False
-    
-    # Check Telegram setup
-    if not Config.TELEGRAM_ENABLED:
-        print("❌ Telegram is not enabled in configuration")
-        print("💡 Please set TELEGRAM_ENABLED=true in your .env file")
-        return False
-    
-    if not Config.TELEGRAM_BOT_TOKEN:
-        print("❌ TELEGRAM_BOT_TOKEN not configured")
-        print("💡 Please add your Telegram bot token to .env file")
-        return False
-    
-    if not Config.TELEGRAM_CHAT_ID:
-        print("❌ TELEGRAM_CHAT_ID not configured")
-        print("💡 Please run: python get_telegram_chat_id.py")
-        return False
-    
-    # Check Hyperliquid setup
-    if not Config.HYPERLIQUID_PRIVATE_KEY:
-        print("❌ HYPERLIQUID_PRIVATE_KEY not configured")
-        print("💡 Please add your private key to .env file")
-        return False
-    
-    print("✅ Configuration validation passed!")
-    return True
-
-def print_configuration():
-    """Print current configuration."""
-    print("\n📋 Current Configuration:")
-    print(f"🌐 Network: {'Testnet' if Config.HYPERLIQUID_TESTNET else '🚨 MAINNET 🚨'}")
-    print(f"📊 Trading Symbol: {Config.DEFAULT_TRADING_SYMBOL}")
-    print(f"💰 Default Amount: {Config.DEFAULT_TRADE_AMOUNT}")
-    print(f"💬 Telegram Bot: @{Config.TELEGRAM_BOT_TOKEN.split(':')[0] if Config.TELEGRAM_BOT_TOKEN else 'Not configured'}")
-    print(f"🔑 Chat ID: {Config.TELEGRAM_CHAT_ID}")
-    print(f"📈 Statistics: Enabled (saved to trading_stats.json)")
-    
-    if not Config.HYPERLIQUID_TESTNET:
-        print("\n⚠️  WARNING: You are running on MAINNET!")
-        print("💸 Real money will be used for trading!")
-        response = input("Are you sure you want to continue? (type 'YES' to confirm): ")
-        if response != 'YES':
-            print("❌ Cancelled by user")
-            return False
-    
-    return True
-
-def print_usage_guide():
-    """Print usage guide."""
-    print("""
-📱 How to Use Your Manual Trading Bot:
-
-1️⃣ Start Telegram and find your bot
-2️⃣ Send /start to see quick action buttons  
-3️⃣ Use these commands for manual trading:
-
-💼 ACCOUNT MONITORING:
-   • /balance - Check your account balance
-   • /positions - View open positions
-   • /orders - See pending orders
-   • /stats - Full trading statistics
-
-🔄 MANUAL TRADING:
-   • /buy 0.001 50000 - Buy 0.001 BTC at $50,000
-   • /sell 0.001 55000 - Sell 0.001 BTC at $55,000
-   • /trades - View recent trade history
-
-📊 STATISTICS TRACKED:
-   • 💰 Starting vs Current Balance
-   • 📈 Total P&L and Return %
-   • 🏆 Win Rate and Profit Factor
-   • 📊 Sharpe & Sortino Ratios
-   • 🎯 Max Drawdown and VaR
-   • 🔄 Trade Count and Expectancy
-
-🛡️ SAFETY FEATURES:
-   • All trades require confirmation
-   • Comprehensive logging
-   • Real-time balance tracking
-   • Risk metrics calculation
-   • Order confirmations
-
-⚠️  IMPORTANT:
-   • Bot starts statistics tracking from first launch
-   • All manual trades are automatically recorded
-   • Statistics persist between bot restarts
-   • Use /stats to see comprehensive performance metrics
-
-Ready to start manual trading from your phone! 🚀
-    """)
-
-async def main():
-    """Main function to start the manual trading bot."""
-    try:
-        print_banner()
-        
-        # Validate setup
-        if not validate_setup():
-            sys.exit(1)
-        
-        # Print configuration
-        if not print_configuration():
-            sys.exit(1)
-        
-        print_usage_guide()
-        
-        print("🚀 Starting Manual Trading Bot...")
-        print("📱 Your phone controls are ready!")
-        print("🔄 Statistics tracking initialized")
-        print("⏰ Started at:", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
-        print("\n💡 Open Telegram and send /start to your bot!")
-        print("🛑 Press Ctrl+C to stop the bot\n")
-        
-        # Create and run the bot
-        bot = TelegramTradingBot()
-        await bot.run()
-        
-    except KeyboardInterrupt:
-        print("\n👋 Manual Trading Bot stopped by user")
-        print("📊 Your trading statistics have been saved")
-        print("🔄 Restart anytime to continue tracking!")
-    except Exception as e:
-        logger.error(f"❌ Unexpected error: {e}")
-        print(f"\n❌ Error: {e}")
-        print("💡 Check your configuration and try again")
-
-if __name__ == "__main__":
-    asyncio.run(main()) 

+ 0 - 192
utils/simple_bot.py

@@ -1,192 +0,0 @@
-#!/usr/bin/env python3
-"""
-Simple Hyperliquid Trading Bot
-
-This is a basic trading bot that demonstrates:
-- Connecting to Hyperliquid
-- Fetching market data
-- Checking account balance
-- Basic trading functions
-
-Run with: python simple_bot.py
-"""
-
-import time
-import json
-from typing import Dict, Any
-from hyperliquid_client import HyperliquidClient
-from config import Config
-
-
-class SimpleTradingBot:
-    """A simple trading bot for demonstration purposes."""
-    
-    def __init__(self):
-        """Initialize the trading bot."""
-        print("🤖 Initializing Simple Trading Bot...")
-        self.client = HyperliquidClient(use_testnet=Config.HYPERLIQUID_TESTNET)
-        self.symbol = Config.DEFAULT_TRADING_SYMBOL
-        self.is_running = False
-        
-    def print_banner(self):
-        """Print a welcome banner."""
-        print("=" * 60)
-        print("🚀 HYPERLIQUID TRADING BOT")
-        print("=" * 60)
-        Config.print_config()
-        print("=" * 60)
-    
-    def check_connection(self) -> bool:
-        """Check if we can connect to Hyperliquid."""
-        print("\n🔗 Testing connection to Hyperliquid...")
-        
-        # Try to fetch market data (doesn't require private key)
-        market_data = self.client.get_market_data(self.symbol)
-        if market_data:
-            ticker = market_data['ticker']
-            print(f"✅ Connection successful!")
-            print(f"📊 {self.symbol} - Price: ${ticker.get('last', 'N/A')}")
-            return True
-        else:
-            print("❌ Connection failed!")
-            return False
-    
-    def show_account_info(self):
-        """Display account information."""
-        print("\n💰 Account Information:")
-        
-        # Get balance
-        balance = self.client.get_balance()
-        if balance:
-            print("💳 Balance:")
-            for asset, amount in balance.get('total', {}).items():
-                if float(amount) > 0:
-                    print(f"  {asset}: {amount}")
-        else:
-            print("❌ Could not fetch balance")
-        
-        # Get positions
-        positions = self.client.get_positions()
-        if positions and len(positions) > 0:
-            print("📈 Open Positions:")
-            for position in positions:
-                if float(position.get('contracts', 0)) != 0:
-                    print(f"  {position.get('symbol')}: {position.get('contracts')} contracts")
-        else:
-            print("📈 No open positions")
-        
-        # Get open orders
-        orders = self.client.get_open_orders()
-        if orders and len(orders) > 0:
-            print("📋 Open Orders:")
-            for order in orders:
-                print(f"  {order.get('symbol')}: {order.get('side')} {order.get('amount')} @ ${order.get('price')}")
-        else:
-            print("📋 No open orders")
-    
-    def show_market_data(self):
-        """Display current market data."""
-        print(f"\n📊 Market Data for {self.symbol}:")
-        
-        market_data = self.client.get_market_data(self.symbol)
-        if market_data:
-            ticker = market_data['ticker']
-            orderbook = market_data['orderbook']
-            
-            print(f"💵 Price: ${ticker.get('last', 'N/A')}")
-            print(f"📈 24h High: ${ticker.get('high', 'N/A')}")
-            print(f"📉 24h Low: ${ticker.get('low', 'N/A')}")
-            print(f"📊 24h Volume: {ticker.get('baseVolume', 'N/A')}")
-            
-            if orderbook.get('bids') and orderbook.get('asks'):
-                best_bid = orderbook['bids'][0][0] if orderbook['bids'] else 'N/A'
-                best_ask = orderbook['asks'][0][0] if orderbook['asks'] else 'N/A'
-                print(f"🟢 Best Bid: ${best_bid}")
-                print(f"🔴 Best Ask: ${best_ask}")
-        else:
-            print("❌ Could not fetch market data")
-    
-    def demo_trading_functions(self):
-        """Demonstrate trading functions (without actually placing orders)."""
-        print(f"\n🎯 Trading Demo (SIMULATION ONLY):")
-        print("This would demonstrate trading functions, but we're in safe mode.")
-        print("To enable real trading:")
-        print("1. Set up your .env file with a real private key")
-        print("2. Modify this function to actually place orders")
-        print("3. Start with small amounts on testnet!")
-        
-        # Get current price for reference
-        market_data = self.client.get_market_data(self.symbol)
-        if market_data:
-            current_price = float(market_data['ticker'].get('last', 0))
-            print(f"\n📊 Current {self.symbol} price: ${current_price}")
-            
-            # Simulate order examples
-            buy_price = current_price * 0.99  # 1% below market
-            sell_price = current_price * 1.01  # 1% above market
-            amount = Config.DEFAULT_TRADE_AMOUNT
-            
-            print(f"🟢 Example BUY order: {amount} {self.symbol} @ ${buy_price:.2f}")
-            print(f"🔴 Example SELL order: {amount} {self.symbol} @ ${sell_price:.2f}")
-    
-    def interactive_menu(self):
-        """Show an interactive menu for the bot."""
-        while True:
-            print("\n" + "=" * 40)
-            print("🤖 Trading Bot Menu")
-            print("=" * 40)
-            print("1. Show Account Info")
-            print("2. Show Market Data")
-            print("3. Demo Trading Functions")
-            print("4. Exit")
-            print("=" * 40)
-            
-            choice = input("Select an option (1-4): ").strip()
-            
-            if choice == "1":
-                self.show_account_info()
-            elif choice == "2":
-                self.show_market_data()
-            elif choice == "3":
-                self.demo_trading_functions()
-            elif choice == "4":
-                print("👋 Goodbye!")
-                break
-            else:
-                print("❌ Invalid choice. Please try again.")
-    
-    def run(self):
-        """Main bot execution."""
-        self.print_banner()
-        
-        # Validate configuration
-        if not Config.validate():
-            print("\n❌ Configuration validation failed!")
-            print("Please set up your .env file based on env.example")
-            return
-        
-        # Test connection
-        if not self.check_connection():
-            print("❌ Could not connect to Hyperliquid. Please check your configuration.")
-            return
-        
-        # Show initial account info
-        self.show_account_info()
-        
-        # Start interactive menu
-        self.interactive_menu()
-
-
-def main():
-    """Main entry point."""
-    try:
-        bot = SimpleTradingBot()
-        bot.run()
-    except KeyboardInterrupt:
-        print("\n\n👋 Bot stopped by user")
-    except Exception as e:
-        print(f"\n❌ Unexpected error: {e}")
-
-
-if __name__ == "__main__":
-    main() 

+ 0 - 157
utils/simple_chat_id.py

@@ -1,157 +0,0 @@
-#!/usr/bin/env python3
-"""
-Simple Telegram Chat ID Finder
-
-A more robust version that works better in server environments.
-"""
-
-import sys
-import asyncio
-import signal
-from pathlib import Path
-
-# Add src directory to Python path
-sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
-
-try:
-    from telegram import Bot
-    from telegram.ext import Application, MessageHandler, filters
-except ImportError:
-    print("❌ python-telegram-bot not installed!")
-    print("💡 Run: pip install python-telegram-bot")
-    sys.exit(1)
-
-# Global variables for graceful shutdown
-running = True
-found_ids = set()
-
-def signal_handler(signum, frame):
-    """Handle shutdown signals gracefully."""
-    global running
-    print(f"\n🛑 Stopping...")
-    running = False
-
-async def message_handler(update, context):
-    """Handle incoming messages and show chat info."""
-    global found_ids
-    
-    try:
-        chat_id = update.effective_chat.id
-        user = update.effective_user
-        message_text = update.message.text if update.message else "No text"
-        
-        found_ids.add(chat_id)
-        
-        # Send response
-        response = f"""
-🎯 <b>Chat ID Found!</b>
-
-🆔 <b>Chat ID:</b> <code>{chat_id}</code>
-👤 <b>User:</b> {user.first_name} {user.last_name or ''}
-📧 <b>Username:</b> @{user.username or 'None'}
-
-✅ <b>Add this to your .env file:</b>
-<code>TELEGRAM_CHAT_ID={chat_id}</code>
-        """
-        
-        await update.message.reply_text(response.strip(), parse_mode='HTML')
-        
-        # Print to console
-        print(f"\n🎉 SUCCESS! Chat ID: {chat_id}")
-        print(f"👤 User: {user.first_name} {user.last_name or ''}")
-        print(f"📧 Username: @{user.username or 'None'}")
-        print(f"\n📋 Add to .env file:")
-        print(f"TELEGRAM_CHAT_ID={chat_id}")
-        print(f"\n✅ Press Ctrl+C to stop")
-        
-    except Exception as e:
-        print(f"❌ Error: {e}")
-
-async def run_bot(token):
-    """Run the bot to find Chat ID."""
-    global running
-    
-    try:
-        # Create application
-        app = Application.builder().token(token).build()
-        
-        # Add message handler
-        app.add_handler(MessageHandler(filters.ALL, message_handler))
-        
-        print("🤖 Chat ID finder is running...")
-        print("💬 Send ANY message to your bot in Telegram")
-        print("🛑 Press Ctrl+C when done\n")
-        
-        # Start the bot
-        async with app:
-            await app.start()
-            await app.updater.start_polling()
-            
-            # Keep running until stopped
-            while running:
-                await asyncio.sleep(0.1)
-                
-            await app.updater.stop()
-            
-    except Exception as e:
-        print(f"❌ Bot error: {e}")
-        raise
-
-def main():
-    """Main function."""
-    global running, found_ids
-    
-    print("🔍 Simple Telegram Chat ID Finder\n")
-    
-    # Set up signal handlers
-    signal.signal(signal.SIGINT, signal_handler)
-    signal.signal(signal.SIGTERM, signal_handler)
-    
-    # Get bot token
-    token = input("🤖 Enter your Telegram Bot Token: ").strip()
-    
-    if not token:
-        print("❌ No token provided!")
-        return
-    
-    if ':' not in token:
-        print("❌ Invalid token format!")
-        print("💡 Should look like: 123456789:ABCdefGHIjklMNOPqrs")
-        return
-    
-    print(f"\n✅ Token looks valid!")
-    print(f"🚀 Starting bot...\n")
-    
-    try:
-        # Test the token first
-        async def test_token():
-            try:
-                bot = Bot(token)
-                me = await bot.get_me()
-                print(f"🤖 Bot: @{me.username} ({me.first_name})")
-                return True
-            except Exception as e:
-                print(f"❌ Invalid token: {e}")
-                return False
-        
-        # Test token
-        if not asyncio.run(test_token()):
-            return
-        
-        # Run the bot
-        asyncio.run(run_bot(token))
-        
-    except KeyboardInterrupt:
-        pass
-    except Exception as e:
-        print(f"❌ Error: {e}")
-    finally:
-        if found_ids:
-            print(f"\n📋 Found Chat IDs: {', '.join(map(str, found_ids))}")
-            print(f"✅ Add any of these to your .env file")
-        else:
-            print(f"\n❌ No Chat IDs found")
-            print(f"💡 Make sure you sent a message to your bot!")
-
-if __name__ == "__main__":
-    main() 

+ 0 - 255
utils/strategy_bot.py

@@ -1,255 +0,0 @@
-#!/usr/bin/env python3
-"""
-Automated Trading Strategy Bot
-
-This bot runs continuously and implements automated trading strategies.
-It can run alongside the Telegram bot for monitoring and control.
-"""
-
-import asyncio
-import time
-import logging
-from datetime import datetime, timedelta
-from typing import Optional, Dict, Any
-from hyperliquid_client import HyperliquidClient
-from config import Config
-
-# Set up logging
-logging.basicConfig(
-    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
-    level=getattr(logging, Config.LOG_LEVEL)
-)
-logger = logging.getLogger(__name__)
-
-class TradingStrategy:
-    """Base class for trading strategies."""
-    
-    def __init__(self, client: HyperliquidClient):
-        self.client = client
-        self.symbol = Config.DEFAULT_TRADING_SYMBOL
-        self.trade_amount = Config.DEFAULT_TRADE_AMOUNT
-        
-    async def analyze_market(self) -> Dict[str, Any]:
-        """Analyze market conditions. Override in subclasses."""
-        market_data = self.client.get_market_data(self.symbol)
-        return {
-            'signal': 'HOLD',  # BUY, SELL, HOLD
-            'confidence': 0.0,  # 0.0 to 1.0
-            'market_data': market_data
-        }
-    
-    async def execute_strategy(self) -> bool:
-        """Execute the trading strategy. Override in subclasses."""
-        analysis = await self.analyze_market()
-        logger.info(f"Strategy analysis: {analysis['signal']} (confidence: {analysis['confidence']:.2f})")
-        return True
-
-class SimpleMovingAverageStrategy(TradingStrategy):
-    """Example: Simple Moving Average Crossover Strategy."""
-    
-    def __init__(self, client: HyperliquidClient):
-        super().__init__(client)
-        self.price_history = []
-        self.short_period = 5  # 5 minute MA
-        self.long_period = 20  # 20 minute MA
-        
-    async def analyze_market(self) -> Dict[str, Any]:
-        """Analyze using moving average crossover."""
-        market_data = self.client.get_market_data(self.symbol)
-        
-        if not market_data:
-            return {'signal': 'HOLD', 'confidence': 0.0, 'market_data': None}
-        
-        current_price = float(market_data['ticker'].get('last', 0))
-        if current_price == 0:
-            return {'signal': 'HOLD', 'confidence': 0.0, 'market_data': market_data}
-        
-        # Add current price to history
-        self.price_history.append(current_price)
-        
-        # Keep only what we need
-        max_history = max(self.short_period, self.long_period) + 5
-        if len(self.price_history) > max_history:
-            self.price_history = self.price_history[-max_history:]
-        
-        # Need enough data for analysis
-        if len(self.price_history) < self.long_period:
-            return {'signal': 'HOLD', 'confidence': 0.0, 'market_data': market_data}
-        
-        # Calculate moving averages
-        short_ma = sum(self.price_history[-self.short_period:]) / self.short_period
-        long_ma = sum(self.price_history[-self.long_period:]) / self.long_period
-        
-        # Previous MAs for crossover detection
-        if len(self.price_history) >= self.long_period + 1:
-            prev_short_ma = sum(self.price_history[-self.short_period-1:-1]) / self.short_period
-            prev_long_ma = sum(self.price_history[-self.long_period-1:-1]) / self.long_period
-            
-            # Bullish crossover: short MA crosses above long MA
-            if prev_short_ma <= prev_long_ma and short_ma > long_ma:
-                return {'signal': 'BUY', 'confidence': 0.7, 'market_data': market_data}
-            
-            # Bearish crossover: short MA crosses below long MA
-            if prev_short_ma >= prev_long_ma and short_ma < long_ma:
-                return {'signal': 'SELL', 'confidence': 0.7, 'market_data': market_data}
-        
-        return {'signal': 'HOLD', 'confidence': 0.5, 'market_data': market_data}
-    
-    async def execute_strategy(self) -> bool:
-        """Execute the moving average strategy."""
-        analysis = await self.analyze_market()
-        signal = analysis['signal']
-        confidence = analysis['confidence']
-        
-        logger.info(f"MA Strategy: {signal} (confidence: {confidence:.2f})")
-        
-        # Only trade with high confidence
-        if confidence < 0.6:
-            return True
-        
-        # Get current positions to avoid overtrading
-        positions = self.client.get_positions(self.symbol)
-        current_position = 0
-        if positions:
-            for pos in positions:
-                if pos.get('symbol') == self.symbol:
-                    current_position = float(pos.get('contracts', 0))
-                    break
-        
-        market_data = analysis['market_data']
-        current_price = float(market_data['ticker'].get('last', 0))
-        
-        if signal == 'BUY' and current_position <= 0:
-            # Place buy order slightly below market price
-            buy_price = current_price * 0.999  # 0.1% below market
-            logger.info(f"🟢 Placing BUY order: {self.trade_amount} {self.symbol} @ ${buy_price:.2f}")
-            
-            # Uncomment to enable real trading:
-            # order = self.client.place_limit_order(self.symbol, 'buy', self.trade_amount, buy_price)
-            # if order:
-            #     logger.info(f"✅ Buy order placed: {order}")
-            # else:
-            #     logger.error("❌ Failed to place buy order")
-            
-        elif signal == 'SELL' and current_position >= 0:
-            # Place sell order slightly above market price
-            sell_price = current_price * 1.001  # 0.1% above market
-            logger.info(f"🔴 Placing SELL order: {self.trade_amount} {self.symbol} @ ${sell_price:.2f}")
-            
-            # Uncomment to enable real trading:
-            # order = self.client.place_limit_order(self.symbol, 'sell', self.trade_amount, sell_price)
-            # if order:
-            #     logger.info(f"✅ Sell order placed: {order}")
-            # else:
-            #     logger.error("❌ Failed to place sell order")
-        
-        return True
-
-class StrategyBot:
-    """Main automated trading bot that runs strategies continuously."""
-    
-    def __init__(self):
-        """Initialize the strategy bot."""
-        self.client = HyperliquidClient(use_testnet=Config.HYPERLIQUID_TESTNET)
-        self.strategies = []
-        self.is_running = False
-        self.loop_interval = 60  # Run every 60 seconds
-        
-        # Add strategies
-        self.add_strategy(SimpleMovingAverageStrategy(self.client))
-    
-    def add_strategy(self, strategy: TradingStrategy):
-        """Add a trading strategy to the bot."""
-        self.strategies.append(strategy)
-        logger.info(f"Added strategy: {strategy.__class__.__name__}")
-    
-    async def run_strategies(self):
-        """Run all strategies once."""
-        for strategy in self.strategies:
-            try:
-                await strategy.execute_strategy()
-            except Exception as e:
-                logger.error(f"Error in strategy {strategy.__class__.__name__}: {e}")
-    
-    async def health_check(self):
-        """Check bot health and connection."""
-        # Test connection
-        market_data = self.client.get_market_data(Config.DEFAULT_TRADING_SYMBOL)
-        if not market_data:
-            logger.error("❌ Health check failed - cannot connect to Hyperliquid")
-            return False
-        
-        # Check balance
-        balance = self.client.get_balance()
-        if not balance:
-            logger.warning("⚠️ Could not fetch balance")
-        
-        logger.info("✅ Health check passed")
-        return True
-    
-    async def run(self):
-        """Main bot loop."""
-        logger.info("🚀 Starting Strategy Bot...")
-        logger.info(f"📊 Default Symbol: {Config.DEFAULT_TRADING_SYMBOL}")
-        logger.info(f"💰 Trade Amount: {Config.DEFAULT_TRADE_AMOUNT}")
-        logger.info(f"⏰ Loop Interval: {self.loop_interval} seconds")
-        logger.info(f"🌐 Network: {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}")
-        
-        # Initial health check
-        if not await self.health_check():
-            logger.error("❌ Initial health check failed. Exiting.")
-            return
-        
-        self.is_running = True
-        iteration = 0
-        
-        try:
-            while self.is_running:
-                iteration += 1
-                start_time = time.time()
-                
-                logger.info(f"🔄 Strategy iteration #{iteration} started")
-                
-                # Run strategies
-                await self.run_strategies()
-                
-                # Periodic health check (every 10 iterations)
-                if iteration % 10 == 0:
-                    await self.health_check()
-                
-                # Calculate sleep time
-                execution_time = time.time() - start_time
-                sleep_time = max(0, self.loop_interval - execution_time)
-                
-                logger.info(f"✅ Iteration #{iteration} completed in {execution_time:.2f}s. Sleeping {sleep_time:.2f}s")
-                
-                if sleep_time > 0:
-                    await asyncio.sleep(sleep_time)
-                
-        except KeyboardInterrupt:
-            logger.info("👋 Strategy bot stopped by user")
-        except Exception as e:
-            logger.error(f"❌ Unexpected error in strategy bot: {e}")
-        finally:
-            self.is_running = False
-            logger.info("🛑 Strategy bot stopped")
-
-def main():
-    """Main entry point."""
-    try:
-        # Validate configuration
-        if not Config.validate():
-            logger.error("❌ Configuration validation failed!")
-            return
-        
-        # Create and run the bot
-        bot = StrategyBot()
-        asyncio.run(bot.run())
-        
-    except KeyboardInterrupt:
-        logger.info("👋 Bot stopped by user")
-    except Exception as e:
-        logger.error(f"❌ Unexpected error: {e}")
-
-if __name__ == "__main__":
-    main()