123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- import logging
- from telegram import Update
- from telegram.ext import ContextTypes
- from .base import InfoCommandsBase
- from src.utils.token_display_formatter import get_formatter
- logger = logging.getLogger(__name__)
- class RiskCommands(InfoCommandsBase):
- """Handles all risk management-related commands."""
- async def risk_command(self, update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
- """Handle the /risk command to show risk management information."""
- if not self._is_authorized(update):
- return
- try:
- stats = self.trading_engine.get_stats()
- if not stats:
- await self._reply(update, "❌ Could not load trading statistics")
- return
- # Get current positions
- positions = stats.get_open_positions()
- if not positions:
- await self._reply(update, "📭 No open positions to analyze risk")
- return
- # Get current orders for stop loss analysis
- orders = self.trading_engine.get_orders() or []
-
- # Get formatter for consistent display
- formatter = get_formatter()
- # Build risk analysis message
- risk_text_parts = ["🎯 <b>Risk Management Overview</b>"]
- # Analyze each position
- for position in positions:
- symbol = position['symbol']
- token = symbol.split('/')[0] if '/' in symbol else symbol.split(':')[0]
- side = position['position_side']
- size = position['current_position_size']
- entry_price = position['entry_price']
- current_price = position.get('current_price', entry_price)
-
- # Calculate unrealized P&L
- if side == 'long':
- unrealized_pnl = size * (current_price - entry_price)
- else: # short
- unrealized_pnl = size * (entry_price - current_price)
-
- # Find stop loss orders for this position
- stop_loss_orders = [
- order for order in orders
- if order.get('symbol') == symbol and
- order.get('type') == 'stop_loss'
- ]
-
- # Get the most relevant stop loss price
- stop_loss_price = None
- if stop_loss_orders:
- # Sort by trigger price to find the most conservative stop loss
- stop_loss_orders.sort(key=lambda x: float(x.get('triggerPrice', 0)))
- if side == 'long':
- stop_loss_price = float(stop_loss_orders[0].get('triggerPrice', 0))
- else: # short
- stop_loss_price = float(stop_loss_orders[-1].get('triggerPrice', 0))
-
- # Calculate risk metrics
- risk_text_parts.append(f"\n📊 <b>{token}</b>")
- risk_text_parts.append(f"• Position: {side.upper()} {formatter.format_amount(size, token)} @ {formatter.format_price_with_symbol(entry_price, token)}")
- risk_text_parts.append(f"• Current: {formatter.format_price_with_symbol(current_price, token)}")
-
- # Show P&L
- pnl_emoji = "🟢" if unrealized_pnl >= 0 else "🔴"
- risk_text_parts.append(f"• P&L: {pnl_emoji} {formatter.format_price_with_symbol(unrealized_pnl)}")
-
- # Show stop loss info
- if stop_loss_price:
- risk_amount = abs(size * (stop_loss_price - entry_price))
- risk_text_parts.append(f"• Stop Loss: {formatter.format_price_with_symbol(stop_loss_price, token)}")
- risk_text_parts.append(f"• Risk Amount: {formatter.format_price_with_symbol(risk_amount)}")
- else:
- risk_text_parts.append("• Stop Loss: ❌ Not set")
-
- # Add separator between positions
- risk_text_parts.append("")
- # Add portfolio-level risk metrics
- total_position_value = sum(
- abs(float(pos.get('current_position_size', 0)) * float(pos.get('current_price', 0)))
- for pos in positions
- )
-
- # Get account balance
- balance = self.trading_engine.get_balance()
- if balance:
- total_balance = float(balance.get('total', 0))
- if total_balance > 0:
- portfolio_risk = (total_position_value / total_balance) * 100
- risk_text_parts.append(f"📈 <b>Portfolio Risk</b>")
- risk_text_parts.append(f"• Total Position Value: {formatter.format_price_with_symbol(total_position_value)}")
- risk_text_parts.append(f"• Portfolio Risk: {portfolio_risk:.1f}% of balance")
- await self._reply(update, "\n".join(risk_text_parts).strip())
- except Exception as e:
- error_message = f"❌ Error processing risk command: {str(e)}"
- await self._reply(update, error_message)
- logger.error(f"Error in risk command: {e}")
|