Przeglądaj źródła

Refactor Telegram bot to support v13.x compatibility - Updated command handler setup to utilize the dispatcher for improved organization and clarity. Enhanced logging during bot initialization and shutdown processes, ensuring better traceability and user feedback. Adjusted comments for clarity and consistency, while maintaining graceful shutdown handling.

Carles Sentis 4 dni temu
rodzic
commit
e132d61161
1 zmienionych plików z 67 dodań i 75 usunięć
  1. 67 75
      src/bot/core.py

+ 67 - 75
src/bot/core.py

@@ -5,10 +5,10 @@ Core Telegram Bot - Handles only bot setup, authentication, and basic messaging.
 
 import asyncio
 import logging
-# import telegram # Import telegram to check version (NO LONGER NEEDED)
+import telegram # Import telegram to check version
 from datetime import datetime
 from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
-from telegram.ext import Application, ContextTypes, CommandHandler, CallbackQueryHandler, MessageHandler, filters
+from telegram.ext import Application, ContextTypes, CommandHandler, CallbackQueryHandler, MessageHandler, filters, Updater
 
 from src.config.config import Config
 from src.trading.trading_engine import TradingEngine
@@ -65,45 +65,47 @@ class TelegramTradingBot:
         if not self.application:
             return
         
+        dp = self.application.dispatcher # Get dispatcher for v13.x
+        
         # Basic bot commands
-        self.application.add_handler(CommandHandler("start", self.start_command))
-        self.application.add_handler(CommandHandler("help", self.help_command))
+        dp.add_handler(CommandHandler("start", self.start_command))
+        dp.add_handler(CommandHandler("help", self.help_command))
         
         # Trading commands
-        self.application.add_handler(CommandHandler("long", self.trading_commands.long_command))
-        self.application.add_handler(CommandHandler("short", self.trading_commands.short_command))
-        self.application.add_handler(CommandHandler("exit", self.trading_commands.exit_command))
-        self.application.add_handler(CommandHandler("sl", self.trading_commands.sl_command))
-        self.application.add_handler(CommandHandler("tp", self.trading_commands.tp_command))
-        self.application.add_handler(CommandHandler("coo", self.trading_commands.coo_command))
+        dp.add_handler(CommandHandler("long", self.trading_commands.long_command))
+        dp.add_handler(CommandHandler("short", self.trading_commands.short_command))
+        dp.add_handler(CommandHandler("exit", self.trading_commands.exit_command))
+        dp.add_handler(CommandHandler("sl", self.trading_commands.sl_command))
+        dp.add_handler(CommandHandler("tp", self.trading_commands.tp_command))
+        dp.add_handler(CommandHandler("coo", self.trading_commands.coo_command))
         
         # Info commands
-        self.application.add_handler(CommandHandler("balance", self.info_commands.balance_command))
-        self.application.add_handler(CommandHandler("positions", self.info_commands.positions_command))
-        self.application.add_handler(CommandHandler("orders", self.info_commands.orders_command))
-        self.application.add_handler(CommandHandler("stats", self.info_commands.stats_command))
-        self.application.add_handler(CommandHandler("trades", self.info_commands.trades_command))
-        self.application.add_handler(CommandHandler("market", self.info_commands.market_command))
-        self.application.add_handler(CommandHandler("price", self.info_commands.price_command))
-        self.application.add_handler(CommandHandler("performance", self.info_commands.performance_command))
-        self.application.add_handler(CommandHandler("daily", self.info_commands.daily_command))
-        self.application.add_handler(CommandHandler("weekly", self.info_commands.weekly_command))
-        self.application.add_handler(CommandHandler("monthly", self.info_commands.monthly_command))
-        self.application.add_handler(CommandHandler("risk", self.info_commands.risk_command))
-        self.application.add_handler(CommandHandler("balance_adjustments", self.info_commands.balance_adjustments_command))
-        self.application.add_handler(CommandHandler("commands", self.info_commands.commands_command))
-        self.application.add_handler(CommandHandler("c", self.info_commands.commands_command))  # Alias
+        dp.add_handler(CommandHandler("balance", self.info_commands.balance_command))
+        dp.add_handler(CommandHandler("positions", self.info_commands.positions_command))
+        dp.add_handler(CommandHandler("orders", self.info_commands.orders_command))
+        dp.add_handler(CommandHandler("stats", self.info_commands.stats_command))
+        dp.add_handler(CommandHandler("trades", self.info_commands.trades_command))
+        dp.add_handler(CommandHandler("market", self.info_commands.market_command))
+        dp.add_handler(CommandHandler("price", self.info_commands.price_command))
+        dp.add_handler(CommandHandler("performance", self.info_commands.performance_command))
+        dp.add_handler(CommandHandler("daily", self.info_commands.daily_command))
+        dp.add_handler(CommandHandler("weekly", self.info_commands.weekly_command))
+        dp.add_handler(CommandHandler("monthly", self.info_commands.monthly_command))
+        dp.add_handler(CommandHandler("risk", self.info_commands.risk_command))
+        dp.add_handler(CommandHandler("balance_adjustments", self.info_commands.balance_adjustments_command))
+        dp.add_handler(CommandHandler("commands", self.info_commands.commands_command))
+        dp.add_handler(CommandHandler("c", self.info_commands.commands_command))  # Alias
         
         # Management commands
-        self.application.add_handler(CommandHandler("monitoring", self.management_commands.monitoring_command))
-        self.application.add_handler(CommandHandler("alarm", self.management_commands.alarm_command))
-        self.application.add_handler(CommandHandler("logs", self.management_commands.logs_command))
-        self.application.add_handler(CommandHandler("debug", self.management_commands.debug_command))
-        self.application.add_handler(CommandHandler("version", self.management_commands.version_command))
-        self.application.add_handler(CommandHandler("keyboard", self.management_commands.keyboard_command))
+        dp.add_handler(CommandHandler("monitoring", self.management_commands.monitoring_command))
+        dp.add_handler(CommandHandler("alarm", self.management_commands.alarm_command))
+        dp.add_handler(CommandHandler("logs", self.management_commands.logs_command))
+        dp.add_handler(CommandHandler("debug", self.management_commands.debug_command))
+        dp.add_handler(CommandHandler("version", self.management_commands.version_command))
+        dp.add_handler(CommandHandler("keyboard", self.management_commands.keyboard_command))
         
         # Callback and message handlers
-        self.application.add_handler(CallbackQueryHandler(self.trading_commands.button_callback))
+        dp.add_handler(CallbackQueryHandler(self.trading_commands.button_callback))
         
     async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /start command."""
@@ -276,7 +278,7 @@ For support or issues, check the logs or contact the administrator.
             logger.error(f"Error sending help message in /help: {e}")
     
     async def run(self):
-        """Run the Telegram bot with manual initialization and shutdown."""
+        """Run the Telegram bot (v13.x compatible)."""
         if not Config.TELEGRAM_BOT_TOKEN:
             logger.error("❌ TELEGRAM_BOT_TOKEN not configured")
             return
@@ -285,77 +287,67 @@ For support or issues, check the logs or contact the administrator.
             logger.error("❌ TELEGRAM_CHAT_ID not configured")
             return
         
-        # logger.info(f"🔧 Using python-telegram-bot version: {telegram.__version__}") # NO LONGER NEEDED
+        logger.info(f"🔧 Using python-telegram-bot version: {telegram.__version__} (Running in v13.x compatibility mode)")
 
-        # Create application
-        self.application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).drop_pending_updates(True).build()
+        # Create Updater for v13.x compatibility
+        # self.application is already initialized as Updater in __init__ if we move it there, or here.
+        # For consistency, let's ensure it's initialized if not already.
+        if not isinstance(self.application, Updater):
+            self.application = Updater(token=Config.TELEGRAM_BOT_TOKEN, use_context=True)
         
         # Connect notification manager to the bot application
         self.notification_manager.set_bot_application(self.application)
         
-        # Set up handlers
+        # Set up handlers (handlers are added to dispatcher inside setup_handlers)
         self.setup_handlers()
 
-        keep_running_future = asyncio.Future() # Future to keep the bot alive
-
         try:
-            logger.info("🚀 Initializing bot application...")
-            await self.application.initialize()
-            
-            logger.info(f"🚀 Starting Telegram trading bot v{self.version}...")
+            logger.info(f"🚀 Starting Telegram trading bot v{self.version} (v13.x mode)...")
             
-            # Send startup notification
+            # Send startup notification (await is fine, send_message is async)
             await self.send_message(
-                f"🤖 <b>Manual Trading Bot v{self.version} Started</b>\n\n"
+                f"🤖 <b>Manual Trading Bot v{self.version} Started (v13.x mode)</b>\n\n"
                 f"✅ Connected to Hyperliquid {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}\n"
                 f"📊 Default Symbol: {Config.DEFAULT_TRADING_TOKEN}\n"
                 f"🔄 All systems ready!\n\n"
                 "Use /start for quick actions or /help for all commands."
             )
             
-            # Start subsystems
+            # Start subsystems (market_monitor needs to be started as async)
+            # For v13, typically MarketMonitor might not be started with await here unless it's run in a separate async loop
+            # or if start_polling itself is managed within an asyncio context by the main script.
+            # Given trading_bot.py uses asyncio.run(), this should be okay.
             await self.market_monitor.start()
             
-            logger.info("▶️ Starting PTB application (handlers, dispatcher, polling...)...")
-            await self.application.start() # This starts polling and other processes
+            logger.info("🔄 Starting PTB Updater polling (v13.x mode)...")
+            self.application.start_polling(drop_pending_updates=True)
             
-            # logger.info(f"🔍 Type of self.application.running after start: {type(self.application.running)}") # NO LONGER NEEDED
-            logger.info("Bot is now running. Awaiting external stop signal (e.g., Ctrl+C)...")
-            
-            # Wait indefinitely until an exception (like KeyboardInterrupt) or task cancellation
-            await keep_running_future
+            logger.info("Bot is now running. Waiting for signals to stop (e.g., Ctrl+C)...")
+            self.application.idle() # This is blocking and handles signals
+            logger.info("PTB Updater has stopped/idled gracefully.")
                     
         except (KeyboardInterrupt, SystemExit):
             logger.info("🛑 Bot run interrupted by user/system. Initiating shutdown...")
-            if not keep_running_future.done():
-                keep_running_future.set_exception(KeyboardInterrupt()) # Ensure future is resolved
-        except asyncio.CancelledError:
-            logger.info("🛑 Bot run task cancelled. Initiating shutdown...")
-            if not keep_running_future.done():
-                keep_running_future.cancel()
         except Exception as e:
-            logger.error(f"❌ Unhandled error in bot run loop: {e}", exc_info=True)
-            if not keep_running_future.done():
-                keep_running_future.set_exception(e)
+            logger.error(f"❌ Unhandled error in bot run loop (v13.x mode): {e}", exc_info=True)
         finally:
-            logger.info("🔌 Starting graceful shutdown sequence in TelegramTradingBot.run...")
+            logger.info("🔌 Starting graceful shutdown sequence in TelegramTradingBot.run (v13.x mode)...")
             try:
                 logger.info("Stopping market monitor...")
                 await self.market_monitor.stop()
                 logger.info("Market monitor stopped.")
 
-                if self.application:
-                    logger.info("Attempting to stop PTB application...")
-                    await self.application.stop() 
-                    logger.info("PTB application stop attempted.")
-                    
-                    logger.info("Shutting down PTB application...")
-                    await self.application.shutdown()
-                    logger.info("PTB application shut down.")
-                else:
-                    logger.warning("Application object was None during shutdown in TelegramTradingBot.run.")
+                if hasattr(self.application, 'running') and self.application.running:
+                    logger.info("Stopping PTB Updater (v13.x mode)...")
+                    self.application.stop()
+                    logger.info("PTB Updater stopped.")
+                elif isinstance(self.application, Updater):
+                    # If not `running` attribute, just call stop for Updater as a fallback.
+                    logger.info("PTB Updater might not be running or attribute 'running' not found, attempting stop anyway...")
+                    self.application.stop()
+                    logger.info("PTB Updater stop attempted.")
                 
-                logger.info("✅ Graceful shutdown sequence in TelegramTradingBot.run complete.")
+                logger.info("✅ Graceful shutdown sequence in TelegramTradingBot.run (v13.x mode) complete.")
                 
             except Exception as e:
-                logger.error(f"💥 Error during shutdown sequence in TelegramTradingBot.run: {e}", exc_info=True) 
+                logger.error(f"💥 Error during shutdown sequence in TelegramTradingBot.run (v13.x mode): {e}", exc_info=True)