|
@@ -88,79 +88,22 @@ class StatsCommands(InfoCommandsBase):
|
|
await self._reply(update, "❌ Trading stats not available.")
|
|
await self._reply(update, "❌ Trading stats not available.")
|
|
return
|
|
return
|
|
|
|
|
|
|
|
+ # If a token is provided, show detailed stats for that token
|
|
if context.args and len(context.args) > 0:
|
|
if context.args and len(context.args) > 0:
|
|
- # Token-specific stats
|
|
|
|
token_name = context.args[0].upper()
|
|
token_name = context.args[0].upper()
|
|
- token_stats = stats.get_token_stats(token_name)
|
|
|
|
- if not token_stats:
|
|
|
|
- await self._reply(update, f"❌ No trading data found for {token_name}.")
|
|
|
|
- return
|
|
|
|
- stats_message = await self._format_token_specific_stats_message(token_stats, token_name)
|
|
|
|
|
|
+ # Assuming get_token_detailed_stats is the correct method in TradingStats
|
|
|
|
+ # to get the data needed by format_token_stats_message.
|
|
|
|
+ stats_message = await stats.format_token_stats_message(token_name)
|
|
await self._reply(update, stats_message)
|
|
await self._reply(update, stats_message)
|
|
return
|
|
return
|
|
|
|
|
|
- # Get current balance
|
|
|
|
- current_balance = self.trading_engine.get_balance()
|
|
|
|
- # Fix: If current_balance is a dict, extract the numeric value
|
|
|
|
- if isinstance(current_balance, dict):
|
|
|
|
- # Try common keys for USDC or total
|
|
|
|
- if 'USDC' in current_balance and isinstance(current_balance['USDC'], dict):
|
|
|
|
- current_balance = current_balance['USDC'].get('total', 0)
|
|
|
|
- elif 'total' in current_balance:
|
|
|
|
- current_balance = current_balance['total']
|
|
|
|
- else:
|
|
|
|
- # Fallback: try to find a float value in the dict
|
|
|
|
- for v in current_balance.values():
|
|
|
|
- if isinstance(v, (float, int)):
|
|
|
|
- current_balance = v
|
|
|
|
- break
|
|
|
|
- else:
|
|
|
|
- current_balance = 0
|
|
|
|
-
|
|
|
|
- # Get performance stats
|
|
|
|
- perf = stats.get_performance_stats()
|
|
|
|
- if not perf:
|
|
|
|
- await self._reply(update, "❌ Could not get performance stats.")
|
|
|
|
- return
|
|
|
|
-
|
|
|
|
- # Format the message
|
|
|
|
- formatter = get_formatter()
|
|
|
|
- stats_text_parts = ["📊 <b>Trading Statistics</b>\n"]
|
|
|
|
-
|
|
|
|
- # Account Overview
|
|
|
|
- stats_text_parts.append("💰 <b>Account Overview:</b>")
|
|
|
|
- stats_text_parts.append(f"• Current Balance: {await formatter.format_price_with_symbol(current_balance)}")
|
|
|
|
- stats_text_parts.append(f"• Open Positions: {perf.get('open_positions', 0)}")
|
|
|
|
- stats_text_parts.append(f"• Total P&L: {await formatter.format_price_with_symbol(perf.get('total_pnl', 0))}")
|
|
|
|
-
|
|
|
|
- # Performance Metrics
|
|
|
|
- stats_text_parts.append("\n🏆 <b>Performance Metrics:</b>")
|
|
|
|
- stats_text_parts.append(f"• Total Trades: {perf.get('total_trades', 0)}")
|
|
|
|
- stats_text_parts.append(f"• Win Rate: {perf.get('win_rate', 0.0):.1f}% ({perf.get('total_wins', 0)}/{perf.get('total_trades', 0)})")
|
|
|
|
- stats_text_parts.append(f"• Trading Volume: {await formatter.format_price_with_symbol(perf.get('total_entry_volume', 0.0))}")
|
|
|
|
- stats_text_parts.append(f"• Profit Factor: {perf.get('profit_factor', 0.0):.2f}")
|
|
|
|
- stats_text_parts.append(f"• Expectancy: {await formatter.format_price_with_symbol(perf.get('expectancy', 0.0))}")
|
|
|
|
-
|
|
|
|
- # Largest Trades
|
|
|
|
- stats_text_parts.append("\n📈 <b>Largest Trades:</b>")
|
|
|
|
- stats_text_parts.append(f"• Largest Win: {await formatter.format_price_with_symbol(perf.get('largest_win', 0.0))} ({perf.get('largest_win_pct', 0.0):+.2f}%) ({perf.get('largest_win_token', 'N/A')})")
|
|
|
|
- stats_text_parts.append(f"• Largest Loss: {await formatter.format_price_with_symbol(perf.get('largest_loss', 0.0))} ({perf.get('largest_loss_pct', 0.0):+.2f}%) ({perf.get('largest_loss_token', 'N/A')})")
|
|
|
|
-
|
|
|
|
- # Best/Worst Tokens
|
|
|
|
- stats_text_parts.append("\n🏆 <b>Token Performance:</b>")
|
|
|
|
- stats_text_parts.append(f"• Best Token: {perf.get('best_token', 'N/A')} {await formatter.format_price_with_symbol(perf.get('best_token_pnl', 0.0))} ({perf.get('best_token_pct', 0.0):+.2f}%)")
|
|
|
|
- stats_text_parts.append(f"• Worst Token: {perf.get('worst_token', 'N/A')} {await formatter.format_price_with_symbol(perf.get('worst_token_pnl', 0.0))} ({perf.get('worst_token_pct', 0.0):+.2f}%)")
|
|
|
|
-
|
|
|
|
- # Risk Metrics
|
|
|
|
- stats_text_parts.append("\n⚠️ <b>Risk Metrics:</b>")
|
|
|
|
- stats_text_parts.append(f"• Max Drawdown: {perf.get('max_drawdown_pct', 0.0):.2f}%")
|
|
|
|
-
|
|
|
|
- # Session Info
|
|
|
|
- stats_text_parts.append("\n⏰ <b>Session Info:</b>")
|
|
|
|
- stats_text_parts.append(f"• Stats Last Updated: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S UTC')}")
|
|
|
|
-
|
|
|
|
- await self._reply(update, "\n".join(stats_text_parts))
|
|
|
|
|
|
+ # For the general /stats command, use the centralized formatter
|
|
|
|
+ balance_info = self.trading_engine.get_balance()
|
|
|
|
+ current_balance = balance_info.get('total', {}).get('USDC', 0.0)
|
|
|
|
+
|
|
|
|
+ stats_message = await stats.format_stats_message(current_balance)
|
|
|
|
+ await self._reply(update, stats_message, disable_web_page_preview=True)
|
|
|
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- logger.error(f"Error in stats command: {e}")
|
|
|
|
|
|
+ logger.error(f"Error in stats command: {e}", exc_info=True)
|
|
await self._reply(update, f"❌ Error getting statistics: {str(e)}")
|
|
await self._reply(update, f"❌ Error getting statistics: {str(e)}")
|