瀏覽代碼

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 5 天之前
父節點
當前提交
e132d61161
共有 1 個文件被更改,包括 67 次插入75 次删除
  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 asyncio
 import logging
 import logging
-# import telegram # Import telegram to check version (NO LONGER NEEDED)
+import telegram # Import telegram to check version
 from datetime import datetime
 from datetime import datetime
 from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
 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.config.config import Config
 from src.trading.trading_engine import TradingEngine
 from src.trading.trading_engine import TradingEngine
@@ -65,45 +65,47 @@ class TelegramTradingBot:
         if not self.application:
         if not self.application:
             return
             return
         
         
+        dp = self.application.dispatcher # Get dispatcher for v13.x
+        
         # Basic bot commands
         # 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
         # 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
         # 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
         # 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
         # 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:
     async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /start command."""
         """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}")
             logger.error(f"Error sending help message in /help: {e}")
     
     
     async def run(self):
     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:
         if not Config.TELEGRAM_BOT_TOKEN:
             logger.error("❌ TELEGRAM_BOT_TOKEN not configured")
             logger.error("❌ TELEGRAM_BOT_TOKEN not configured")
             return
             return
@@ -285,77 +287,67 @@ For support or issues, check the logs or contact the administrator.
             logger.error("❌ TELEGRAM_CHAT_ID not configured")
             logger.error("❌ TELEGRAM_CHAT_ID not configured")
             return
             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
         # Connect notification manager to the bot application
         self.notification_manager.set_bot_application(self.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()
         self.setup_handlers()
 
 
-        keep_running_future = asyncio.Future() # Future to keep the bot alive
-
         try:
         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(
             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"✅ Connected to Hyperliquid {'Testnet' if Config.HYPERLIQUID_TESTNET else 'Mainnet'}\n"
                 f"📊 Default Symbol: {Config.DEFAULT_TRADING_TOKEN}\n"
                 f"📊 Default Symbol: {Config.DEFAULT_TRADING_TOKEN}\n"
                 f"🔄 All systems ready!\n\n"
                 f"🔄 All systems ready!\n\n"
                 "Use /start for quick actions or /help for all commands."
                 "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()
             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):
         except (KeyboardInterrupt, SystemExit):
             logger.info("🛑 Bot run interrupted by user/system. Initiating shutdown...")
             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:
         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:
         finally:
-            logger.info("🔌 Starting graceful shutdown sequence in TelegramTradingBot.run...")
+            logger.info("🔌 Starting graceful shutdown sequence in TelegramTradingBot.run (v13.x mode)...")
             try:
             try:
                 logger.info("Stopping market monitor...")
                 logger.info("Stopping market monitor...")
                 await self.market_monitor.stop()
                 await self.market_monitor.stop()
                 logger.info("Market monitor stopped.")
                 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:
             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)