Jelajahi Sumber

Enhance Hyperliquid Account Analyzer with detailed single account deep dive analysis

- Introduced a new method to provide a comprehensive deep dive analysis for individual accounts, including live data fetching, performance metrics, trading patterns, and copy trading evaluations.
- Updated the existing analysis results method to handle single account scenarios, improving user insights and experience.
- Enhanced output formatting for better clarity and engagement during account evaluations.
Carles Sentis 4 hari lalu
induk
melakukan
7c235388a6
2 mengubah file dengan 193 tambahan dan 4 penghapusan
  1. 1 1
      trading_bot.py
  2. 192 3
      utils/hyperliquid_account_analyzer.py

+ 1 - 1
trading_bot.py

@@ -14,7 +14,7 @@ from datetime import datetime
 from pathlib import Path
 
 # Bot version
-BOT_VERSION = "3.0.346"
+BOT_VERSION = "3.0.347"
 
 # Add src directory to Python path
 sys.path.insert(0, str(Path(__file__).parent / "src"))

+ 192 - 3
utils/hyperliquid_account_analyzer.py

@@ -832,16 +832,205 @@ class HyperliquidAccountAnalyzer:
         
         return valid_results
 
-    def print_analysis_results(self, stats_list: List[AccountStats]):
+    async def print_single_account_deep_dive(self, stats: AccountStats):
+        """Print detailed deep dive analysis for a single account"""
+        print(f"\n๐ŸŽฏ ACCOUNT: {stats.address}")
+        print("="*100)
+        
+        # Fetch current live data
+        print("๐Ÿ”„ Fetching current account state...")
+        try:
+            current_state = await self.get_account_state(stats.address)
+            current_positions = self.parse_positions(current_state) if current_state else []
+            
+            # Get recent fills for more context
+            recent_fills = await self.get_user_fills(stats.address, limit=20)
+            recent_trades = self.parse_trades(recent_fills) if recent_fills else []
+            
+        except Exception as e:
+            print(f"โš ๏ธ Could not fetch live data: {e}")
+            current_positions = []
+            recent_trades = []
+        
+        # Basic Account Information
+        print(f"\n๐Ÿ“‹ ACCOUNT OVERVIEW")
+        print(f"   ๐Ÿ“ Address: {stats.address}")
+        print(f"   ๐Ÿ“… Analysis Period: {stats.analysis_period_days} days")
+        if stats.last_trade_timestamp > 0:
+            from datetime import datetime
+            last_trade_date = datetime.fromtimestamp(stats.last_trade_timestamp / 1000)
+            print(f"   ๐Ÿ•’ Last Trade: {last_trade_date.strftime('%Y-%m-%d %H:%M:%S')} UTC")
+        
+        # Current Positions (LIVE DATA)
+        print(f"\n๐Ÿ“Š CURRENT POSITIONS ({len(current_positions)} active)")
+        if current_positions:
+            total_position_value = 0
+            total_unrealized_pnl = 0
+            
+            for pos in current_positions:
+                side_emoji = "๐Ÿ“ˆ" if pos.side == "long" else "๐Ÿ“‰"
+                pnl_emoji = "โœ…" if pos.unrealized_pnl >= 0 else "โŒ"
+                
+                print(f"   {side_emoji} {pos.coin} - {pos.side.upper()}")
+                print(f"      ๐Ÿ’ฐ Size: {pos.size:.6f} {pos.coin} @ ${pos.entry_price:.4f}")
+                print(f"      ๐Ÿท๏ธ Mark Price: ${pos.mark_price:.4f}")
+                print(f"      {pnl_emoji} Unrealized PnL: ${pos.unrealized_pnl:.2f}")
+                print(f"      โš–๏ธ Leverage: {pos.leverage:.1f}x")
+                print(f"      ๐Ÿ’ณ Margin Used: ${pos.margin_used:.2f}")
+                
+                total_position_value += abs(pos.size * pos.mark_price)
+                total_unrealized_pnl += pos.unrealized_pnl
+                print()
+            
+            print(f"   ๐Ÿ“Š POSITION SUMMARY:")
+            print(f"      ๐Ÿ’ผ Total Position Value: ${total_position_value:.2f}")
+            print(f"      ๐Ÿ“ˆ Total Unrealized PnL: ${total_unrealized_pnl:.2f}")
+            
+        else:
+            print("   ๐Ÿ’ค No active positions")
+        
+        # Performance Metrics
+        print(f"\n๐Ÿ“ˆ PERFORMANCE ANALYSIS")
+        print(f"   ๐Ÿ’ฐ Total Realized PnL: ${stats.total_pnl:.2f}")
+        print(f"   ๐Ÿ“Š Win Rate: {stats.win_rate:.1%}")
+        print(f"   ๐ŸŽฏ Total Trades: {stats.total_trades}")
+        print(f"   ๐Ÿ’ต Average Position Size: ${stats.avg_position_size:.2f}")
+        print(f"   โฑ๏ธ Average Trade Duration: {stats.avg_trade_duration_hours:.1f} hours")
+        print(f"   ๐Ÿ“‰ Maximum Drawdown: {stats.max_drawdown:.1%}")
+        print(f"   ๐Ÿ“‰ Current Drawdown: {stats.current_drawdown:.1%}")
+        print(f"   ๐Ÿ† Largest Win: ${stats.largest_win:.2f}")
+        print(f"   ๐Ÿ’” Largest Loss: ${stats.largest_loss:.2f}")
+        print(f"   ๐Ÿ“Š Profit Factor: {stats.profit_factor:.2f}")
+        print(f"   ๐Ÿ”— Max Consecutive Losses: {stats.consecutive_losses_max}")
+        
+        # Trading Patterns
+        print(f"\n๐ŸŽฒ TRADING PATTERNS")
+        print(f"   ๐Ÿ”„ Trading Frequency: {stats.trading_frequency_per_day:.1f} trades/day")
+        print(f"   โš–๏ธ Average Leverage: {stats.avg_leverage_used:.1f}x")
+        print(f"   ๐Ÿ“Š Max Leverage Used: {stats.max_leverage_used:.1f}x")
+        print(f"   ๐Ÿช™ Unique Tokens Traded: {stats.unique_tokens_traded}")
+        
+        # Trading style analysis
+        trading_type_display = {
+            "perps": "๐Ÿ”„ Perpetuals",
+            "spot": "๐Ÿ’ฑ Spot Trading", 
+            "mixed": "๐Ÿ”€ Mixed (Spot + Perps)",
+            "unknown": "โ“ Unknown"
+        }.get(stats.trading_type, f"โ“ {stats.trading_type}")
+        print(f"   ๐Ÿ“ˆ Trading Type: {trading_type_display}")
+        print(f"   ๐Ÿ“Š Trading Style: {stats.trading_style}")
+        print(f"   ๐Ÿ“‰ Short Percentage: {stats.short_percentage:.1f}%")
+        
+        # Buy/Sell ratio
+        if stats.buy_sell_ratio == float('inf'):
+            ratio_display = "โˆž (only buys)"
+        elif stats.buy_sell_ratio == 0:
+            ratio_display = "0 (only sells)" 
+        else:
+            ratio_display = f"{stats.buy_sell_ratio:.2f}"
+        print(f"   โš–๏ธ Buy/Sell Ratio: {ratio_display}")
+        
+        # Top tokens
+        if stats.top_tokens:
+            print(f"   ๐Ÿ† Top Traded Tokens: {', '.join(stats.top_tokens[:5])}")
+        
+        # Recent Trading Activity
+        if recent_trades:
+            print(f"\n๐Ÿ•’ RECENT TRADING ACTIVITY (last {len(recent_trades)} trades)")
+            for i, trade in enumerate(recent_trades[:10], 1):  # Show last 10 trades
+                from datetime import datetime
+                trade_time = datetime.fromtimestamp(trade.timestamp / 1000)
+                side_emoji = "๐ŸŸข" if trade.side == "buy" else "๐Ÿ”ด"
+                
+                print(f"   {i}. {side_emoji} {trade.side.upper()} {trade.size:.6f} {trade.coin}")
+                print(f"      ๐Ÿ’ฐ Price: ${trade.price:.4f} | Value: ${trade.size * trade.price:.2f}")
+                print(f"      ๐Ÿ•’ Time: {trade_time.strftime('%m-%d %H:%M:%S')}")
+                if i < len(recent_trades[:10]):
+                    print()
+        
+        # Copy Trading Evaluation
+        print(f"\n๐ŸŽฏ COPY TRADING EVALUATION")
+        print(f"   โœ… Copyable: {'YES' if stats.is_copyable else 'NO'}")
+        print(f"   ๐Ÿ“ Reason: {stats.copyability_reason}")
+        
+        # Detailed evaluation
+        evaluation = []
+        is_hft_pattern = stats.trading_frequency_per_day > 50
+        is_copyable = 1 <= stats.trading_frequency_per_day <= 20
+        
+        if is_hft_pattern:
+            evaluation.append("โŒ HFT/Bot pattern detected")
+        elif stats.trading_frequency_per_day < 1:
+            evaluation.append("โŒ Too inactive for copy trading")
+        elif is_copyable:
+            evaluation.append("โœ… Human-like trading pattern")
+        
+        if stats.total_pnl > 0:
+            evaluation.append("โœ… Profitable track record")
+        else:
+            evaluation.append("โŒ Not profitable")
+        
+        if stats.max_drawdown < 0.15:
+            evaluation.append("โœ… Good risk management")
+        elif stats.max_drawdown < 0.25:
+            evaluation.append("โš ๏ธ Moderate risk")
+        else:
+            evaluation.append("โŒ High risk (excessive drawdown)")
+        
+        if 2 <= stats.avg_trade_duration_hours <= 48:
+            evaluation.append("โœ… Suitable trade duration")
+        elif stats.avg_trade_duration_hours < 2:
+            evaluation.append("โš ๏ธ Very short trades (scalping)")
+        else:
+            evaluation.append("โš ๏ธ Long hold times")
+        
+        print(f"\n   ๐Ÿ“Š Detailed Evaluation:")
+        for eval_point in evaluation:
+            print(f"      {eval_point}")
+        
+        # Copy Trading Recommendations
+        if stats.is_copyable and stats.total_pnl > 0:
+            print(f"\n๐Ÿ’ก COPY TRADING RECOMMENDATIONS")
+            
+            if stats.max_drawdown < 0.1 and stats.win_rate > 0.6:
+                print(f"   ๐Ÿ“Š Suggested Portfolio Allocation: 15-25% (high confidence)")
+                print(f"   โš–๏ธ Max Leverage Limit: 8-10x")
+            elif stats.max_drawdown < 0.2 and stats.win_rate > 0.5:
+                print(f"   ๐Ÿ“Š Suggested Portfolio Allocation: 8-15% (moderate confidence)")
+                print(f"   โš–๏ธ Max Leverage Limit: 5-8x")
+            else:
+                print(f"   ๐Ÿ“Š Suggested Portfolio Allocation: 3-8% (low confidence)")
+                print(f"   โš–๏ธ Max Leverage Limit: 2-5x")
+            
+            print(f"   ๐Ÿ’ฐ Min Position Size: $25-50")
+            print(f"   ๐Ÿ”„ Expected Activity: ~{stats.trading_frequency_per_day:.1f} trades/day")
+            print(f"   โฑ๏ธ Avg Trade Duration: ~{stats.avg_trade_duration_hours:.1f} hours")
+            
+        else:
+            print(f"\nโŒ NOT RECOMMENDED FOR COPY TRADING")
+            print(f"   Reason: {stats.copyability_reason}")
+
+    async def print_analysis_results(self, stats_list: List[AccountStats]):
         """Print comprehensive analysis results with relative scoring"""
         if not stats_list:
             print("โŒ No valid analysis results to display")
             return
         
+        # Check if this is a single account deep dive
+        is_single_account = len(stats_list) == 1
+        
         print("\n" + "="*100)
-        print("๐Ÿ“Š HYPERLIQUID ACCOUNT ANALYSIS RESULTS")
+        if is_single_account:
+            print("๐Ÿ” DEEP DIVE ACCOUNT ANALYSIS")
+        else:
+            print("๐Ÿ“Š HYPERLIQUID ACCOUNT ANALYSIS RESULTS")
         print("="*100)
         
+        # Special handling for single account analysis
+        if is_single_account:
+            await self.print_single_account_deep_dive(stats_list[0])
+            return
+        
         # Calculate data ranges for relative scoring
         def get_data_ranges(stats_list):
             """Calculate min/max values for relative scoring"""
@@ -1458,7 +1647,7 @@ async def main():
             return
             
         results = await analyzer.analyze_multiple_accounts(addresses)
-        analyzer.print_analysis_results(results)
+        await analyzer.print_analysis_results(results)
 
 if __name__ == "__main__":
     asyncio.run(main())