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.")