import logging import html from telegram import Update from telegram.ext import ContextTypes from .base import InfoCommandsBase from src.config.config import Config from src.utils.token_display_formatter import get_formatter logger = logging.getLogger(__name__) class RiskCommands(InfoCommandsBase): """Handles all risk management-related commands.""" def __init__(self, trading_engine, notification_manager): super().__init__(trading_engine, notification_manager) self.formatter = get_formatter() async def risk_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Handle the /risk command to show risk management information.""" try: # Get token from command arguments or use default token = context.args[0].upper() if context.args else Config.DEFAULT_TRADING_TOKEN # Get current positions and orders positions = self.trading_engine.get_positions() orders = self.trading_engine.get_orders() # Get trading statistics stats = self.trading_engine.get_stats() # Calculate unrealized P&L for open positions total_unrealized_pnl = 0.0 position_risks = [] for position in positions: try: # Get position details symbol = position.get('symbol', '') size = float(position.get('size', 0) or 0) entry_price = float(position.get('entryPrice', 0) or 0) mark_price = float(position.get('markPrice', 0) or 0) liquidation_price = float(position.get('liquidationPrice', 0) or 0) if size == 0 or entry_price == 0: continue # Calculate position value and P&L position_value = abs(size * entry_price) unrealized_pnl = size * (mark_price - entry_price) total_unrealized_pnl += unrealized_pnl # Calculate risk metrics price_risk = abs((mark_price - entry_price) / entry_price * 100) liquidation_risk = abs((liquidation_price - mark_price) / mark_price * 100) if liquidation_price > 0 else 0 # Find stop loss orders for this position stop_loss_orders = [o for o in orders if o.get('symbol') == symbol and o.get('type') == 'stop'] stop_loss_risk = 0 if stop_loss_orders: stop_price = float(stop_loss_orders[0].get('price', 0) or 0) if stop_price > 0: stop_loss_risk = abs((stop_price - mark_price) / mark_price * 100) position_risks.append({ 'symbol': symbol, 'size': size, 'entry_price': entry_price, 'mark_price': mark_price, 'position_value': position_value, 'unrealized_pnl': unrealized_pnl, 'price_risk': price_risk, 'liquidation_risk': liquidation_risk, 'stop_loss_risk': stop_loss_risk }) except (ValueError, TypeError) as e: logger.error(f"Error processing position: {e}") continue # Get portfolio value balance_data = self.trading_engine.get_balance() portfolio_value = float(balance_data.get('total', {}).get('USDC', 0) or 0) if balance_data else 0.0 # Calculate portfolio risk metrics portfolio_risk = (total_unrealized_pnl / portfolio_value * 100) if portfolio_value > 0 else 0 # Format the message message = f"šŸ“Š Risk Analysis for {token}\n\n" # Add position risks if position_risks: message += "šŸ” Position Risks:\n" for risk in position_risks: pnl_emoji = "🟢" if risk['unrealized_pnl'] >= 0 else "šŸ”“" message += ( f"\n{risk['symbol']}\n" f"Size: {await self.formatter.format_amount(risk['size'], risk['symbol'].split('/')[0])}\n" f"Entry: {await self.formatter.format_price_with_symbol(risk['entry_price'], risk['symbol'].split('/')[0])}\n" f"Mark: {await self.formatter.format_price_with_symbol(risk['mark_price'], risk['symbol'].split('/')[0])}\n" f"P&L: {pnl_emoji} {await self.formatter.format_price_with_symbol(risk['unrealized_pnl'], risk['symbol'].split('/')[0])}\n" f"Price Risk: {risk['price_risk']:.2f}%\n" f"Liquidation Risk: {risk['liquidation_risk']:.2f}%\n" f"Stop Loss Risk: {risk['stop_loss_risk']:.2f}%\n" ) else: message += "No open positions\n" # Add portfolio summary message += f"\nšŸ“ˆ Portfolio Summary:\n" message += f"Total Value: {await self.formatter.format_price_with_symbol(portfolio_value)}\n" message += f"Unrealized P&L: {await self.formatter.format_price_with_symbol(total_unrealized_pnl)}\n" message += f"Portfolio Risk: {portfolio_risk:.2f}%\n" # Add trading statistics if stats: performance_stats = stats.get_performance_stats() message += f"\nšŸ“Š Trading Statistics:\n" message += f"Win Rate: {performance_stats.get('win_rate', 0):.2f}%\n" message += f"Profit Factor: {performance_stats.get('profit_factor', 0):.2f}\n" message += f"Average Win: {await self.formatter.format_price_with_symbol(performance_stats.get('average_win', 0))}\n" message += f"Average Loss: {await self.formatter.format_price_with_symbol(performance_stats.get('average_loss', 0))}\n" await self._reply(update, message) except Exception as e: logger.error(f"Error in risk command: {e}", exc_info=True) await self._reply(update, "āŒ Error getting risk information. Please try again later.")