Prechádzať zdrojové kódy

Refactor Telegram bot to support v20.x style - Updated command handler setup to directly utilize the application for improved clarity and organization. Enhanced logging during bot initialization and shutdown processes, ensuring better traceability and user feedback. Adjusted comments and method calls to align with the new version, contributing to a more streamlined and reliable bot operation.

Carles Sentis 4 dní pred
rodič
commit
e73dcaa327
1 zmenil súbory, kde vykonal 71 pridanie a 68 odobranie
  1. 71 68
      src/bot/core.py

+ 71 - 68
src/bot/core.py

@@ -8,7 +8,7 @@ import logging
 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, Updater
+from telegram.ext import Application, ContextTypes, CommandHandler, CallbackQueryHandler, MessageHandler, filters
 
 from src.config.config import Config
 from src.trading.trading_engine import TradingEngine
@@ -65,47 +65,45 @@ class TelegramTradingBot:
         if not self.application:
             return
         
-        dp = self.application.dispatcher # Get dispatcher for v13.x
-        
-        # Basic bot commands
-        dp.add_handler(CommandHandler("start", self.start_command))
-        dp.add_handler(CommandHandler("help", self.help_command))
+        # Basic bot commands (directly on application for v20.x)
+        self.application.add_handler(CommandHandler("start", self.start_command))
+        self.application.add_handler(CommandHandler("help", self.help_command))
         
         # Trading commands
-        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))
+        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))
         
         # Info commands
-        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
+        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
         
         # Management commands
-        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))
+        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))
         
         # Callback and message handlers
-        dp.add_handler(CallbackQueryHandler(self.trading_commands.button_callback))
+        self.application.add_handler(CallbackQueryHandler(self.trading_commands.button_callback))
         
     async def start_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /start command."""
@@ -278,7 +276,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 (v13.x compatible)."""
+        """Run the Telegram bot with manual initialization and shutdown (v20.x style)."""
         if not Config.TELEGRAM_BOT_TOKEN:
             logger.error("❌ TELEGRAM_BOT_TOKEN not configured")
             return
@@ -287,67 +285,72 @@ 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__} (Running in v13.x compatibility mode)")
+        logger.info(f"🔧 Using python-telegram-bot version: {telegram.__version__} (Running in v20.x style)")
 
-        # 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)
+        # Create application
+        self.application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).drop_pending_updates(True).build()
         
         # Connect notification manager to the bot application
         self.notification_manager.set_bot_application(self.application)
         
-        # Set up handlers (handlers are added to dispatcher inside setup_handlers)
+        # Set up handlers
         self.setup_handlers()
 
+        keep_running_future = asyncio.Future() # Future to keep the bot alive
+
         try:
-            logger.info(f"🚀 Starting Telegram trading bot v{self.version} (v13.x mode)...")
+            logger.info("🚀 Initializing bot application (v20.x style)...")
+            await self.application.initialize()
+            
+            logger.info(f"🚀 Starting Telegram trading bot v{self.version} (v20.x style)...")
             
-            # Send startup notification (await is fine, send_message is async)
             await self.send_message(
-                f"🤖 <b>Manual Trading Bot v{self.version} Started (v13.x mode)</b>\n\n"
+                f"🤖 <b>Manual Trading Bot v{self.version} Started (v20.x style)</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 (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 Updater polling (v13.x mode)...")
-            self.application.start_polling(drop_pending_updates=True)
+            logger.info("▶️ Starting PTB application (handlers, dispatcher, polling...) (v20.x style)...")
+            await self.application.start()
             
-            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.")
+            logger.info("Bot is now running. Awaiting external stop signal (e.g., Ctrl+C) (v20.x style)...")
+            await keep_running_future
                     
         except (KeyboardInterrupt, SystemExit):
-            logger.info("🛑 Bot run interrupted by user/system. Initiating shutdown...")
+            logger.info("🛑 Bot run interrupted by user/system. Initiating shutdown (v20.x style)...")
+            if not keep_running_future.done():
+                keep_running_future.set_exception(KeyboardInterrupt())
+        except asyncio.CancelledError:
+            logger.info("🛑 Bot run task cancelled. Initiating shutdown (v20.x style)...")
+            if not keep_running_future.done():
+                keep_running_future.cancel()
         except Exception as e:
-            logger.error(f"❌ Unhandled error in bot run loop (v13.x mode): {e}", exc_info=True)
+            logger.error(f"❌ Unhandled error in bot run loop (v20.x style): {e}", exc_info=True)
+            if not keep_running_future.done():
+                keep_running_future.set_exception(e)
         finally:
-            logger.info("🔌 Starting graceful shutdown sequence in TelegramTradingBot.run (v13.x mode)...")
+            logger.info("🔌 Starting graceful shutdown sequence in TelegramTradingBot.run (v20.x style)...")
             try:
                 logger.info("Stopping market monitor...")
                 await self.market_monitor.stop()
                 logger.info("Market monitor stopped.")
 
-                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.")
+                if self.application:
+                    logger.info("Attempting to stop PTB application (v20.x style)...")
+                    await self.application.stop() 
+                    logger.info("PTB application stop attempted.")
+                    
+                    logger.info("Shutting down PTB application (v20.x style)...")
+                    await self.application.shutdown()
+                    logger.info("PTB application shut down.")
+                else:
+                    logger.warning("Application object was None during shutdown in TelegramTradingBot.run.")
                 
-                logger.info("✅ Graceful shutdown sequence in TelegramTradingBot.run (v13.x mode) complete.")
+                logger.info("✅ Graceful shutdown sequence in TelegramTradingBot.run (v20.x style) complete.")
                 
             except Exception as e:
-                logger.error(f"💥 Error during shutdown sequence in TelegramTradingBot.run (v13.x mode): {e}", exc_info=True) 
+                logger.error(f"💥 Error during shutdown sequence in TelegramTradingBot.run (v20.x style): {e}", exc_info=True)