Browse Source

Enhance Hyperliquid Account Analyzer with token diversity and trading pattern analysis

- Introduced methods to analyze token diversity, trading type, and short/long trading patterns.
- Updated account statistics to include unique tokens traded, trading type, top tokens, short percentage, and trading style.
- Enhanced output to display detailed trading analysis, improving insights for users.
Carles Sentis 4 days ago
parent
commit
63d256933d
2 changed files with 196 additions and 2 deletions
  1. 1 1
      trading_bot.py
  2. 195 1
      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.336"
+BOT_VERSION = "3.0.337"
 
 # Add src directory to Python path
 sys.path.insert(0, str(Path(__file__).parent / "src"))

+ 195 - 1
utils/hyperliquid_account_analyzer.py

@@ -93,6 +93,12 @@ class AccountStats:
     analysis_period_days: int
     is_copyable: bool  # Whether this account is suitable for copy trading
     copyability_reason: str  # Why it is/isn't copyable
+    unique_tokens_traded: int  # Number of unique tokens/coins traded
+    trading_type: str  # "spot", "perps", or "mixed"
+    top_tokens: List[str]  # Top 5 most traded tokens by volume
+    short_percentage: float  # Percentage of trades that are likely shorts
+    trading_style: str  # Directional trading style description
+    buy_sell_ratio: float  # Ratio of buys to sells
 
 class HyperliquidAccountAnalyzer:
     """Analyzes Hyperliquid trading accounts"""
@@ -450,6 +456,146 @@ class HyperliquidAccountAnalyzer:
         
         return cumulative_pnl, pnl_series, winning_periods, losing_periods
 
+    def analyze_token_diversity_and_type(self, trades: List[Trade], positions: List[Position]) -> Tuple[int, str, List[str]]:
+        """
+        Analyze token diversity and determine trading type (spot vs perps)
+        
+        Returns:
+            tuple: (unique_tokens_count, trading_type, top_tokens_list)
+        """
+        if not trades:
+            return 0, "unknown", []
+        
+        # Count token frequency by volume
+        token_volumes = defaultdict(float)
+        for trade in trades:
+            volume = trade.size * trade.price
+            token_volumes[trade.coin] += volume
+        
+        # Get unique token count
+        unique_tokens = len(token_volumes)
+        
+        # Get top 5 tokens by volume
+        sorted_tokens = sorted(token_volumes.items(), key=lambda x: x[1], reverse=True)
+        top_tokens = [token for token, _ in sorted_tokens[:5]]
+        
+        # Determine trading type based on positions and leverage
+        trading_type = self._determine_trading_type(positions, trades)
+        
+        return unique_tokens, trading_type, top_tokens
+    
+    def _determine_trading_type(self, positions: List[Position], trades: List[Trade]) -> str:
+        """
+        Determine if account trades spot, perps, or mixed
+        
+        Logic:
+        - If positions have leverage > 1.1, it's perps
+        - If no positions with leverage, check for margin/leverage indicators
+        - Hyperliquid primarily offers perps, so default to perps if uncertain
+        """
+        if not positions and not trades:
+            return "unknown"
+        
+        # Check current positions for leverage
+        leveraged_positions = 0
+        total_positions = len(positions)
+        
+        for position in positions:
+            if position.leverage > 1.1:  # Consider leverage > 1.1 as perps
+                leveraged_positions += 1
+        
+        # If we have positions, determine based on leverage
+        if total_positions > 0:
+            leverage_ratio = leveraged_positions / total_positions
+            
+            if leverage_ratio >= 0.8:  # 80%+ leveraged positions = perps
+                return "perps"
+            elif leverage_ratio <= 0.2:  # 20%- leveraged positions = spot
+                return "spot"  
+            else:  # Mixed
+                return "mixed"
+        
+        # If no current positions, check historical leverage patterns
+        # For Hyperliquid, most trading is perps, so default to perps
+        # We could also check if trades show signs of leverage (frequent short selling, etc.)
+        
+        # Check for short selling patterns (indicator of perps)
+        total_trades = len(trades)
+        if total_trades > 0:
+            sell_trades = sum(1 for trade in trades if trade.side == 'sell')
+            buy_trades = total_trades - sell_trades
+            
+            # If significantly more sells than buys, likely includes short selling (perps)
+            if sell_trades > buy_trades * 1.2:
+                return "perps"
+            # If roughly balanced, could be perps with both long/short
+            elif abs(sell_trades - buy_trades) / total_trades < 0.3:
+                return "perps"
+        
+        # Default to perps for Hyperliquid (they primarily offer perps)
+        return "perps"
+
+    def analyze_short_long_patterns(self, trades: List[Trade]) -> Dict[str, Any]:
+        """
+        Analyze short/long trading patterns for perpetual traders
+        
+        Returns:
+            dict: Analysis of directional trading patterns
+        """
+        if not trades:
+            return {
+                'total_buys': 0,
+                'total_sells': 0,
+                'buy_sell_ratio': 0,
+                'likely_short_trades': 0,
+                'directional_balance': 'unknown',
+                'trading_style': 'unknown'
+            }
+        
+        total_buys = sum(1 for trade in trades if trade.side == 'buy')
+        total_sells = sum(1 for trade in trades if trade.side == 'sell')
+        total_trades = len(trades)
+        
+        buy_sell_ratio = total_buys / max(1, total_sells)
+        
+        # Analyze trading patterns
+        if abs(total_buys - total_sells) / total_trades < 0.1:  # Within 10%
+            directional_balance = "balanced"
+            trading_style = "Long/Short Balanced (can profit both ways)"
+        elif total_sells > total_buys * 1.3:  # 30% more sells
+            directional_balance = "sell_heavy"
+            trading_style = "Short-Heavy (profits from price drops)"
+        elif total_buys > total_sells * 1.3:  # 30% more buys
+            directional_balance = "buy_heavy" 
+            trading_style = "Long-Heavy (profits from price rises)"
+        else:
+            directional_balance = "moderately_balanced"
+            trading_style = "Moderately Balanced (flexible direction)"
+        
+        # Estimate likely short positions (sells without preceding buys)
+        likely_shorts = 0
+        position_tracker = defaultdict(lambda: {'net_position': 0})
+        
+        for trade in sorted(trades, key=lambda x: x.timestamp):
+            coin_pos = position_tracker[trade.coin]
+            
+            if trade.side == 'sell':
+                if coin_pos['net_position'] <= 0:  # Selling without long position = likely short
+                    likely_shorts += 1
+                coin_pos['net_position'] -= trade.size
+            else:  # buy
+                coin_pos['net_position'] += trade.size
+        
+        return {
+            'total_buys': total_buys,
+            'total_sells': total_sells,
+            'buy_sell_ratio': buy_sell_ratio,
+            'likely_short_trades': likely_shorts,
+            'short_percentage': (likely_shorts / total_trades * 100) if total_trades > 0 else 0,
+            'directional_balance': directional_balance,
+            'trading_style': trading_style
+        }
+
     async def analyze_account(self, address: str) -> Optional[AccountStats]:
         """Analyze a single account and return comprehensive statistics"""
         print(f"\n🔍 Analyzing account: {address}")
@@ -617,6 +763,12 @@ class HyperliquidAccountAnalyzer:
                 # Fallback if variables don't exist
                 risk_reward_ratio = win_rate / (1 - win_rate) if win_rate < 1 else 1.0
         
+        # Analyze token diversity and trading type
+        unique_tokens, trading_type, top_tokens = self.analyze_token_diversity_and_type(trades, positions)
+        
+        # Analyze short/long patterns
+        short_long_analysis = self.analyze_short_long_patterns(trades)
+        
         return AccountStats(
             address=address,
             total_pnl=total_pnl,
@@ -639,7 +791,13 @@ class HyperliquidAccountAnalyzer:
             last_trade_timestamp=newest_trade,
             analysis_period_days=int(analysis_period_days),
             is_copyable=is_copyable,
-            copyability_reason=copyability_reason
+            copyability_reason=copyability_reason,
+            unique_tokens_traded=unique_tokens,
+            trading_type=trading_type,
+            top_tokens=top_tokens,
+            short_percentage=short_long_analysis['short_percentage'],
+            trading_style=short_long_analysis['trading_style'],
+            buy_sell_ratio=short_long_analysis['buy_sell_ratio']
         )
 
     async def analyze_multiple_accounts(self, addresses: List[str]) -> List[AccountStats]:
@@ -836,6 +994,30 @@ class HyperliquidAccountAnalyzer:
             print(f"   📍 Active Positions: {stats.active_positions}")
             print(f"   📅 Analysis Period: {stats.analysis_period_days} days")
             
+            # New token and trading type information
+            print(f"   🪙 Unique Tokens: {stats.unique_tokens_traded}")
+            
+            # Trading type with emoji
+            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}")
+            
+            # Short/Long patterns - KEY ADVANTAGE
+            print(f"   📊 Trading Style: {stats.trading_style}")
+            print(f"   📉 Short Trades: {stats.short_percentage:.1f}% (can profit from price drops)")
+            print(f"   ⚖️ Buy/Sell Ratio: {stats.buy_sell_ratio:.2f}")
+            
+            # Top tokens
+            if stats.top_tokens:
+                top_tokens_str = ", ".join(stats.top_tokens[:3])  # Show top 3
+                if len(stats.top_tokens) > 3:
+                    top_tokens_str += f" +{len(stats.top_tokens)-3} more"
+                print(f"   🏆 Top Tokens: {top_tokens_str}")
+            
             # Copy Trading Suitability Evaluation
             evaluation = []
             is_hft_pattern = stats.trading_frequency_per_day > 50
@@ -947,6 +1129,18 @@ class HyperliquidAccountAnalyzer:
         print(f"   • Start with small allocation (5%) and increase gradually")
         print(f"   • Monitor performance and adjust leverage accordingly")
         print(f"   • Higher relative scores indicate better performance within this cohort")
+        print(f"   • 🔄 ADVANTAGE: Perpetual traders can profit in BOTH bull & bear markets!")
+        print(f"   • 📈📉 They go long (profit when price rises) AND short (profit when price falls)")
+        print(f"   • 💡 This means potential profits in any market condition")
+        
+        # Show directional trading summary
+        if copyable_accounts:
+            print(f"\n🎯 DIRECTIONAL TRADING ANALYSIS OF COPYABLE ACCOUNTS:")
+            for i, (stats, score, breakdown) in enumerate(copyable_accounts, 1):
+                short_capability = "✅ Excellent" if stats.short_percentage > 30 else "⚠️ Limited" if stats.short_percentage > 10 else "❌ Minimal"
+                print(f"   {i}. {stats.address[:10]}... - {stats.short_percentage:.1f}% shorts ({short_capability} short capability)")
+                print(f"      Style: {stats.trading_style}")
+                print(f"      Advantage: Can profit when {', '.join(stats.top_tokens[:2])} prices move in EITHER direction")
 
     async def get_leaderboard(self, window: str = "7d", limit: int = 20) -> Optional[List[str]]:
         """