import logging from typing import Dict, Any, List, Optional from datetime import datetime, timedelta from telegram import Update from telegram.ext import ContextTypes from .base import InfoCommandsBase logger = logging.getLogger(__name__) class TradesCommands(InfoCommandsBase): """Handles all trade history-related commands.""" async def trades_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Handle the /trades command.""" try: if not self._is_authorized(update): 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 recent trades recent_trades = stats.get_recent_trades() if not recent_trades: await self._reply(update, "📭 No recent trades") return # Format trades text trades_text = "📜 <b>Recent Trades</b>\n\n" for trade in recent_trades: try: # Defensive check to ensure 'trade' is a dictionary if not isinstance(trade, dict): logger.warning(f"Skipping non-dict item in recent_trades: {trade}") continue symbol = trade.get('symbol', 'unknown') base_asset = symbol.split('/')[0] if '/' in symbol else symbol.split(':')[0] side = trade.get('side', 'unknown').upper() price = float(trade.get('price', 0)) amount = float(trade.get('amount', 0)) pnl = float(trade.get('pnl', 0)) pnl_percentage = float(trade.get('pnl_percentage', 0)) trade_type = trade.get('trade_type', 'unknown') trade_time = trade.get('trade_time') # Format trade details formatter = self._get_formatter() price_str = await formatter.format_price_with_symbol(price, base_asset) amount_str = await formatter.format_amount(amount, base_asset) # Trade header side_emoji = "🟢" if side == "BUY" else "🔴" trades_text += f"{side_emoji} <b>{base_asset} {side}</b>\n" trades_text += f" 📏 Amount: {amount_str} {base_asset}\n" trades_text += f" 💰 Price: {price_str}\n" # Add P&L info pnl_emoji = "🟢" if pnl >= 0 else "🔴" trades_text += f" {pnl_emoji} P&L: ${pnl:,.2f} ({pnl_percentage:+.2f}%)\n" # Add trade type type_indicator = "" if trade.get('trade_lifecycle_id'): type_indicator = " 🤖" elif trade_type == 'external': type_indicator = " 🔄" trades_text += f" 📝 Type: {trade_type.upper()}{type_indicator}\n" # Add trade time if trade_time: try: trade_datetime = datetime.fromisoformat(trade_time.replace('Z', '+00:00')) time_diff = datetime.now(trade_datetime.tzinfo) - trade_datetime if time_diff.days > 0: time_str = f"{time_diff.days}d ago" elif time_diff.seconds >= 3600: time_str = f"{time_diff.seconds // 3600}h ago" else: time_str = f"{time_diff.seconds // 60}m ago" trades_text += f" ⏰ Time: {time_str}\n" except ValueError: logger.warning(f"Could not parse trade_time: {trade_time}") # Add trade ID trade_id = trade.get('id', 'unknown') trades_text += f" 🆔 Trade ID: {trade_id[:8]}\n\n" except Exception as e: logger.error(f"Error processing trade {trade.get('symbol', 'unknown')}: {e}") continue await self._reply(update, trades_text.strip()) except Exception as e: logger.error(f"Error in trades command: {e}") await self._reply(update, "❌ Error retrieving trade history.")