Browse Source

Enhance balance command functionality in TelegramTradingBot.

- Improved balance retrieval in `balance.py` to include detailed USDC and other asset balances, enhancing user feedback.
- Added performance metrics display, including initial balance and overall P&L, for better trading insights.
- Updated system status reporting to reflect trading engine activity and last update time, improving transparency in command responses.
- Refactored error handling to provide more informative logging for balance retrieval issues.
Carles Sentis 1 week ago
parent
commit
fc0afb4fbf
3 changed files with 60 additions and 47 deletions
  1. 57 44
      src/commands/info/balance.py
  2. 2 2
      src/commands/info/daily.py
  3. 1 1
      trading_bot.py

+ 57 - 44
src/commands/info/balance.py

@@ -3,6 +3,7 @@ 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__)
 
@@ -16,58 +17,70 @@ class BalanceCommands(InfoCommandsBase):
                 await self._reply(update, "❌ Unauthorized access.")
                 return
 
-            stats = self.trading_engine.get_stats()
-            if not stats:
-                await self._reply(update, "❌ Trading stats not available.")
-                return
-
-            # Get balance info
-            balance_info = stats.get_basic_stats()
-            if not balance_info:
-                await self._reply(update, "❌ Balance information not available.")
+            balance = self.trading_engine.get_balance()
+            if not balance:
+                await self._reply(update, "❌ Could not fetch balance information")
                 return
 
-            # Format balance text
-            balance_text = "💰 <b>Account Balance</b>\n\n"
+            # Get USDC balances
+            usdc_total = 0.0
+            usdc_free = 0.0
+            usdc_used = 0.0
 
-            # Add total balance
-            total_balance = balance_info.get('total_balance', 0.0)
-            balance_text += f"💵 Total Balance: ${total_balance:,.2f}\n"
+            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))
 
-            # Add available balance
-            available_balance = balance_info.get('available_balance', 0.0)
-            balance_text += f"💳 Available Balance: ${available_balance:,.2f}\n"
+            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 margin used
-            margin_used = balance_info.get('margin_used', 0.0)
-            if margin_used > 0:
-                balance_text += f"📊 Margin Used: ${margin_used:,.2f}\n"
-                margin_ratio = (margin_used / total_balance) * 100 if total_balance > 0 else 0
-                balance_text += f"⚖️ Margin Ratio: {margin_ratio:.2f}%\n"
+            # 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)
 
-            # Add unrealized P&L
-            unrealized_pnl = balance_info.get('unrealized_pnl', 0.0)
-            pnl_emoji = "🟢" if unrealized_pnl >= 0 else "🔴"
-            balance_text += f"{pnl_emoji} Unrealized P&L: ${unrealized_pnl:,.2f}\n"
-
-            # Add realized P&L if available
-            realized_pnl = balance_info.get('realized_pnl', 0.0)
-            if realized_pnl != 0:
-                realized_emoji = "🟢" if realized_pnl >= 0 else "🔴"
-                balance_text += f"{realized_emoji} Realized P&L: ${realized_pnl:,.2f}\n"
-
-            # Add total P&L
-            total_pnl = unrealized_pnl + realized_pnl
-            total_pnl_emoji = "🟢" if total_pnl >= 0 else "🔴"
-            balance_text += f"{total_pnl_emoji} Total P&L: ${total_pnl:,.2f}\n"
+            # Performance Metrics
+            stats = self.trading_engine.get_stats()
+            initial_balance = 0.0
+            pnl = 0.0
+            pnl_percent = 0.0
+            pnl_emoji = "⚪"
 
-            # Add P&L percentage if margin is used
-            if margin_used > 0:
-                pnl_percentage = (total_pnl / margin_used) * 100
-                balance_text += f"📈 Return on Margin: {pnl_percentage:+.2f}%\n"
+            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}%)")
 
-            await self._reply(update, balance_text.strip())
+            # 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}")
+            logger.error(f"Error in balance command: {e}", exc_info=True)
             await self._reply(update, "❌ Error retrieving balance information.")

+ 2 - 2
src/commands/info/daily.py

@@ -41,14 +41,14 @@ class DailyCommands(InfoCommandsBase):
                     pnl_str = formatter.format_price_with_symbol(day_stats_item.get('pnl', 0))
                     roe = day_stats_item.get('roe', 0.0)  # Get ROE from stats
                     roe_str = f"ROE: {roe:+.1f}%" if roe != 0 else ""
-                    day_str = day_stats_item.get('day', 'Unknown')
+                    day_str = day_stats_item.get('date_formatted', 'Unknown')
                     period_lines.append(f"📅 <b>{day_str}</b>: {pnl_emoji} {pnl_str} ({day_stats_item.get('pnl_pct', 0):+.1f}%) {roe_str} | Trades: {day_stats_item.get('trades', 0)}")
                     total_pnl_all_days += day_stats_item.get('pnl', 0)
                     total_trades_all_days += day_stats_item.get('trades', 0)
                     total_roe_all_days += roe
                     trading_days_count += 1
                 else:
-                    day_str = day_stats_item.get('day', 'Unknown')
+                    day_str = day_stats_item.get('date_formatted', 'Unknown')
                     period_lines.append(f"📅 <b>{day_str}</b>: 📭 No trading activity")
 
             if period_lines:

+ 1 - 1
trading_bot.py

@@ -14,7 +14,7 @@ from datetime import datetime
 from pathlib import Path
 
 # Bot version
-BOT_VERSION = "2.4.185"
+BOT_VERSION = "2.4.186"
 
 # Add src directory to Python path
 sys.path.insert(0, str(Path(__file__).parent / "src"))