فهرست منبع

Refactor Telegram bot command responses and authorization handling - Updated command methods to utilize context-based message sending for unauthorized access notifications. Enhanced logging for command execution and error handling, improving user feedback and traceability during bot operations. Streamlined command usage messages for clarity and consistency across trading and management commands.

Carles Sentis 5 روز پیش
والد
کامیت
c9bc3dbf2e
4فایلهای تغییر یافته به همراه242 افزوده شده و 228 حذف شده
  1. 31 8
      src/bot/core.py
  2. 90 76
      src/commands/info_commands.py
  3. 50 79
      src/commands/management_commands.py
  4. 71 65
      src/commands/trading_commands.py

+ 31 - 8
src/bot/core.py

@@ -108,8 +108,15 @@ class TelegramTradingBot:
     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."""
         logger.info(f"/start command triggered by chat_id: {update.effective_chat.id}")
         logger.info(f"/start command triggered by chat_id: {update.effective_chat.id}")
-        if not self.is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        logger.debug(f"Full Update object in start_command: {update}")
+
+        chat_id = update.effective_chat.id
+        if not self.is_authorized(chat_id):
+            logger.warning(f"Unauthorized access attempt by chat_id: {chat_id} in /start.")
+            try:
+                await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
+            except Exception as e:
+                logger.error(f"Error sending unauthorized message in /start: {e}")
             return
             return
         
         
         # Determine risk management and stop loss details from Config
         # Determine risk management and stop loss details from Config
@@ -211,12 +218,24 @@ Type /help for detailed command information.
 For support, contact your bot administrator.
 For support, contact your bot administrator.
         """
         """
         
         
-        await update.message.reply_text(welcome_text, parse_mode='HTML')
+        logger.debug(f"In /start, update.message is: {update.message}, update.effective_chat.id is: {chat_id}")
+        try:
+            await context.bot.send_message(chat_id=chat_id, text=welcome_text, parse_mode='HTML')
+        except Exception as e:
+            logger.error(f"Error sending welcome message in /start: {e}")
     
     
     async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def help_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /help command."""
         """Handle the /help command."""
-        if not self.is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        logger.info(f"/help command triggered by chat_id: {update.effective_chat.id}")
+        logger.debug(f"Full Update object in help_command: {update}")
+
+        chat_id = update.effective_chat.id
+        if not self.is_authorized(chat_id):
+            logger.warning(f"Unauthorized access attempt by chat_id: {chat_id} in /help.")
+            try:
+                await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
+            except Exception as e:
+                logger.error(f"Error sending unauthorized message in /help: {e}")
             return
             return
         
         
         help_text = """
         help_text = """
@@ -250,7 +269,11 @@ For support, contact your bot administrator.
 For support or issues, check the logs or contact the administrator.
 For support or issues, check the logs or contact the administrator.
         """
         """
         
         
-        await update.message.reply_text(help_text, parse_mode='HTML')
+        logger.debug(f"In /help, update.message is: {update.message}, update.effective_chat.id is: {chat_id}")
+        try:
+            await context.bot.send_message(chat_id=chat_id, text=help_text, parse_mode='HTML')
+        except Exception as 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 with manual initialization and shutdown."""
@@ -265,7 +288,7 @@ For support or issues, check the logs or contact the administrator.
         # logger.info(f"🔧 Using python-telegram-bot version: {telegram.__version__}") # NO LONGER NEEDED
         # logger.info(f"🔧 Using python-telegram-bot version: {telegram.__version__}") # NO LONGER NEEDED
 
 
         # Create application
         # Create application
-        self.application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).build()
+        self.application = Application.builder().token(Config.TELEGRAM_BOT_TOKEN).drop_pending_updates(True).build()
         
         
         # 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)
@@ -277,7 +300,7 @@ For support or issues, check the logs or contact the administrator.
 
 
         try:
         try:
             logger.info("🚀 Initializing bot application...")
             logger.info("🚀 Initializing bot application...")
-            await self.application.initialize(drop_pending_updates=True)
+            await self.application.initialize()
             
             
             logger.info(f"🚀 Starting Telegram trading bot v{self.version}...")
             logger.info(f"🚀 Starting Telegram trading bot v{self.version}...")
             
             

+ 90 - 76
src/commands/info_commands.py

@@ -26,8 +26,9 @@ class InfoCommands:
     
     
     async def balance_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def balance_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /balance command."""
         """Handle the /balance command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         balance = self.trading_engine.get_balance()
         balance = self.trading_engine.get_balance()
@@ -93,14 +94,15 @@ class InfoCommands:
                 balance_text += f"   💵 Initial: ${initial_balance:,.2f}\n"
                 balance_text += f"   💵 Initial: ${initial_balance:,.2f}\n"
                 balance_text += f"   {pnl_emoji} P&L: ${pnl:,.2f} ({pnl_percent:+.2f}%)\n"
                 balance_text += f"   {pnl_emoji} P&L: ${pnl:,.2f} ({pnl_percent:+.2f}%)\n"
             
             
-            await update.message.reply_text(balance_text, parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=balance_text, parse_mode='HTML')
         else:
         else:
-            await update.message.reply_text("❌ Could not fetch balance information")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Could not fetch balance information")
     
     
     async def positions_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def positions_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /positions command."""
         """Handle the /positions command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         positions = self.trading_engine.get_positions()
         positions = self.trading_engine.get_positions()
@@ -168,14 +170,15 @@ class InfoCommands:
                 positions_text += "📭 No open positions\n\n"
                 positions_text += "📭 No open positions\n\n"
                 positions_text += "💡 Use /long or /short to open a position"
                 positions_text += "💡 Use /long or /short to open a position"
             
             
-            await update.message.reply_text(positions_text, parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=positions_text, parse_mode='HTML')
         else:
         else:
-            await update.message.reply_text("❌ Could not fetch positions")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Could not fetch positions")
     
     
     async def orders_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def orders_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /orders command."""
         """Handle the /orders command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         orders = self.trading_engine.get_orders()
         orders = self.trading_engine.get_orders()
@@ -216,14 +219,15 @@ class InfoCommands:
                 orders_text += "📭 No open orders\n\n"
                 orders_text += "📭 No open orders\n\n"
                 orders_text += "💡 Use /long, /short, /sl, or /tp to create orders"
                 orders_text += "💡 Use /long, /short, /sl, or /tp to create orders"
             
             
-            await update.message.reply_text(orders_text, parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=orders_text, parse_mode='HTML')
         else:
         else:
-            await update.message.reply_text("❌ Could not fetch orders")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Could not fetch orders")
     
     
     async def stats_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def stats_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /stats command."""
         """Handle the /stats command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         # Get current balance for stats
         # Get current balance for stats
@@ -235,25 +239,26 @@ class InfoCommands:
         stats = self.trading_engine.get_stats()
         stats = self.trading_engine.get_stats()
         if stats:
         if stats:
             stats_message = stats.format_stats_message(current_balance)
             stats_message = stats.format_stats_message(current_balance)
-            await update.message.reply_text(stats_message, parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=stats_message, parse_mode='HTML')
         else:
         else:
-            await update.message.reply_text("❌ Could not load trading statistics")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
     
     
     async def trades_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def trades_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /trades command."""
         """Handle the /trades command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         stats = self.trading_engine.get_stats()
         stats = self.trading_engine.get_stats()
         if not stats:
         if not stats:
-            await update.message.reply_text("❌ Could not load trading statistics")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
             return
             return
         
         
         recent_trades = stats.get_recent_trades(10)
         recent_trades = stats.get_recent_trades(10)
         
         
         if not recent_trades:
         if not recent_trades:
-            await update.message.reply_text("📝 No trades recorded yet.")
+            await context.bot.send_message(chat_id=chat_id, text="📝 No trades recorded yet.")
             return
             return
         
         
         trades_text = "🔄 <b>Recent Trades</b>\n\n"
         trades_text = "🔄 <b>Recent Trades</b>\n\n"
@@ -266,12 +271,13 @@ class InfoCommands:
             trades_text += f"   💰 ${trade['price']:,.2f} | 💵 ${trade['value']:,.2f}\n"
             trades_text += f"   💰 ${trade['price']:,.2f} | 💵 ${trade['value']:,.2f}\n"
             trades_text += f"   📅 {timestamp}\n\n"
             trades_text += f"   📅 {timestamp}\n\n"
         
         
-        await update.message.reply_text(trades_text, parse_mode='HTML')
+        await context.bot.send_message(chat_id=chat_id, text=trades_text, parse_mode='HTML')
     
     
     async def market_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def market_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /market command."""
         """Handle the /market command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         # Get token from arguments or use default
         # Get token from arguments or use default
@@ -316,14 +322,15 @@ class InfoCommands:
 ⏰ <b>Last Updated:</b> {datetime.now().strftime('%H:%M:%S')}
 ⏰ <b>Last Updated:</b> {datetime.now().strftime('%H:%M:%S')}
             """
             """
             
             
-            await update.message.reply_text(market_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=market_text.strip(), parse_mode='HTML')
         else:
         else:
-            await update.message.reply_text(f"❌ Could not fetch market data for {token}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Could not fetch market data for {token}")
     
     
     async def price_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def price_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /price command."""
         """Handle the /price command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         # Get token from arguments or use default
         # Get token from arguments or use default
@@ -353,14 +360,15 @@ class InfoCommands:
 ⏰ {datetime.now().strftime('%H:%M:%S')}
 ⏰ {datetime.now().strftime('%H:%M:%S')}
             """
             """
             
             
-            await update.message.reply_text(price_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=price_text.strip(), parse_mode='HTML')
         else:
         else:
-            await update.message.reply_text(f"❌ Could not fetch price for {token}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Could not fetch price for {token}")
     
     
     async def performance_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def performance_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /performance command to show token performance ranking or detailed stats."""
         """Handle the /performance command to show token performance ranking or detailed stats."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
@@ -368,27 +376,27 @@ class InfoCommands:
             if context.args and len(context.args) >= 1:
             if context.args and len(context.args) >= 1:
                 # Detailed performance for specific token
                 # Detailed performance for specific token
                 token = context.args[0].upper()
                 token = context.args[0].upper()
-                await self._show_token_performance(update, token)
+                await self._show_token_performance(chat_id, token, context)
             else:
             else:
                 # Show token performance ranking
                 # Show token performance ranking
-                await self._show_performance_ranking(update)
+                await self._show_performance_ranking(chat_id, context)
                 
                 
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing performance command: {str(e)}"
             error_message = f"❌ Error processing performance command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in performance command: {e}")
             logger.error(f"Error in performance command: {e}")
 
 
-    async def _show_performance_ranking(self, update: Update):
+    async def _show_performance_ranking(self, chat_id: str, context: ContextTypes.DEFAULT_TYPE):
         """Show token performance ranking (compressed view)."""
         """Show token performance ranking (compressed view)."""
         stats = self.trading_engine.get_stats()
         stats = self.trading_engine.get_stats()
         if not stats:
         if not stats:
-            await update.message.reply_text("❌ Could not load trading statistics")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
             return
             return
             
             
         token_performance = stats.get_token_performance()
         token_performance = stats.get_token_performance()
         
         
         if not token_performance:
         if not token_performance:
-            await update.message.reply_text(
+            await context.bot.send_message(chat_id=chat_id, text=
                 "📊 <b>Token Performance</b>\n\n"
                 "📊 <b>Token Performance</b>\n\n"
                 "📭 No trading data available yet.\n\n"
                 "📭 No trading data available yet.\n\n"
                 "💡 Performance tracking starts after your first completed trades.\n"
                 "💡 Performance tracking starts after your first completed trades.\n"
@@ -444,20 +452,20 @@ class InfoCommands:
         
         
         performance_text += f"💡 <b>Usage:</b> <code>/performance BTC</code> for detailed {Config.DEFAULT_TRADING_TOKEN} stats"
         performance_text += f"💡 <b>Usage:</b> <code>/performance BTC</code> for detailed {Config.DEFAULT_TRADING_TOKEN} stats"
         
         
-        await update.message.reply_text(performance_text.strip(), parse_mode='HTML')
+        await context.bot.send_message(chat_id=chat_id, text=performance_text.strip(), parse_mode='HTML')
 
 
-    async def _show_token_performance(self, update: Update, token: str):
+    async def _show_token_performance(self, chat_id: str, token: str, context: ContextTypes.DEFAULT_TYPE):
         """Show detailed performance for a specific token."""
         """Show detailed performance for a specific token."""
         stats = self.trading_engine.get_stats()
         stats = self.trading_engine.get_stats()
         if not stats:
         if not stats:
-            await update.message.reply_text("❌ Could not load trading statistics")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
             return
             return
             
             
         token_stats = stats.get_token_detailed_stats(token)
         token_stats = stats.get_token_detailed_stats(token)
         
         
         # Check if token has any data
         # Check if token has any data
         if token_stats.get('total_trades', 0) == 0:
         if token_stats.get('total_trades', 0) == 0:
-            await update.message.reply_text(
+            await context.bot.send_message(chat_id=chat_id, text=
                 f"📊 <b>{token} Performance</b>\n\n"
                 f"📊 <b>{token} Performance</b>\n\n"
                 f"📭 No trading history found for {token}.\n\n"
                 f"📭 No trading history found for {token}.\n\n"
                 f"💡 Start trading {token} with:\n"
                 f"💡 Start trading {token} with:\n"
@@ -470,7 +478,7 @@ class InfoCommands:
         
         
         # Check if there's a message (no completed trades)
         # Check if there's a message (no completed trades)
         if 'message' in token_stats and token_stats.get('completed_trades', 0) == 0:
         if 'message' in token_stats and token_stats.get('completed_trades', 0) == 0:
-            await update.message.reply_text(
+            await context.bot.send_message(chat_id=chat_id, text=
                 f"📊 <b>{token} Performance</b>\n\n"
                 f"📊 <b>{token} Performance</b>\n\n"
                 f"{token_stats['message']}\n\n"
                 f"{token_stats['message']}\n\n"
                 f"📈 <b>Current Activity:</b>\n"
                 f"📈 <b>Current Activity:</b>\n"
@@ -525,24 +533,25 @@ class InfoCommands:
         
         
         performance_text += f"\n🔄 Use <code>/performance</code> to see all token rankings"
         performance_text += f"\n🔄 Use <code>/performance</code> to see all token rankings"
         
         
-        await update.message.reply_text(performance_text.strip(), parse_mode='HTML')
+        await context.bot.send_message(chat_id=chat_id, text=performance_text.strip(), parse_mode='HTML')
 
 
     async def daily_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def daily_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /daily command to show daily performance stats."""
         """Handle the /daily command to show daily performance stats."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             stats = self.trading_engine.get_stats()
             stats = self.trading_engine.get_stats()
             if not stats:
             if not stats:
-                await update.message.reply_text("❌ Could not load trading statistics")
+                await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
                 return
                 return
                 
                 
             daily_stats = stats.get_daily_stats(10)
             daily_stats = stats.get_daily_stats(10)
             
             
             if not daily_stats:
             if not daily_stats:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=
                     "📅 <b>Daily Performance</b>\n\n"
                     "📅 <b>Daily Performance</b>\n\n"
                     "📭 No daily performance data available yet.\n\n"
                     "📭 No daily performance data available yet.\n\n"
                     "💡 Daily stats are calculated from completed trades.\n"
                     "💡 Daily stats are calculated from completed trades.\n"
@@ -584,29 +593,30 @@ class InfoCommands:
                 daily_text += f"   📈 Avg Daily P&L: ${avg_daily_pnl:,.2f}\n"
                 daily_text += f"   📈 Avg Daily P&L: ${avg_daily_pnl:,.2f}\n"
                 daily_text += f"   🔄 Total Trades: {total_trades}\n"
                 daily_text += f"   🔄 Total Trades: {total_trades}\n"
             
             
-            await update.message.reply_text(daily_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=daily_text.strip(), parse_mode='HTML')
                 
                 
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing daily command: {str(e)}"
             error_message = f"❌ Error processing daily command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in daily command: {e}")
             logger.error(f"Error in daily command: {e}")
     
     
     async def weekly_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def weekly_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /weekly command to show weekly performance stats."""
         """Handle the /weekly command to show weekly performance stats."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             stats = self.trading_engine.get_stats()
             stats = self.trading_engine.get_stats()
             if not stats:
             if not stats:
-                await update.message.reply_text("❌ Could not load trading statistics")
+                await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
                 return
                 return
                 
                 
             weekly_stats = stats.get_weekly_stats(10)
             weekly_stats = stats.get_weekly_stats(10)
             
             
             if not weekly_stats:
             if not weekly_stats:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=
                     "📊 <b>Weekly Performance</b>\n\n"
                     "📊 <b>Weekly Performance</b>\n\n"
                     "📭 No weekly performance data available yet.\n\n"
                     "📭 No weekly performance data available yet.\n\n"
                     "💡 Weekly stats are calculated from completed trades.\n"
                     "💡 Weekly stats are calculated from completed trades.\n"
@@ -650,29 +660,30 @@ class InfoCommands:
                 weekly_text += f"   📭 No completed trades in the last 10 weeks\n"
                 weekly_text += f"   📭 No completed trades in the last 10 weeks\n"
                 weekly_text += f"   💡 Start trading to see weekly performance!"
                 weekly_text += f"   💡 Start trading to see weekly performance!"
             
             
-            await update.message.reply_text(weekly_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=weekly_text.strip(), parse_mode='HTML')
             
             
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing weekly command: {str(e)}"
             error_message = f"❌ Error processing weekly command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in weekly command: {e}")
             logger.error(f"Error in weekly command: {e}")
 
 
     async def monthly_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def monthly_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /monthly command to show monthly performance stats."""
         """Handle the /monthly command to show monthly performance stats."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             stats = self.trading_engine.get_stats()
             stats = self.trading_engine.get_stats()
             if not stats:
             if not stats:
-                await update.message.reply_text("❌ Could not load trading statistics")
+                await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
                 return
                 return
                 
                 
             monthly_stats = stats.get_monthly_stats(10)
             monthly_stats = stats.get_monthly_stats(10)
             
             
             if not monthly_stats:
             if not monthly_stats:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=
                     "📆 <b>Monthly Performance</b>\n\n"
                     "📆 <b>Monthly Performance</b>\n\n"
                     "📭 No monthly performance data available yet.\n\n"
                     "📭 No monthly performance data available yet.\n\n"
                     "💡 Monthly stats are calculated from completed trades.\n"
                     "💡 Monthly stats are calculated from completed trades.\n"
@@ -716,17 +727,18 @@ class InfoCommands:
                 monthly_text += f"   📭 No completed trades in the last 10 months\n"
                 monthly_text += f"   📭 No completed trades in the last 10 months\n"
                 monthly_text += f"   💡 Start trading to see monthly performance!"
                 monthly_text += f"   💡 Start trading to see monthly performance!"
             
             
-            await update.message.reply_text(monthly_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=monthly_text.strip(), parse_mode='HTML')
             
             
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing monthly command: {str(e)}"
             error_message = f"❌ Error processing monthly command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in monthly command: {e}")
             logger.error(f"Error in monthly command: {e}")
     
     
     async def risk_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def risk_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /risk command to show advanced risk metrics."""
         """Handle the /risk command to show advanced risk metrics."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
@@ -739,7 +751,7 @@ class InfoCommands:
             # Get risk metrics and basic stats
             # Get risk metrics and basic stats
             stats = self.trading_engine.get_stats()
             stats = self.trading_engine.get_stats()
             if not stats:
             if not stats:
-                await update.message.reply_text("❌ Could not load trading statistics")
+                await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
                 return
                 return
                 
                 
             risk_metrics = stats.get_risk_metrics()
             risk_metrics = stats.get_risk_metrics()
@@ -747,7 +759,7 @@ class InfoCommands:
             
             
             # Check if we have enough data for risk calculations
             # Check if we have enough data for risk calculations
             if basic_stats['completed_trades'] < 2:
             if basic_stats['completed_trades'] < 2:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=
                     "📊 <b>Risk Analysis</b>\n\n"
                     "📊 <b>Risk Analysis</b>\n\n"
                     "📭 <b>Insufficient Data</b>\n\n"
                     "📭 <b>Insufficient Data</b>\n\n"
                     f"• Current completed trades: {basic_stats['completed_trades']}\n"
                     f"• Current completed trades: {basic_stats['completed_trades']}\n"
@@ -834,23 +846,24 @@ class InfoCommands:
 🔄 Use /stats for trading performance metrics
 🔄 Use /stats for trading performance metrics
             """
             """
             
             
-            await update.message.reply_text(risk_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=risk_text.strip(), parse_mode='HTML')
             
             
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing risk command: {str(e)}"
             error_message = f"❌ Error processing risk command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in risk command: {e}")
             logger.error(f"Error in risk command: {e}")
     
     
     async def balance_adjustments_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def balance_adjustments_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /balance_adjustments command to show deposit/withdrawal history."""
         """Handle the /balance_adjustments command to show deposit/withdrawal history."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             stats = self.trading_engine.get_stats()
             stats = self.trading_engine.get_stats()
             if not stats:
             if not stats:
-                await update.message.reply_text("❌ Could not load trading statistics")
+                await context.bot.send_message(chat_id=chat_id, text="❌ Could not load trading statistics")
                 return
                 return
             
             
             # Get balance adjustments summary
             # Get balance adjustments summary
@@ -860,7 +873,7 @@ class InfoCommands:
             all_adjustments = stats.data.get('balance_adjustments', [])
             all_adjustments = stats.data.get('balance_adjustments', [])
             
             
             if not all_adjustments:
             if not all_adjustments:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=
                     "💰 <b>Balance Adjustments</b>\n\n"
                     "💰 <b>Balance Adjustments</b>\n\n"
                     "📭 No deposits or withdrawals detected yet.\n\n"
                     "📭 No deposits or withdrawals detected yet.\n\n"
                     "💡 The bot automatically monitors for deposits and withdrawals\n"
                     "💡 The bot automatically monitors for deposits and withdrawals\n"
@@ -915,17 +928,18 @@ class InfoCommands:
 ⏰ <b>Last Check:</b> {adjustments_summary['last_adjustment'][:16] if adjustments_summary['last_adjustment'] else 'Never'}
 ⏰ <b>Last Check:</b> {adjustments_summary['last_adjustment'][:16] if adjustments_summary['last_adjustment'] else 'Never'}
             """
             """
             
             
-            await update.message.reply_text(adjustments_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=adjustments_text.strip(), parse_mode='HTML')
             
             
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing balance adjustments command: {str(e)}"
             error_message = f"❌ Error processing balance adjustments command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in balance_adjustments command: {e}")
             logger.error(f"Error in balance_adjustments command: {e}")
     
     
     async def commands_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def commands_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /commands and /c command with quick action buttons."""
         """Handle the /commands and /c command with quick action buttons."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         commands_text = """
         commands_text = """
@@ -973,4 +987,4 @@ Tap any button below for instant access to bot functions:
         ]
         ]
         reply_markup = InlineKeyboardMarkup(keyboard)
         reply_markup = InlineKeyboardMarkup(keyboard)
         
         
-        await update.message.reply_text(commands_text, parse_mode='HTML', reply_markup=reply_markup) 
+        await context.bot.send_message(chat_id=chat_id, text=commands_text, parse_mode='HTML', reply_markup=reply_markup) 

+ 50 - 79
src/commands/management_commands.py

@@ -8,7 +8,7 @@ import os
 import platform
 import platform
 import sys
 import sys
 from datetime import datetime, timedelta
 from datetime import datetime, timedelta
-from telegram import Update
+from telegram import Update, ReplyKeyboardMarkup, KeyboardButton, InlineKeyboardMarkup
 from telegram.ext import ContextTypes
 from telegram.ext import ContextTypes
 import json
 import json
 
 
@@ -32,8 +32,9 @@ class ManagementCommands:
     
     
     async def monitoring_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def monitoring_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /monitoring command."""
         """Handle the /monitoring command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         # Get alarm statistics
         # Get alarm statistics
@@ -105,12 +106,13 @@ class ManagementCommands:
             for token, count in alarm_stats['token_breakdown'].items():
             for token, count in alarm_stats['token_breakdown'].items():
                 status_text += f"• {token}: {count} alarm{'s' if count != 1 else ''}\n"
                 status_text += f"• {token}: {count} alarm{'s' if count != 1 else ''}\n"
         
         
-        await update.message.reply_text(status_text.strip(), parse_mode='HTML')
+        await context.bot.send_message(chat_id=chat_id, text=status_text.strip(), parse_mode='HTML')
     
     
     async def alarm_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def alarm_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /alarm command."""
         """Handle the /alarm command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
@@ -118,7 +120,7 @@ class ManagementCommands:
                 # No arguments - list all alarms
                 # No arguments - list all alarms
                 alarms = self.alarm_manager.get_all_active_alarms()
                 alarms = self.alarm_manager.get_all_active_alarms()
                 message = self.alarm_manager.format_alarm_list(alarms)
                 message = self.alarm_manager.format_alarm_list(alarms)
-                await update.message.reply_text(message, parse_mode='HTML')
+                await context.bot.send_message(chat_id=chat_id, text=message, parse_mode='HTML')
                 return
                 return
             
             
             elif len(context.args) == 1:
             elif len(context.args) == 1:
@@ -129,16 +131,16 @@ class ManagementCommands:
                     alarm_id = int(arg)
                     alarm_id = int(arg)
                     # Remove alarm by ID
                     # Remove alarm by ID
                     if self.alarm_manager.remove_alarm(alarm_id):
                     if self.alarm_manager.remove_alarm(alarm_id):
-                        await update.message.reply_text(f"✅ Alarm ID {alarm_id} has been removed.")
+                        await context.bot.send_message(chat_id=chat_id, text=f"✅ Alarm ID {alarm_id} has been removed.")
                     else:
                     else:
-                        await update.message.reply_text(f"❌ Alarm ID {alarm_id} not found.")
+                        await context.bot.send_message(chat_id=chat_id, text=f"❌ Alarm ID {alarm_id} not found.")
                     return
                     return
                 except ValueError:
                 except ValueError:
                     # Not a number, treat as token
                     # Not a number, treat as token
                     token = arg.upper()
                     token = arg.upper()
                     alarms = self.alarm_manager.get_alarms_by_token(token)
                     alarms = self.alarm_manager.get_alarms_by_token(token)
                     message = self.alarm_manager.format_alarm_list(alarms, f"{token} Price Alarms")
                     message = self.alarm_manager.format_alarm_list(alarms, f"{token} Price Alarms")
-                    await update.message.reply_text(message, parse_mode='HTML')
+                    await context.bot.send_message(chat_id=chat_id, text=message, parse_mode='HTML')
                     return
                     return
             
             
             elif len(context.args) == 2:
             elif len(context.args) == 2:
@@ -151,12 +153,12 @@ class ManagementCommands:
                 market_data = self.trading_engine.get_market_data(symbol)
                 market_data = self.trading_engine.get_market_data(symbol)
                 
                 
                 if not market_data or not market_data.get('ticker'):
                 if not market_data or not market_data.get('ticker'):
-                    await update.message.reply_text(f"❌ Could not fetch current price for {token}")
+                    await context.bot.send_message(chat_id=chat_id, text=f"❌ Could not fetch current price for {token}")
                     return
                     return
                 
                 
                 current_price = float(market_data['ticker'].get('last', 0))
                 current_price = float(market_data['ticker'].get('last', 0))
                 if current_price <= 0:
                 if current_price <= 0:
-                    await update.message.reply_text(f"❌ Invalid current price for {token}")
+                    await context.bot.send_message(chat_id=chat_id, text=f"❌ Invalid current price for {token}")
                     return
                     return
                 
                 
                 # Create the alarm
                 # Create the alarm
@@ -189,44 +191,44 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
 💡 The alarm will be checked every {Config.BOT_HEARTBEAT_SECONDS} seconds and you'll receive a notification when triggered.
 💡 The alarm will be checked every {Config.BOT_HEARTBEAT_SECONDS} seconds and you'll receive a notification when triggered.
                 """
                 """
                 
                 
-                await update.message.reply_text(message.strip(), parse_mode='HTML')
+                await context.bot.send_message(chat_id=chat_id, text=message.strip(), parse_mode='HTML')
                 
                 
             else:
             else:
                 # Too many arguments
                 # Too many arguments
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     "❌ Invalid usage. Examples:\n\n"
                     "❌ Invalid usage. Examples:\n\n"
                     "• <code>/alarm</code> - List all alarms\n"
                     "• <code>/alarm</code> - List all alarms\n"
                     "• <code>/alarm BTC</code> - List BTC alarms\n"
                     "• <code>/alarm BTC</code> - List BTC alarms\n"
                     "• <code>/alarm BTC 50000</code> - Set alarm for BTC at $50,000\n"
                     "• <code>/alarm BTC 50000</code> - Set alarm for BTC at $50,000\n"
-                    "• <code>/alarm 3</code> - Remove alarm ID 3",
-                    parse_mode='HTML'
-                )
+                    "• <code>/alarm 3</code> - Remove alarm ID 3"
+                ), parse_mode='HTML')
                 
                 
         except ValueError:
         except ValueError:
-            await update.message.reply_text("❌ Invalid price format. Please use numbers only.")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Invalid price format. Please use numbers only.")
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing alarm command: {str(e)}"
             error_message = f"❌ Error processing alarm command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in alarm command: {e}")
             logger.error(f"Error in alarm command: {e}")
     
     
     async def logs_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def logs_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /logs command."""
         """Handle the /logs command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             logs_dir = "logs"
             logs_dir = "logs"
             
             
             if not os.path.exists(logs_dir):
             if not os.path.exists(logs_dir):
-                await update.message.reply_text("📜 No logs directory found.")
+                await context.bot.send_message(chat_id=chat_id, text="📜 No logs directory found.")
                 return
                 return
             
             
             # Get log files
             # Get log files
             log_files = [f for f in os.listdir(logs_dir) if f.endswith('.log')]
             log_files = [f for f in os.listdir(logs_dir) if f.endswith('.log')]
             
             
             if not log_files:
             if not log_files:
-                await update.message.reply_text("📜 No log files found.")
+                await context.bot.send_message(chat_id=chat_id, text="📜 No log files found.")
                 return
                 return
             
             
             # Handle cleanup command
             # Handle cleanup command
@@ -236,7 +238,7 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
                     try:
                     try:
                         days_to_keep = int(context.args[1])
                         days_to_keep = int(context.args[1])
                     except ValueError:
                     except ValueError:
-                        await update.message.reply_text("❌ Invalid number of days. Using default (30 days).")
+                        await context.bot.send_message(chat_id=chat_id, text="❌ Invalid number of days. Using default (30 days).")
                 
                 
                 # Clean up old log files
                 # Clean up old log files
                 cutoff_date = datetime.now() - timedelta(days=days_to_keep)
                 cutoff_date = datetime.now() - timedelta(days=days_to_keep)
@@ -254,19 +256,13 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
                         cleaned_files += 1
                         cleaned_files += 1
                         total_size_cleaned += file_size
                         total_size_cleaned += file_size
                 
                 
-                cleanup_message = f"""
-🧹 <b>Log Cleanup Complete</b>
-
-📊 <b>Cleanup Results:</b>
-• Files Removed: {cleaned_files}
-• Size Freed: {total_size_cleaned / 1024 / 1024:.2f} MB
-• Cutoff Date: {cutoff_date.strftime('%Y-%m-%d')}
-• Days Kept: {days_to_keep}
-
-✅ <b>Status:</b> Cleanup completed successfully
-                """
-                
-                await update.message.reply_text(cleanup_message.strip(), parse_mode='HTML')
+                size_cleaned_mb = total_size_cleaned / (1024 * 1024)
+                await context.bot.send_message(chat_id=chat_id, text=
+                    f"🧹 Log cleanup complete.\n"
+                    f"• Files older than {days_to_keep} days removed.\n"
+                    f"• Total files deleted: {cleaned_files}\n"
+                    f"• Total size cleaned: {size_cleaned_mb:.2f} MB"
+                )
                 return
                 return
             
             
             # Show log statistics
             # Show log statistics
@@ -327,17 +323,18 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
 • DEBUG: Detailed debugging (if enabled)
 • DEBUG: Detailed debugging (if enabled)
             """
             """
             
             
-            await update.message.reply_text(logs_message.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=logs_message.strip(), parse_mode='HTML')
             
             
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing logs command: {str(e)}"
             error_message = f"❌ Error processing logs command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in logs command: {e}")
             logger.error(f"Error in logs command: {e}")
     
     
     async def debug_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def debug_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /debug command."""
         """Handle the /debug command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
@@ -397,16 +394,17 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
             except Exception as e:
             except Exception as e:
                 debug_info += f"\n💰 <b>Balance:</b> Error fetching ({str(e)})\n"
                 debug_info += f"\n💰 <b>Balance:</b> Error fetching ({str(e)})\n"
             
             
-            await update.message.reply_text(debug_info.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=debug_info.strip(), parse_mode='HTML')
             
             
         except Exception as e:
         except Exception as e:
             logger.error(f"❌ Error in debug command: {e}")
             logger.error(f"❌ Error in debug command: {e}")
-            await update.message.reply_text(f"❌ Debug error: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Debug error: {e}")
     
     
     async def version_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def version_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /version command."""
         """Handle the /version command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
@@ -459,17 +457,18 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
 ⏰ <b>Current Time:</b> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
 ⏰ <b>Current Time:</b> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
             """
             """
             
             
-            await update.message.reply_text(version_text.strip(), parse_mode='HTML')
+            await context.bot.send_message(chat_id=chat_id, text=version_text.strip(), parse_mode='HTML')
             
             
         except Exception as e:
         except Exception as e:
             error_message = f"❌ Error processing version command: {str(e)}"
             error_message = f"❌ Error processing version command: {str(e)}"
-            await update.message.reply_text(error_message)
+            await context.bot.send_message(chat_id=chat_id, text=error_message)
             logger.error(f"Error in version command: {e}")
             logger.error(f"Error in version command: {e}")
     
     
     async def keyboard_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def keyboard_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /keyboard command to enable/show custom keyboard."""
         """Handle the /keyboard command to enable/show custom keyboard."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         # Check if custom keyboard is enabled in config
         # Check if custom keyboard is enabled in config
@@ -477,8 +476,6 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
         
         
         if keyboard_enabled:
         if keyboard_enabled:
             # Create a simple reply keyboard with common commands
             # Create a simple reply keyboard with common commands
-            from telegram import ReplyKeyboardMarkup, KeyboardButton
-            
             keyboard = [
             keyboard = [
                 [KeyboardButton("/balance"), KeyboardButton("/positions")],
                 [KeyboardButton("/balance"), KeyboardButton("/positions")],
                 [KeyboardButton("/orders"), KeyboardButton("/stats")],
                 [KeyboardButton("/orders"), KeyboardButton("/stats")],
@@ -493,32 +490,6 @@ Will trigger when {token} price moves {alarm['direction']} ${target_price:,.2f}
                 selective=True
                 selective=True
             )
             )
             
             
-            await update.message.reply_text(
-                "⌨️ <b>Custom Keyboard Activated!</b>\n\n"
-                "🎯 <b>Your quick buttons are now ready:</b>\n"
-                "• /balance - Account balance\n"
-                "• /positions - Open positions\n"
-                "• /orders - Active orders\n"
-                "• /stats - Trading statistics\n"
-                "• /daily - Daily performance\n"
-                "• /performance - Performance stats\n"
-                "• /help - Help guide\n"
-                "• /commands - Command menu\n\n"
-                "💡 <b>How to use:</b>\n"
-                "Tap any button below to send the command instantly!\n\n"
-                "🔧 These buttons will stay at the bottom of your chat.",
-                parse_mode='HTML',
-                reply_markup=reply_markup
-            )
+            await context.bot.send_message(chat_id=chat_id, text="⌨️ <b>Custom Keyboard Activated!</b>\n\n🎯 <b>Your quick buttons are now ready:</b>\n• /balance - Account balance\n• /positions - Open positions\n• /orders - Active orders\n• /stats - Trading statistics\n• /daily - Daily performance\n• /performance - Performance stats\n• /help - Help guide\n• /commands - Command menu\n\n💡 <b>How to use:</b>\nTap any button below to send the command instantly!\n\n🔧 These buttons will stay at the bottom of your chat.", reply_markup=reply_markup, parse_mode='HTML')
         else:
         else:
-            await update.message.reply_text(
-                "❌ <b>Custom Keyboard Disabled</b>\n\n"
-                "🔧 <b>To enable:</b>\n"
-                "• Set TELEGRAM_CUSTOM_KEYBOARD_ENABLED=true in your .env file\n"
-                "• Restart the bot\n"
-                "• Run /keyboard again\n\n"
-                f"📋 <b>Current config:</b>\n"
-                f"• Enabled: {keyboard_enabled}\n"
-                f"• Layout: {getattr(Config, 'TELEGRAM_CUSTOM_KEYBOARD_LAYOUT', 'default')}",
-                parse_mode='HTML'
-            ) 
+            await context.bot.send_message(chat_id=chat_id, text="❌ <b>Custom Keyboard Disabled</b>\n\n🔧 <b>To enable:</b>\n• Set TELEGRAM_CUSTOM_KEYBOARD_ENABLED=true in your .env file\n• Restart the bot\n• Run /keyboard again\n\n📋 <b>Current config:</b>\n• Enabled: {keyboard_enabled}\n• Layout: {getattr(Config, 'TELEGRAM_CUSTOM_KEYBOARD_LAYOUT', 'default')}", parse_mode='HTML') 

+ 71 - 65
src/commands/trading_commands.py

@@ -26,20 +26,21 @@ class TradingCommands:
     
     
     async def long_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def long_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /long command for opening long positions."""
         """Handle the /long command for opening long positions."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             if not context.args or len(context.args) < 2:
             if not context.args or len(context.args) < 2:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     "❌ Usage: /long [token] [USDC amount] [price (optional)] [sl:price (optional)]\n"
                     "❌ Usage: /long [token] [USDC amount] [price (optional)] [sl:price (optional)]\n"
                     "Examples:\n"
                     "Examples:\n"
                     "• /long BTC 100 - Market order\n"
                     "• /long BTC 100 - Market order\n"
                     "• /long BTC 100 45000 - Limit order at $45,000\n"
                     "• /long BTC 100 45000 - Limit order at $45,000\n"
                     "• /long BTC 100 sl:44000 - Market order with stop loss at $44,000\n"
                     "• /long BTC 100 sl:44000 - Market order with stop loss at $44,000\n"
                     "• /long BTC 100 45000 sl:44000 - Limit order at $45,000 with stop loss at $44,000"
                     "• /long BTC 100 45000 sl:44000 - Limit order at $45,000 with stop loss at $44,000"
-                )
+                ))
                 return
                 return
             
             
             token = context.args[0].upper()
             token = context.args[0].upper()
@@ -56,25 +57,25 @@ class TradingCommands:
                     try:
                     try:
                         stop_loss_price = float(arg[3:])  # Remove 'sl:' prefix
                         stop_loss_price = float(arg[3:])  # Remove 'sl:' prefix
                     except ValueError:
                     except ValueError:
-                        await update.message.reply_text("❌ Invalid stop loss price format. Use sl:price (e.g., sl:44000)")
+                        await context.bot.send_message(chat_id=chat_id, text="❌ Invalid stop loss price format. Use sl:price (e.g., sl:44000)")
                         return
                         return
                 elif limit_price is None:
                 elif limit_price is None:
                     # First non-sl parameter is the limit price
                     # First non-sl parameter is the limit price
                     try:
                     try:
                         limit_price = float(arg)
                         limit_price = float(arg)
                     except ValueError:
                     except ValueError:
-                        await update.message.reply_text("❌ Invalid limit price format. Please use numbers only.")
+                        await context.bot.send_message(chat_id=chat_id, text="❌ Invalid limit price format. Please use numbers only.")
                         return
                         return
             
             
             # Get current market price
             # Get current market price
             market_data = self.trading_engine.get_market_data(f"{token}/USDC:USDC")
             market_data = self.trading_engine.get_market_data(f"{token}/USDC:USDC")
             if not market_data:
             if not market_data:
-                await update.message.reply_text(f"❌ Could not fetch market data for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"❌ Could not fetch market data for {token}")
                 return
                 return
             
             
             current_price = float(market_data['ticker'].get('last', 0))
             current_price = float(market_data['ticker'].get('last', 0))
             if current_price <= 0:
             if current_price <= 0:
-                await update.message.reply_text(f"❌ Invalid current price for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"❌ Invalid current price for {token}")
                 return
                 return
             
             
             # Determine order type and price
             # Determine order type and price
@@ -89,13 +90,13 @@ class TradingCommands:
             
             
             # Validate stop loss for long positions
             # Validate stop loss for long positions
             if stop_loss_price and stop_loss_price >= price:
             if stop_loss_price and stop_loss_price >= price:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     f"⚠️ Stop loss price should be BELOW entry price for long positions\n\n"
                     f"⚠️ Stop loss price should be BELOW entry price for long positions\n\n"
                     f"📊 Your order:\n"
                     f"📊 Your order:\n"
                     f"• Entry Price: ${price:,.2f}\n"
                     f"• Entry Price: ${price:,.2f}\n"
                     f"• Stop Loss: ${stop_loss_price:,.2f} ❌\n\n"
                     f"• Stop Loss: ${stop_loss_price:,.2f} ❌\n\n"
                     f"💡 Try a lower stop loss like: sl:{price * 0.95:.0f}"
                     f"💡 Try a lower stop loss like: sl:{price * 0.95:.0f}"
-                )
+                ))
                 return
                 return
             
             
             # Create confirmation message
             # Create confirmation message
@@ -131,30 +132,31 @@ This will {"place a limit buy order" if limit_price else "execute a market buy o
             ]
             ]
             reply_markup = InlineKeyboardMarkup(keyboard)
             reply_markup = InlineKeyboardMarkup(keyboard)
             
             
-            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            await context.bot.send_message(chat_id=chat_id, text=confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
             
             
         except ValueError as e:
         except ValueError as e:
-            await update.message.reply_text(f"❌ Invalid input format: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Invalid input format: {e}")
         except Exception as e:
         except Exception as e:
-            await update.message.reply_text(f"❌ Error processing long command: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Error processing long command: {e}")
             logger.error(f"Error in long command: {e}")
             logger.error(f"Error in long command: {e}")
     
     
     async def short_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def short_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /short command for opening short positions."""
         """Handle the /short command for opening short positions."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             if not context.args or len(context.args) < 2:
             if not context.args or len(context.args) < 2:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     "❌ Usage: /short [token] [USDC amount] [price (optional)] [sl:price (optional)]\n"
                     "❌ Usage: /short [token] [USDC amount] [price (optional)] [sl:price (optional)]\n"
                     "Examples:\n"
                     "Examples:\n"
                     "• /short BTC 100 - Market order\n"
                     "• /short BTC 100 - Market order\n"
                     "• /short BTC 100 45000 - Limit order at $45,000\n"
                     "• /short BTC 100 45000 - Limit order at $45,000\n"
                     "• /short BTC 100 sl:46000 - Market order with stop loss at $46,000\n"
                     "• /short BTC 100 sl:46000 - Market order with stop loss at $46,000\n"
                     "• /short BTC 100 45000 sl:46000 - Limit order at $45,000 with stop loss at $46,000"
                     "• /short BTC 100 45000 sl:46000 - Limit order at $45,000 with stop loss at $46,000"
-                )
+                ))
                 return
                 return
             
             
             token = context.args[0].upper()
             token = context.args[0].upper()
@@ -169,24 +171,24 @@ This will {"place a limit buy order" if limit_price else "execute a market buy o
                     try:
                     try:
                         stop_loss_price = float(arg[3:])
                         stop_loss_price = float(arg[3:])
                     except ValueError:
                     except ValueError:
-                        await update.message.reply_text("❌ Invalid stop loss price format. Use sl:price (e.g., sl:46000)")
+                        await context.bot.send_message(chat_id=chat_id, text="❌ Invalid stop loss price format. Use sl:price (e.g., sl:46000)")
                         return
                         return
                 elif limit_price is None:
                 elif limit_price is None:
                     try:
                     try:
                         limit_price = float(arg)
                         limit_price = float(arg)
                     except ValueError:
                     except ValueError:
-                        await update.message.reply_text("❌ Invalid limit price format. Please use numbers only.")
+                        await context.bot.send_message(chat_id=chat_id, text="❌ Invalid limit price format. Please use numbers only.")
                         return
                         return
             
             
             # Get current market price
             # Get current market price
             market_data = self.trading_engine.get_market_data(f"{token}/USDC:USDC")
             market_data = self.trading_engine.get_market_data(f"{token}/USDC:USDC")
             if not market_data:
             if not market_data:
-                await update.message.reply_text(f"❌ Could not fetch market data for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"❌ Could not fetch market data for {token}")
                 return
                 return
             
             
             current_price = float(market_data['ticker'].get('last', 0))
             current_price = float(market_data['ticker'].get('last', 0))
             if current_price <= 0:
             if current_price <= 0:
-                await update.message.reply_text(f"❌ Invalid current price for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"❌ Invalid current price for {token}")
                 return
                 return
             
             
             # Determine order type and price
             # Determine order type and price
@@ -201,13 +203,13 @@ This will {"place a limit buy order" if limit_price else "execute a market buy o
             
             
             # Validate stop loss for short positions
             # Validate stop loss for short positions
             if stop_loss_price and stop_loss_price <= price:
             if stop_loss_price and stop_loss_price <= price:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     f"⚠️ Stop loss price should be ABOVE entry price for short positions\n\n"
                     f"⚠️ Stop loss price should be ABOVE entry price for short positions\n\n"
                     f"📊 Your order:\n"
                     f"📊 Your order:\n"
                     f"• Entry Price: ${price:,.2f}\n"
                     f"• Entry Price: ${price:,.2f}\n"
                     f"• Stop Loss: ${stop_loss_price:,.2f} ❌\n\n"
                     f"• Stop Loss: ${stop_loss_price:,.2f} ❌\n\n"
                     f"💡 Try a higher stop loss like: sl:{price * 1.05:.0f}"
                     f"💡 Try a higher stop loss like: sl:{price * 1.05:.0f}"
-                )
+                ))
                 return
                 return
             
             
             # Create confirmation message
             # Create confirmation message
@@ -243,27 +245,28 @@ This will {"place a limit sell order" if limit_price else "execute a market sell
             ]
             ]
             reply_markup = InlineKeyboardMarkup(keyboard)
             reply_markup = InlineKeyboardMarkup(keyboard)
             
             
-            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            await context.bot.send_message(chat_id=chat_id, text=confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
             
             
         except ValueError as e:
         except ValueError as e:
-            await update.message.reply_text(f"❌ Invalid input format: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Invalid input format: {e}")
         except Exception as e:
         except Exception as e:
-            await update.message.reply_text(f"❌ Error processing short command: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Error processing short command: {e}")
             logger.error(f"Error in short command: {e}")
             logger.error(f"Error in short command: {e}")
     
     
     async def exit_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def exit_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /exit command for closing positions."""
         """Handle the /exit command for closing positions."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             if not context.args or len(context.args) < 1:
             if not context.args or len(context.args) < 1:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     "❌ Usage: /exit [token]\n"
                     "❌ Usage: /exit [token]\n"
                     "Example: /exit BTC\n\n"
                     "Example: /exit BTC\n\n"
                     "This closes your entire position for the specified token."
                     "This closes your entire position for the specified token."
-                )
+                ))
                 return
                 return
             
             
             token = context.args[0].upper()
             token = context.args[0].upper()
@@ -271,7 +274,7 @@ This will {"place a limit sell order" if limit_price else "execute a market sell
             # Find the position
             # Find the position
             position = self.trading_engine.find_position(token)
             position = self.trading_engine.find_position(token)
             if not position:
             if not position:
-                await update.message.reply_text(f"📭 No open position found for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"📭 No open position found for {token}")
                 return
                 return
             
             
             # Get position details
             # Get position details
@@ -282,7 +285,7 @@ This will {"place a limit sell order" if limit_price else "execute a market sell
             # Get current market price
             # Get current market price
             market_data = self.trading_engine.get_market_data(f"{token}/USDC:USDC")
             market_data = self.trading_engine.get_market_data(f"{token}/USDC:USDC")
             if not market_data:
             if not market_data:
-                await update.message.reply_text(f"❌ Could not fetch current price for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"❌ Could not fetch current price for {token}")
                 return
                 return
             
             
             current_price = float(market_data['ticker'].get('last', 0))
             current_price = float(market_data['ticker'].get('last', 0))
@@ -320,25 +323,26 @@ This will {"place a limit sell order" if limit_price else "execute a market sell
             ]
             ]
             reply_markup = InlineKeyboardMarkup(keyboard)
             reply_markup = InlineKeyboardMarkup(keyboard)
             
             
-            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            await context.bot.send_message(chat_id=chat_id, text=confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
             
             
         except Exception as e:
         except Exception as e:
-            await update.message.reply_text(f"❌ Error processing exit command: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Error processing exit command: {e}")
             logger.error(f"Error in exit command: {e}")
             logger.error(f"Error in exit command: {e}")
     
     
     async def sl_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def sl_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /sl (stop loss) command."""
         """Handle the /sl (stop loss) command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             if not context.args or len(context.args) < 2:
             if not context.args or len(context.args) < 2:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     "❌ Usage: /sl [token] [price]\n"
                     "❌ Usage: /sl [token] [price]\n"
                     "Example: /sl BTC 44000\n\n"
                     "Example: /sl BTC 44000\n\n"
                     "This sets a stop loss order for your existing position."
                     "This sets a stop loss order for your existing position."
-                )
+                ))
                 return
                 return
             
             
             token = context.args[0].upper()
             token = context.args[0].upper()
@@ -347,7 +351,7 @@ This will {"place a limit sell order" if limit_price else "execute a market sell
             # Find the position
             # Find the position
             position = self.trading_engine.find_position(token)
             position = self.trading_engine.find_position(token)
             if not position:
             if not position:
-                await update.message.reply_text(f"📭 No open position found for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"📭 No open position found for {token}")
                 return
                 return
             
             
             # Get position details
             # Get position details
@@ -356,22 +360,22 @@ This will {"place a limit sell order" if limit_price else "execute a market sell
             
             
             # Validate stop loss price based on position direction
             # Validate stop loss price based on position direction
             if position_type == "LONG" and stop_price >= entry_price:
             if position_type == "LONG" and stop_price >= entry_price:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     f"⚠️ Stop loss price should be BELOW entry price for long positions\n\n"
                     f"⚠️ Stop loss price should be BELOW entry price for long positions\n\n"
                     f"📊 Your {token} LONG position:\n"
                     f"📊 Your {token} LONG position:\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Stop Price: ${stop_price:,.2f} ❌\n\n"
                     f"• Stop Price: ${stop_price:,.2f} ❌\n\n"
                     f"💡 Try a lower price like: /sl {token} {entry_price * 0.95:.0f}"
                     f"💡 Try a lower price like: /sl {token} {entry_price * 0.95:.0f}"
-                )
+                ))
                 return
                 return
             elif position_type == "SHORT" and stop_price <= entry_price:
             elif position_type == "SHORT" and stop_price <= entry_price:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     f"⚠️ Stop loss price should be ABOVE entry price for short positions\n\n"
                     f"⚠️ Stop loss price should be ABOVE entry price for short positions\n\n"
                     f"📊 Your {token} SHORT position:\n"
                     f"📊 Your {token} SHORT position:\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Stop Price: ${stop_price:,.2f} ❌\n\n"
                     f"• Stop Price: ${stop_price:,.2f} ❌\n\n"
                     f"💡 Try a higher price like: /sl {token} {entry_price * 1.05:.0f}"
                     f"💡 Try a higher price like: /sl {token} {entry_price * 1.05:.0f}"
-                )
+                ))
                 return
                 return
             
             
             # Get current market price
             # Get current market price
@@ -418,27 +422,28 @@ This will place a limit {exit_side} order at ${stop_price:,.2f} to protect your
             ]
             ]
             reply_markup = InlineKeyboardMarkup(keyboard)
             reply_markup = InlineKeyboardMarkup(keyboard)
             
             
-            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            await context.bot.send_message(chat_id=chat_id, text=confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
             
             
         except ValueError:
         except ValueError:
-            await update.message.reply_text("❌ Invalid price format. Please use numbers only.")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Invalid price format. Please use numbers only.")
         except Exception as e:
         except Exception as e:
-            await update.message.reply_text(f"❌ Error processing stop loss command: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Error processing stop loss command: {e}")
             logger.error(f"Error in sl command: {e}")
             logger.error(f"Error in sl command: {e}")
     
     
     async def tp_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def tp_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /tp (take profit) command."""
         """Handle the /tp (take profit) command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             if not context.args or len(context.args) < 2:
             if not context.args or len(context.args) < 2:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     "❌ Usage: /tp [token] [price]\n"
                     "❌ Usage: /tp [token] [price]\n"
                     "Example: /tp BTC 50000\n\n"
                     "Example: /tp BTC 50000\n\n"
                     "This sets a take profit order for your existing position."
                     "This sets a take profit order for your existing position."
-                )
+                ))
                 return
                 return
             
             
             token = context.args[0].upper()
             token = context.args[0].upper()
@@ -447,7 +452,7 @@ This will place a limit {exit_side} order at ${stop_price:,.2f} to protect your
             # Find the position
             # Find the position
             position = self.trading_engine.find_position(token)
             position = self.trading_engine.find_position(token)
             if not position:
             if not position:
-                await update.message.reply_text(f"📭 No open position found for {token}")
+                await context.bot.send_message(chat_id=chat_id, text=f"📭 No open position found for {token}")
                 return
                 return
             
             
             # Get position details
             # Get position details
@@ -456,22 +461,22 @@ This will place a limit {exit_side} order at ${stop_price:,.2f} to protect your
             
             
             # Validate take profit price based on position direction
             # Validate take profit price based on position direction
             if position_type == "LONG" and tp_price <= entry_price:
             if position_type == "LONG" and tp_price <= entry_price:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     f"⚠️ Take profit price should be ABOVE entry price for long positions\n\n"
                     f"⚠️ Take profit price should be ABOVE entry price for long positions\n\n"
                     f"📊 Your {token} LONG position:\n"
                     f"📊 Your {token} LONG position:\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Take Profit: ${tp_price:,.2f} ❌\n\n"
                     f"• Take Profit: ${tp_price:,.2f} ❌\n\n"
                     f"💡 Try a higher price like: /tp {token} {entry_price * 1.05:.0f}"
                     f"💡 Try a higher price like: /tp {token} {entry_price * 1.05:.0f}"
-                )
+                ))
                 return
                 return
             elif position_type == "SHORT" and tp_price >= entry_price:
             elif position_type == "SHORT" and tp_price >= entry_price:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     f"⚠️ Take profit price should be BELOW entry price for short positions\n\n"
                     f"⚠️ Take profit price should be BELOW entry price for short positions\n\n"
-                    f"📊 Your {token} SHORT position:\n"
+                    f"�� Your {token} SHORT position:\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Entry Price: ${entry_price:,.2f}\n"
                     f"• Take Profit: ${tp_price:,.2f} ❌\n\n"
                     f"• Take Profit: ${tp_price:,.2f} ❌\n\n"
                     f"💡 Try a lower price like: /tp {token} {entry_price * 0.95:.0f}"
                     f"💡 Try a lower price like: /tp {token} {entry_price * 0.95:.0f}"
-                )
+                ))
                 return
                 return
             
             
             # Get current market price
             # Get current market price
@@ -518,27 +523,28 @@ This will place a limit {exit_side} order at ${tp_price:,.2f} to secure profits
             ]
             ]
             reply_markup = InlineKeyboardMarkup(keyboard)
             reply_markup = InlineKeyboardMarkup(keyboard)
             
             
-            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            await context.bot.send_message(chat_id=chat_id, text=confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
             
             
         except ValueError:
         except ValueError:
-            await update.message.reply_text("❌ Invalid price format. Please use numbers only.")
+            await context.bot.send_message(chat_id=chat_id, text="❌ Invalid price format. Please use numbers only.")
         except Exception as e:
         except Exception as e:
-            await update.message.reply_text(f"❌ Error processing take profit command: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Error processing take profit command: {e}")
             logger.error(f"Error in tp command: {e}")
             logger.error(f"Error in tp command: {e}")
     
     
     async def coo_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def coo_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
         """Handle the /coo (cancel all orders) command."""
         """Handle the /coo (cancel all orders) command."""
-        if not self._is_authorized(update.effective_chat.id):
-            await update.message.reply_text("❌ Unauthorized access.")
+        chat_id = update.effective_chat.id
+        if not self._is_authorized(chat_id):
+            await context.bot.send_message(chat_id=chat_id, text="❌ Unauthorized access.")
             return
             return
         
         
         try:
         try:
             if not context.args or len(context.args) < 1:
             if not context.args or len(context.args) < 1:
-                await update.message.reply_text(
+                await context.bot.send_message(chat_id=chat_id, text=(
                     "❌ Usage: /coo [token]\n"
                     "❌ Usage: /coo [token]\n"
                     "Example: /coo BTC\n\n"
                     "Example: /coo BTC\n\n"
                     "This cancels all open orders for the specified token."
                     "This cancels all open orders for the specified token."
-                )
+                ))
                 return
                 return
             
             
             token = context.args[0].upper()
             token = context.args[0].upper()
@@ -566,10 +572,10 @@ This action cannot be undone.
             ]
             ]
             reply_markup = InlineKeyboardMarkup(keyboard)
             reply_markup = InlineKeyboardMarkup(keyboard)
             
             
-            await update.message.reply_text(confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
+            await context.bot.send_message(chat_id=chat_id, text=confirmation_text, parse_mode='HTML', reply_markup=reply_markup)
             
             
         except Exception as e:
         except Exception as e:
-            await update.message.reply_text(f"❌ Error processing cancel orders command: {e}")
+            await context.bot.send_message(chat_id=chat_id, text=f"❌ Error processing cancel orders command: {e}")
             logger.error(f"Error in coo command: {e}")
             logger.error(f"Error in coo command: {e}")
     
     
     async def button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
     async def button_callback(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: