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"š° <b>Account Balance</b>\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š <b>Other Assets:</b>") 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š <b>Performance:</b>") 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āļø <b>System Status:</b>") 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.")