|
@@ -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)
|