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.")