123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- 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"📊 <b>Risk Analysis for {token}</b>\n\n"
-
- # Add position risks
- if position_risks:
- message += "🔍 <b>Position Risks:</b>\n"
- for risk in position_risks:
- pnl_emoji = "🟢" if risk['unrealized_pnl'] >= 0 else "🔴"
- message += (
- f"\n<b>{risk['symbol']}</b>\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📈 <b>Portfolio Summary:</b>\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📊 <b>Trading Statistics:</b>\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.")
|