Преглед на файлове

Enhance trading statistics reporting - Add completed trades metric to TradingStats class and update message formatting to display performance metrics based on completed trades. Improve error handling in stats message and provide informative messages for open positions, enhancing user experience in trading analysis.

Carles Sentis преди 5 дни
родител
ревизия
7e3f3b7a7b
променени са 3 файла, в които са добавени 128 реда и са изтрити 17 реда
  1. 1 1
      config/env.example
  2. 39 16
      src/trading_stats.py
  3. 88 0
      tests/debug_stats.py

+ 1 - 1
config/env.example

@@ -46,7 +46,7 @@ BOT_HEARTBEAT_SECONDS=30
 # Logging
 # ========================================
 # Options: DEBUG, INFO, WARNING, ERROR
-LOG_LEVEL=INFO
+LOG_LEVEL=INFO 
 
 # Enable/disable logging to file (true/false)
 LOG_TO_FILE=true

+ 39 - 16
src/trading_stats.py

@@ -177,6 +177,7 @@ class TradingStats:
         if not self.data['trades']:
             return {
                 'total_trades': 0,
+                'completed_trades': 0,
                 'buy_trades': 0,
                 'sell_trades': 0,
                 'initial_balance': self.data.get('initial_balance', 0),
@@ -188,14 +189,16 @@ class TradingStats:
             }
         
         trades_with_pnl = self.calculate_trade_pnl()
-        total_pnl = sum(trade.get('pnl', 0) for trade in trades_with_pnl)
+        completed_trades = [t for t in trades_with_pnl if t.get('pnl', 0) != 0]
+        total_pnl = sum(trade.get('pnl', 0) for trade in completed_trades)
         
         # Calculate days active
         start_date = datetime.fromisoformat(self.data['start_time'])
         days_active = (datetime.now() - start_date).days + 1
         
         return {
-            'total_trades': len(self.data['trades']),
+            'total_trades': len(self.data['trades']),  # Total orders placed
+            'completed_trades': len(completed_trades),  # Actual completed trade cycles with P&L
             'buy_trades': len([t for t in self.data['trades'] if t['side'] == 'buy']),
             'sell_trades': len([t for t in self.data['trades'] if t['side'] == 'sell']),
             'initial_balance': self.data.get('initial_balance', 0),
@@ -371,6 +374,10 @@ class TradingStats:
             perf = stats['performance']
             risk = stats['risk']
             
+            # Check if we have completed trades or just open positions
+            completed_trades = basic.get('completed_trades', 0)
+            total_orders = basic.get('total_trades', 0)
+            
             message = f"""
 📊 <b>Trading Statistics</b>
 
@@ -381,11 +388,16 @@ class TradingStats:
 • Total Return: {stats.get('total_return', 0):.2f}%
 
 📈 <b>Trading Activity</b>
-• Total Trades: {basic.get('total_trades', 0)}
+• Total Orders: {total_orders}
+• Completed Trades: {completed_trades}
 • Buy Orders: {basic.get('buy_trades', 0)}
 • Sell Orders: {basic.get('sell_trades', 0)}
 • Days Active: {basic.get('days_active', 0)}
-
+            """
+            
+            if completed_trades > 0:
+                # Show full performance metrics when we have completed trades
+                message += f"""
 🏆 <b>Performance Metrics</b>
 • Win Rate: {perf.get('win_rate', 0):.1f}%
 • Profit Factor: {perf.get('profit_factor', 0):.2f}
@@ -405,30 +417,41 @@ class TradingStats:
 • Largest Loss: ${perf.get('largest_loss', 0):.2f}
 • Max Consecutive Wins: {perf.get('consecutive_wins', 0)}
 • Max Consecutive Losses: {perf.get('consecutive_losses', 0)}
+                """
+            else:
+                # Show informative message when no completed trades
+                open_positions = total_orders - (basic.get('buy_trades', 0) if basic.get('sell_trades', 0) > 0 else 0)
+                message += f"""
+💡 <b>Performance Status</b>
+• Open Positions: {open_positions} position{'s' if open_positions != 1 else ''}
+• Performance metrics will appear after closing positions
+• Current trades: Entry orders placed, waiting for exits
 
+📈 <b>Ready for Analysis</b>
+• Close positions to see P&L calculations
+• Win rate, profit factor, and risk metrics
+• Use /exit [token] to close positions
+                """
+            
+            message += f"""
 📅 <b>Since:</b> {basic.get('start_date', 'N/A')}
+
+💡 <b>Note:</b> Performance metrics based on {completed_trades} completed trade cycle{'s' if completed_trades != 1 else ''}
             """
             
             return message.strip()
-            
+                
         except Exception as e:
             # Fallback message if stats calculation fails
+            logger.error(f"Error formatting stats message: {e}")
             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>Error loading statistics</b>
 
-🔄 <b>Try again after:</b>
-• Making a trade with /long or /short
-• Checking your balance with /balance
-• Restarting the bot
+Please try again in a moment. If the issue persists, contact support.
 
-📱 <b>Current Status:</b> Statistics will be available once trading activity begins.
+🔧 <b>Debug info:</b> {str(e)[:100]}
             """.strip()
     
     def get_recent_trades(self, limit: int = 10) -> List[Dict[str, Any]]:

+ 88 - 0
tests/debug_stats.py

@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+"""
+Debug script to examine current trading stats and understand calculation issues.
+"""
+
+import sys
+import os
+import json
+from pathlib import Path
+
+# Add src directory to Python path
+sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
+
+from trading_stats import TradingStats
+
+def debug_stats():
+    """Debug current trading statistics."""
+    print("🔍 Trading Stats Debug\n")
+    
+    # Check if stats file exists
+    stats_file = "trading_stats.json"
+    if not os.path.exists(stats_file):
+        print(f"❌ Stats file {stats_file} does not exist")
+        return
+    
+    # Load raw stats data
+    print("📁 Raw Stats File:")
+    with open(stats_file, 'r') as f:
+        raw_data = json.load(f)
+    
+    print(f"   Trades count: {len(raw_data.get('trades', []))}")
+    print(f"   Initial balance: ${raw_data.get('initial_balance', 0):,.2f}")
+    print(f"   Start time: {raw_data.get('start_time', 'Not set')}")
+    
+    if raw_data.get('trades'):
+        print(f"\n📋 Raw Trades:")
+        for i, trade in enumerate(raw_data['trades'], 1):
+            print(f"   {i}. {trade['side'].upper()} {trade['amount']} {trade['symbol']} @ ${trade['price']:,.2f}")
+            print(f"      Value: ${trade['value']:,.2f} | ID: {trade.get('order_id', 'N/A')}")
+    
+    # Initialize TradingStats and test calculations
+    stats = TradingStats()
+    
+    print(f"\n🧮 Calculated P&L Trades:")
+    trades_with_pnl = stats.calculate_trade_pnl()
+    
+    for i, trade in enumerate(trades_with_pnl, 1):
+        pnl = trade.get('pnl', 0)
+        print(f"   {i}. {trade['side'].upper()} {trade['amount']} {trade['symbol']} @ ${trade['price']:,.2f}")
+        print(f"      P&L: ${pnl:,.2f} | Value: ${trade['value']:,.2f}")
+    
+    completed_trades = [t for t in trades_with_pnl if t.get('pnl', 0) != 0]
+    print(f"\n✅ Completed Trades (with P&L): {len(completed_trades)}")
+    
+    if completed_trades:
+        total_pnl = sum(t['pnl'] for t in completed_trades)
+        print(f"   Total P&L: ${total_pnl:,.2f}")
+    
+    # Test basic stats
+    print(f"\n📊 Basic Stats:")
+    basic_stats = stats.get_basic_stats()
+    for key, value in basic_stats.items():
+        if isinstance(value, float):
+            print(f"   {key}: ${value:,.2f}")
+        else:
+            print(f"   {key}: {value}")
+    
+    # Test performance stats
+    print(f"\n🏆 Performance Stats:")
+    perf_stats = stats.get_performance_stats()
+    for key, value in perf_stats.items():
+        if isinstance(value, float):
+            print(f"   {key}: {value:.2f}")
+        else:
+            print(f"   {key}: {value}")
+    
+    # Test token performance
+    print(f"\n🎯 Token Performance:")
+    token_perf = stats.get_token_performance()
+    for token, data in token_perf.items():
+        print(f"   {token}:")
+        print(f"      Total Orders: {data['total_trades']}")
+        print(f"      Completed Trades: {data['completed_trades']}")
+        print(f"      Total P&L: ${data['total_pnl']:,.2f}")
+        print(f"      Win Rate: {data['win_rate']:.1f}%")
+
+if __name__ == "__main__":
+    debug_stats()