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 = "📜 Recent Trades\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} {base_asset} {side}\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.")