Преглед на файлове

Re-enable copy trading functionality in TelegramTradingBot and MonitoringCoordinator

- Restored initialization and command handlers for copy trading in TelegramTradingBot, allowing commands for copy trading status, start, and stop.
- Reactivated the copy trading monitor initialization and startup in MonitoringCoordinator, ensuring its functionality is operational.
- Enhanced error handling and timeout management in CopyTradingMonitor for improved reliability during position tracking and trade execution.
Carles Sentis преди 5 дни
родител
ревизия
38c1365ca1
променени са 4 файла, в които са добавени 128 реда и са изтрити 95 реда
  1. 8 25
      src/bot/core.py
  2. 113 56
      src/monitoring/copy_trading_monitor.py
  3. 6 13
      src/monitoring/monitoring_coordinator.py
  4. 1 1
      trading_bot.py

+ 8 - 25
src/bot/core.py

@@ -71,8 +71,7 @@ class TelegramTradingBot:
         self.price_cmds = PriceCommands(self.trading_engine, self.notification_manager)
         self.balance_adjustments_cmds = BalanceAdjustmentsCommands(self.trading_engine, self.notification_manager)
         self.commands_cmds = CommandsInfo(self.trading_engine, self.notification_manager)
-        # TEMPORARY: Disable copy trading commands initialization for debugging
-        # self.copy_trading_cmds = CopyTradingCommands(self.monitoring_coordinator)
+        self.copy_trading_cmds = CopyTradingCommands(self.monitoring_coordinator)
 
         # Create a class to hold all info commands
         class InfoCommandsHandler:
@@ -155,10 +154,9 @@ class TelegramTradingBot:
         self.application.add_handler(CommandHandler("commands", self.commands_cmds.commands_command))
         
         # Copy trading commands
-        # TEMPORARY: Disable copy trading commands for debugging
-        # self.application.add_handler(CommandHandler("copy_status", self.copy_trading_cmds.copy_status_command))
-        # self.application.add_handler(CommandHandler("copy_start", self.copy_trading_cmds.copy_start_command))
-        # self.application.add_handler(CommandHandler("copy_stop", self.copy_trading_cmds.copy_stop_command))
+        self.application.add_handler(CommandHandler("copy_status", self.copy_trading_cmds.copy_status_command))
+        self.application.add_handler(CommandHandler("copy_start", self.copy_trading_cmds.copy_start_command))
+        self.application.add_handler(CommandHandler("copy_stop", self.copy_trading_cmds.copy_stop_command))
         self.application.add_handler(CommandHandler("c", self.commands_cmds.commands_command))  # Alias
         
         # Management commands
@@ -176,13 +174,10 @@ class TelegramTradingBot:
         # Callback and message handlers
         self.application.add_handler(CallbackQueryHandler(self.trading_commands.button_callback))
         self.application.add_handler(MessageHandler(
-            filters.Regex(r'^(LONG|SHORT|EXIT|SL|TP|LEVERAGE|BALANCE|POSITIONS|ORDERS|STATS|MARKET|PERFORMANCE|DAILY|WEEKLY|MONTHLY|RISK|ALARM|MONITORING|LOGS|DEBUG|VERSION|COMMANDS|KEYBOARD|COO)'),
+            filters.Regex(r'^(LONG|SHORT|EXIT|SL|TP|LEVERAGE|BALANCE|POSITIONS|ORDERS|STATS|MARKET|PERFORMANCE|DAILY|WEEKLY|MONTHLY|RISK|ALARM|MONITORING|LOGS|DEBUG|VERSION|COMMANDS|KEYBOARD|COO|COPY_STATUS|COPY_START|COPY_STOP)'),
             self.handle_keyboard_command
         ))
         
-        # Debug message handler to catch all messages (should be last)
-        self.application.add_handler(MessageHandler(filters.ALL, self.debug_message_handler))
-        
     async def handle_keyboard_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handles commands sent via the main keyboard."""
         command_text = update.message.text.upper()
@@ -214,10 +209,9 @@ class TelegramTradingBot:
             "DEBUG": self.management_commands.debug_command,
             "VERSION": self.management_commands.version_command,
             "KEYBOARD": self.management_commands.keyboard_command,
-            # TEMPORARY: Disable copy trading keyboard commands for debugging
-            # "COPY_STATUS": self.copy_trading_cmds.copy_status_command,
-            # "COPY_START": self.copy_trading_cmds.copy_start_command,
-            # "COPY_STOP": self.copy_trading_cmds.copy_stop_command,
+            "COPY_STATUS": self.copy_trading_cmds.copy_status_command,
+            "COPY_START": self.copy_trading_cmds.copy_start_command,
+            "COPY_STOP": self.copy_trading_cmds.copy_stop_command,
         }
 
         command_func = command_map.get(command_text)
@@ -233,17 +227,6 @@ class TelegramTradingBot:
                 f"Unknown command: {command_text}", chat_id=update.effective_chat.id
             )
 
-    async def debug_message_handler(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
-        """Debug handler to log all incoming messages."""
-        try:
-            chat_id = update.effective_chat.id if update.effective_chat else "unknown"
-            message_text = update.message.text if update.message and update.message.text else "no text"
-            logger.info(f"🐛 DEBUG: Received message from chat_id={chat_id}, text='{message_text}'")
-            logger.info(f"🐛 DEBUG: Expected chat_id={Config.TELEGRAM_CHAT_ID}")
-            logger.info(f"🐛 DEBUG: Authorization result={self.is_authorized(chat_id)}")
-        except Exception as e:
-            logger.error(f"Error in debug message handler: {e}")
-
     async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /start command."""
         logger.info(f"/start command triggered by chat_id: {update.effective_chat.id}")

+ 113 - 56
src/monitoring/copy_trading_monitor.py

@@ -100,81 +100,128 @@ class CopyTradingMonitor:
             
         self.logger.info(f"Starting copy trading monitor for {self.target_address}")
         
-        # Start state tracking
-        self.state_manager.start_copy_trading(self.target_address)
-        
-        # Get current target positions for initialization
-        current_positions = await self.get_target_positions()
-        if current_positions:
-            # Check if this is a fresh start or resuming
-            if not self.state_manager.get_tracked_positions():
-                # Fresh start - initialize tracking but don't copy existing positions
-                self.logger.info("🆕 Fresh start - initializing with existing positions (won't copy)")
-                self.state_manager.initialize_tracked_positions(current_positions)
-                
-                startup_message = (
-                    f"🔄 Copy Trading Started (Fresh)\n"
-                    f"Target: {self.target_address[:10]}...\n"
-                    f"Portfolio Allocation: {self.portfolio_percentage:.1%}\n"
-                    f"Mode: {self.copy_mode}\n"
-                    f"Max Leverage: {self.max_leverage}x\n\n"
-                    f"📊 Found {len(current_positions)} existing positions\n"
-                    f"⚠️ Will only copy NEW trades from now on"
+        try:
+            # Start state tracking
+            self.state_manager.start_copy_trading(self.target_address)
+            
+            # Get current target positions for initialization (with timeout)
+            try:
+                current_positions = await asyncio.wait_for(
+                    self.get_target_positions(), 
+                    timeout=15.0  # 15 second timeout for initialization
                 )
+            except asyncio.TimeoutError:
+                self.logger.warning("Timeout during initialization - will retry in monitoring loop")
+                current_positions = None
+            except Exception as e:
+                self.logger.error(f"Error during initialization: {e}")
+                current_positions = None
+            
+            if current_positions:
+                # Check if this is a fresh start or resuming
+                if not self.state_manager.get_tracked_positions():
+                    # Fresh start - initialize tracking but don't copy existing positions
+                    self.logger.info("🆕 Fresh start - initializing with existing positions (won't copy)")
+                    self.state_manager.initialize_tracked_positions(current_positions)
+                    
+                    startup_message = (
+                        f"🔄 Copy Trading Started (Fresh)\n"
+                        f"Target: {self.target_address[:10]}...\n"
+                        f"Portfolio Allocation: {self.portfolio_percentage:.1%}\n"
+                        f"Mode: {self.copy_mode}\n"
+                        f"Max Leverage: {self.max_leverage}x\n\n"
+                        f"📊 Found {len(current_positions)} existing positions\n"
+                        f"⚠️ Will only copy NEW trades from now on"
+                    )
+                else:
+                    # Resuming - continue from where we left off
+                    tracked_count = len(self.state_manager.get_tracked_positions())
+                    self.logger.info(f"▶️ Resuming session - {tracked_count} positions tracked")
+                    
+                    startup_message = (
+                        f"▶️ Copy Trading Resumed\n"
+                        f"Target: {self.target_address[:10]}...\n"
+                        f"Portfolio Allocation: {self.portfolio_percentage:.1%}\n"
+                        f"Mode: {self.copy_mode}\n"
+                        f"Max Leverage: {self.max_leverage}x\n\n"
+                        f"📊 Resuming with {tracked_count} tracked positions"
+                    )
             else:
-                # Resuming - continue from where we left off
-                tracked_count = len(self.state_manager.get_tracked_positions())
-                self.logger.info(f"▶️ Resuming session - {tracked_count} positions tracked")
-                
                 startup_message = (
-                    f"▶️ Copy Trading Resumed\n"
+                    f"🔄 Copy Trading Started\n"
                     f"Target: {self.target_address[:10]}...\n"
                     f"Portfolio Allocation: {self.portfolio_percentage:.1%}\n"
                     f"Mode: {self.copy_mode}\n"
                     f"Max Leverage: {self.max_leverage}x\n\n"
-                    f"📊 Resuming with {tracked_count} tracked positions"
+                    f"⚠️ Could not access target trader positions during startup"
                 )
-        else:
-            startup_message = (
-                f"🔄 Copy Trading Started\n"
-                f"Target: {self.target_address[:10]}...\n"
-                f"Portfolio Allocation: {self.portfolio_percentage:.1%}\n"
-                f"Mode: {self.copy_mode}\n"
-                f"Max Leverage: {self.max_leverage}x\n\n"
-                f"⚠️ Could not access target trader positions"
-            )
-        
-        # Send startup notification
-        if self.notifications_enabled:
-            await self.notification_manager.send_message(startup_message)
-        
-        # Initial sync
-        await self.sync_positions()
-        
-        # Start monitoring loop
-        while self.enabled and self.state_manager.is_enabled():
+            
+            # Send startup notification
+            if self.notifications_enabled:
+                try:
+                    await asyncio.wait_for(
+                        self.notification_manager.send_message(startup_message),
+                        timeout=5.0
+                    )
+                except Exception as e:
+                    self.logger.error(f"Error sending startup notification: {e}")
+            
+            # Initial sync (non-blocking)
             try:
-                await self.monitor_cycle()
-                await asyncio.sleep(30)  # Check every 30 seconds
+                await asyncio.wait_for(self.sync_positions(), timeout=10.0)
             except Exception as e:
-                self.logger.error(f"Error in copy trading monitor cycle: {e}")
-                await asyncio.sleep(60)  # Wait longer on error
+                self.logger.error(f"Error during initial sync: {e}")
+            
+            # Start monitoring loop
+            while self.enabled and self.state_manager.is_enabled():
+                try:
+                    await self.monitor_cycle()
+                    await asyncio.sleep(30)  # Check every 30 seconds
+                except Exception as e:
+                    self.logger.error(f"Error in copy trading monitor cycle: {e}")
+                    await asyncio.sleep(60)  # Wait longer on error
+                    
+        except Exception as e:
+            self.logger.error(f"Fatal error in copy trading monitor: {e}")
+            self.enabled = False
     
     async def monitor_cycle(self):
         """Single monitoring cycle"""
         try:
-            # Get target trader's current positions
-            new_positions = await self.get_target_positions()
-            
+            # Get target trader's current positions with timeout
+            try:
+                new_positions = await asyncio.wait_for(
+                    self.get_target_positions(),
+                    timeout=15.0  # 15 second timeout
+                )
+            except asyncio.TimeoutError:
+                self.logger.warning("Timeout getting target positions - skipping this cycle")
+                return
+            except Exception as e:
+                self.logger.error(f"Error getting target positions: {e}")
+                return
+
             if new_positions is None:
                 return
                 
             # Compare with previous positions to detect changes
-            position_changes = self.detect_position_changes(new_positions)
+            try:
+                position_changes = self.detect_position_changes(new_positions)
+            except Exception as e:
+                self.logger.error(f"Error detecting position changes: {e}")
+                return
             
             # Execute any detected trades
             for trade in position_changes:
-                await self.execute_copy_trade(trade)
+                try:
+                    await asyncio.wait_for(
+                        self.execute_copy_trade(trade),
+                        timeout=30.0  # 30 second timeout per trade
+                    )
+                except asyncio.TimeoutError:
+                    self.logger.error(f"Timeout executing copy trade for {trade.coin}")
+                except Exception as e:
+                    self.logger.error(f"Error executing copy trade for {trade.coin}: {e}")
                 
             # Update our tracking
             self.target_positions = new_positions
@@ -190,7 +237,9 @@ class CopyTradingMonitor:
                 "user": self.target_address
             }
             
-            async with aiohttp.ClientSession() as session:
+            # Use timeout to prevent blocking
+            timeout = aiohttp.ClientTimeout(total=10.0)  # 10 second timeout
+            async with aiohttp.ClientSession(timeout=timeout) as session:
                 async with session.post(self.info_url, json=payload) as response:
                     if response.status != 200:
                         self.logger.error(f"Failed to get target positions: {response.status}")
@@ -225,6 +274,9 @@ class CopyTradingMonitor:
             
             return positions
             
+        except asyncio.TimeoutError:
+            self.logger.warning("Timeout getting target positions - will retry next cycle")
+            return None
         except Exception as e:
             self.logger.error(f"Error getting target positions: {e}")
             return None
@@ -439,7 +491,9 @@ class CopyTradingMonitor:
                 "user": self.target_address
             }
             
-            async with aiohttp.ClientSession() as session:
+            # Use timeout to prevent blocking
+            timeout = aiohttp.ClientTimeout(total=10.0)  # 10 second timeout
+            async with aiohttp.ClientSession(timeout=timeout) as session:
                 async with session.post(self.info_url, json=payload) as response:
                     if response.status == 200:
                         data = await response.json()
@@ -447,6 +501,9 @@ class CopyTradingMonitor:
                     else:
                         return 0.0
                 
+        except asyncio.TimeoutError:
+            self.logger.warning("Timeout getting target account balance")
+            return 0.0
         except Exception as e:
             self.logger.error(f"Error getting target account balance: {e}")
             return 0.0

+ 6 - 13
src/monitoring/monitoring_coordinator.py

@@ -43,11 +43,8 @@ class MonitoringCoordinator:
         # Initialize copy trading monitor if available
         if COPY_TRADING_AVAILABLE:
             try:
-                # TEMPORARY: Disable copy trading monitor for debugging
-                # self.copy_trading_monitor = CopyTradingMonitor(hl_client, notification_manager)
-                # logger.info("✅ Copy trading monitor initialized")
-                self.copy_trading_monitor = None
-                logger.info("🚫 Copy trading monitor temporarily disabled for debugging")
+                self.copy_trading_monitor = CopyTradingMonitor(hl_client, notification_manager)
+                logger.info("✅ Copy trading monitor initialized (non-blocking version)")
             except Exception as e:
                 logger.error(f"❌ Failed to initialize copy trading monitor: {e}")
                 self.copy_trading_monitor = None
@@ -82,10 +79,8 @@ class MonitoringCoordinator:
             # Start copy trading monitor if enabled
             if self.copy_trading_monitor and hasattr(self.copy_trading_monitor, 'enabled') and self.copy_trading_monitor.enabled:
                 try:
-                    # TEMPORARY: Disable copy trading monitor startup for debugging
-                    # asyncio.create_task(self.copy_trading_monitor.start_monitoring())
-                    # logger.info("🔄 Copy trading monitor started")
-                    logger.info("🚫 Copy trading monitor startup skipped for debugging")
+                    asyncio.create_task(self.copy_trading_monitor.start_monitoring())
+                    logger.info("🔄 Copy trading monitor started (non-blocking)")
                 except Exception as e:
                     logger.error(f"❌ Failed to start copy trading monitor: {e}")
             
@@ -128,10 +123,8 @@ class MonitoringCoordinator:
         # Stop copy trading monitor
         if self.copy_trading_monitor and hasattr(self.copy_trading_monitor, 'stop_monitoring'):
             try:
-                # TEMPORARY: Skip copy trading monitor stop for debugging
-                # await self.copy_trading_monitor.stop_monitoring()
-                # logger.info("🛑 Copy trading monitor stopped")
-                logger.info("🚫 Copy trading monitor stop skipped (was disabled)")
+                await self.copy_trading_monitor.stop_monitoring()
+                logger.info("🛑 Copy trading monitor stopped")
             except Exception as e:
                 logger.error(f"❌ Error stopping copy trading monitor: {e}")
         

+ 1 - 1
trading_bot.py

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