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