|
@@ -211,7 +211,10 @@ class TradingStats:
|
|
|
'largest_win': 0,
|
|
|
'largest_loss': 0,
|
|
|
'consecutive_wins': 0,
|
|
|
- 'consecutive_losses': 0
|
|
|
+ 'consecutive_losses': 0,
|
|
|
+ 'total_wins': 0,
|
|
|
+ 'total_losses': 0,
|
|
|
+ 'expectancy': 0
|
|
|
}
|
|
|
|
|
|
# Separate wins and losses
|
|
@@ -353,51 +356,72 @@ class TradingStats:
|
|
|
|
|
|
def format_stats_message(self, current_balance: float = None) -> str:
|
|
|
"""Format stats for Telegram display."""
|
|
|
- stats = self.get_comprehensive_stats(current_balance)
|
|
|
-
|
|
|
- basic = stats['basic']
|
|
|
- perf = stats['performance']
|
|
|
- risk = stats['risk']
|
|
|
-
|
|
|
- message = f"""
|
|
|
+ try:
|
|
|
+ stats = self.get_comprehensive_stats(current_balance)
|
|
|
+
|
|
|
+ basic = stats['basic']
|
|
|
+ perf = stats['performance']
|
|
|
+ risk = stats['risk']
|
|
|
+
|
|
|
+ message = f"""
|
|
|
📊 <b>Trading Statistics</b>
|
|
|
|
|
|
💰 <b>Balance Overview</b>
|
|
|
-• Initial: ${basic['initial_balance']:,.2f}
|
|
|
-• Current: ${stats['current_balance']:,.2f}
|
|
|
-• Total P&L: ${basic['total_pnl']:,.2f}
|
|
|
-• Total Return: {stats['total_return']:.2f}%
|
|
|
+• Initial: ${basic.get('initial_balance', 0):,.2f}
|
|
|
+• Current: ${stats.get('current_balance', 0):,.2f}
|
|
|
+• Total P&L: ${basic.get('total_pnl', 0):,.2f}
|
|
|
+• Total Return: {stats.get('total_return', 0):.2f}%
|
|
|
|
|
|
📈 <b>Trading Activity</b>
|
|
|
-• Total Trades: {basic['total_trades']}
|
|
|
-• Buy Orders: {basic['buy_trades']}
|
|
|
-• Sell Orders: {basic['sell_trades']}
|
|
|
-• Days Active: {basic['days_active']}
|
|
|
+• Total Trades: {basic.get('total_trades', 0)}
|
|
|
+• Buy Orders: {basic.get('buy_trades', 0)}
|
|
|
+• Sell Orders: {basic.get('sell_trades', 0)}
|
|
|
+• Days Active: {basic.get('days_active', 0)}
|
|
|
|
|
|
🏆 <b>Performance Metrics</b>
|
|
|
-• Win Rate: {perf['win_rate']:.1f}%
|
|
|
-• Profit Factor: {perf['profit_factor']:.2f}
|
|
|
-• Avg Win: ${perf['avg_win']:.2f}
|
|
|
-• Avg Loss: ${perf['avg_loss']:.2f}
|
|
|
-• Expectancy: ${perf['expectancy']:.2f}
|
|
|
+• Win Rate: {perf.get('win_rate', 0):.1f}%
|
|
|
+• Profit Factor: {perf.get('profit_factor', 0):.2f}
|
|
|
+• Avg Win: ${perf.get('avg_win', 0):.2f}
|
|
|
+• Avg Loss: ${perf.get('avg_loss', 0):.2f}
|
|
|
+• Expectancy: ${perf.get('expectancy', 0):.2f}
|
|
|
|
|
|
📊 <b>Risk Metrics</b>
|
|
|
-• Sharpe Ratio: {risk['sharpe_ratio']:.2f}
|
|
|
-• Sortino Ratio: {risk['sortino_ratio']:.2f}
|
|
|
-• Max Drawdown: {risk['max_drawdown']:.2f}%
|
|
|
-• Volatility: {risk['volatility']:.2f}%
|
|
|
-• VaR (95%): {risk['var_95']:.2f}%
|
|
|
+• Sharpe Ratio: {risk.get('sharpe_ratio', 0):.2f}
|
|
|
+• Sortino Ratio: {risk.get('sortino_ratio', 0):.2f}
|
|
|
+• Max Drawdown: {risk.get('max_drawdown', 0):.2f}%
|
|
|
+• Volatility: {risk.get('volatility', 0):.2f}%
|
|
|
+• VaR (95%): {risk.get('var_95', 0):.2f}%
|
|
|
|
|
|
🎯 <b>Best/Worst</b>
|
|
|
-• Largest Win: ${perf['largest_win']:.2f}
|
|
|
-• Largest Loss: ${perf['largest_loss']:.2f}
|
|
|
-• Max Consecutive Wins: {perf['consecutive_wins']}
|
|
|
-• Max Consecutive Losses: {perf['consecutive_losses']}
|
|
|
+• Largest Win: ${perf.get('largest_win', 0):.2f}
|
|
|
+• Largest Loss: ${perf.get('largest_loss', 0):.2f}
|
|
|
+• Max Consecutive Wins: {perf.get('consecutive_wins', 0)}
|
|
|
+• Max Consecutive Losses: {perf.get('consecutive_losses', 0)}
|
|
|
|
|
|
-📅 <b>Since:</b> {basic['start_date']}
|
|
|
- """
|
|
|
-
|
|
|
- return message.strip()
|
|
|
+📅 <b>Since:</b> {basic.get('start_date', 'N/A')}
|
|
|
+ """
|
|
|
+
|
|
|
+ return message.strip()
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ # Fallback message if stats calculation fails
|
|
|
+ return f"""
|
|
|
+📊 <b>Trading Statistics</b>
|
|
|
+
|
|
|
+⚠️ <b>Error loading statistics:</b> {str(e)}
|
|
|
+
|
|
|
+💡 <b>This might happen if:</b>
|
|
|
+• No trading data has been recorded yet
|
|
|
+• Stats file is corrupted or missing
|
|
|
+• Balance information is not available
|
|
|
+
|
|
|
+🔄 <b>Try again after:</b>
|
|
|
+• Making a trade with /long or /short
|
|
|
+• Checking your balance with /balance
|
|
|
+• Restarting the bot
|
|
|
+
|
|
|
+📱 <b>Current Status:</b> Statistics will be available once trading activity begins.
|
|
|
+ """.strip()
|
|
|
|
|
|
def get_recent_trades(self, limit: int = 10) -> List[Dict[str, Any]]:
|
|
|
"""Get recent trades."""
|