import logging from typing import Dict, Any, Optional from telegram import Update from telegram.ext import ContextTypes from .base import InfoCommandsBase from datetime import datetime logger = logging.getLogger(__name__) class BalanceCommands(InfoCommandsBase): """Handles all balance-related commands.""" async def balance_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Handle the /balance command.""" try: if not self._is_authorized(update): await self._reply(update, "āŒ Unauthorized access.") return balance = self.trading_engine.get_balance() if not balance: await self._reply(update, "āŒ Could not fetch balance information") return # Get USDC balances usdc_total = 0.0 usdc_free = 0.0 usdc_used = 0.0 if 'USDC' in balance.get('total', {}): usdc_total = float(balance['total']['USDC']) usdc_free = float(balance.get('free', {}).get('USDC', 0)) usdc_used = float(balance.get('used', {}).get('USDC', 0)) balance_text_parts = [ f"šŸ’° Account Balance\n", f" šŸ’µ Total USDC: ${usdc_total:,.2f}", f" āœ… Available USDC: ${usdc_free:,.2f}", f" šŸ”’ USDC In Use: ${usdc_used:,.2f}" ] # Add other assets other_assets_text = [] for asset, amount_val in balance.get('total', {}).items(): if asset != 'USDC' and float(amount_val) > 0: free_amount = float(balance.get('free', {}).get(asset, 0)) other_assets_text.append(f" šŸŖ™ {asset}: {float(amount_val):.6f} (Free: {free_amount:.6f})") if other_assets_text: balance_text_parts.append("\nšŸ“Š Other Assets:") balance_text_parts.extend(other_assets_text) # Performance Metrics stats = self.trading_engine.get_stats() initial_balance = 0.0 pnl = 0.0 pnl_percent = 0.0 pnl_emoji = "⚪" if stats: basic_stats = stats.get_basic_stats() initial_balance = basic_stats.get('initial_balance', usdc_total) # Fallback to current total if no initial if initial_balance is None: # Should not happen if basic_stats is fetched initial_balance = usdc_total pnl = usdc_total - initial_balance pnl_percent = (pnl / initial_balance * 100) if initial_balance > 0 else 0 pnl_emoji = "🟢" if pnl >= 0 else "šŸ”“" balance_text_parts.append("\nšŸ“ˆ Performance:") balance_text_parts.append(f" šŸ’µ Initial Balance: ${initial_balance:,.2f}") balance_text_parts.append(f" {pnl_emoji} Overall P&L: ${pnl:,.2f} ({pnl_percent:+.2f}%)") # System Status trading_engine_active = "āœ… Active" if self.trading_engine else "āŒ Inactive (Error)" balance_text_parts.append("\nāš™ļø System Status:") balance_text_parts.append(f"• Trading Engine: {trading_engine_active}") balance_text_parts.append(f"• Data Source: Exchange (Live)") # Balance is usually live balance_text_parts.append(f"• Last Update: {datetime.now().strftime('%H:%M:%S')}") final_message = "\n".join(balance_text_parts) await self._reply(update, final_message.strip()) except Exception as e: logger.error(f"Error in balance command: {e}", exc_info=True) await self._reply(update, "āŒ Error retrieving balance information.")