瀏覽代碼

Update bot version to 3.0.345 and remove account balance and PnL percentage calculations from Hyperliquid Account Analyzer

- Incremented bot version for release.
- Removed methods and calculations related to account balance and PnL percentage, streamlining the analysis process.
- Adjusted output messages to reflect the removal of account balance and PnL percentage information.
Carles Sentis 4 天之前
父節點
當前提交
c37ae33871
共有 2 個文件被更改,包括 34 次插入90 次删除
  1. 1 1
      trading_bot.py
  2. 33 89
      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.344"
+BOT_VERSION = "3.0.345"
 
 # Add src directory to Python path
 sys.path.insert(0, str(Path(__file__).parent / "src"))

+ 33 - 89
utils/hyperliquid_account_analyzer.py

@@ -99,8 +99,6 @@ class AccountStats:
     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
-    account_balance: float  # Current account balance (accountValue)
-    pnl_percentage: float  # Total PnL as percentage of account balance
 
 class HyperliquidAccountAnalyzer:
     """Analyzes Hyperliquid trading accounts"""
@@ -212,34 +210,6 @@ class HyperliquidAccountAnalyzer:
                 
         return trades
     
-    def get_account_balance(self, account_state: Dict) -> float:
-        """Extract account balance from account state"""
-        if not account_state:
-            return 0.0
-        
-        try:
-            # Try to get account value from marginSummary
-            margin_summary = account_state.get('marginSummary', {})
-            if margin_summary:
-                account_value = float(margin_summary.get('accountValue', '0'))
-                if account_value > 0:
-                    return account_value
-            
-            # Fallback: try crossMarginSummary
-            cross_margin = account_state.get('crossMarginSummary', {})
-            if cross_margin:
-                account_value = float(cross_margin.get('accountValue', '0'))
-                if account_value > 0:
-                    return account_value
-            
-            # Last resort: estimate from withdrawable balance
-            withdrawable = float(account_state.get('withdrawable', '0'))
-            return withdrawable
-            
-        except (ValueError, KeyError) as e:
-            print(f"⚠️ Warning: Could not extract account balance: {e}")
-            return 0.0
-
     def parse_positions(self, account_state: Dict) -> List[Position]:
         """Parse account state into Position objects"""
         positions = []
@@ -749,22 +719,8 @@ class HyperliquidAccountAnalyzer:
         unrealized_pnl = sum(pos.unrealized_pnl for pos in positions)
         total_pnl = realized_pnl + unrealized_pnl
         
-        # Extract account balance for percentage calculations
-        account_balance = self.get_account_balance(account_state)
-        
-        # Calculate percentage return
-        if account_balance > 0:
-            # PnL percentage = total_pnl / (account_balance - total_pnl) * 100
-            # This gives us the return on the original balance before PnL
-            original_balance = account_balance - total_pnl
-            pnl_percentage = (total_pnl / original_balance * 100) if original_balance > 0 else 0.0
-        else:
-            pnl_percentage = 0.0
-        
         print(f"💰 Total PnL: ${total_pnl:.2f} (Realized: ${realized_pnl:.2f} + Unrealized: ${unrealized_pnl:.2f})")
         print(f"💸 Total Fees: ${total_fees:.2f}")
-        print(f"🏦 Account Balance: ${account_balance:.2f}")
-        print(f"📊 PnL Percentage: {pnl_percentage:.2f}%")
         
         # Calculate position size statistics
         position_sizes = [trade.size * trade.price for trade in trades]
@@ -856,9 +812,7 @@ class HyperliquidAccountAnalyzer:
             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'],
-            account_balance=account_balance,
-            pnl_percentage=pnl_percentage
+            buy_sell_ratio=short_long_analysis['buy_sell_ratio']
         )
 
     async def analyze_multiple_accounts(self, addresses: List[str]) -> List[AccountStats]:
@@ -900,26 +854,19 @@ class HyperliquidAccountAnalyzer:
             
             ranges = {}
             
-            # Profitability range (use percentage returns for fair comparison)
-            pnl_percentages = [s.pnl_percentage for s in all_accounts]
-            ranges['pnl_pct_min'] = min(pnl_percentages)
-            ranges['pnl_pct_max'] = max(pnl_percentages)
-            ranges['pnl_pct_range'] = ranges['pnl_pct_max'] - ranges['pnl_pct_min']
-            
-            # Separate positive and negative percentage returns for different scoring
-            positive_pnl_pcts = [p for p in pnl_percentages if p > 0]
-            negative_pnl_pcts = [p for p in pnl_percentages if p < 0]
-            ranges['has_profitable'] = len(positive_pnl_pcts) > 0
-            ranges['has_unprofitable'] = len(negative_pnl_pcts) > 0
-            ranges['most_profitable_pct'] = max(positive_pnl_pcts) if positive_pnl_pcts else 0
-            ranges['most_unprofitable_pct'] = min(negative_pnl_pcts) if negative_pnl_pcts else 0
-            
-            # Keep absolute PnL for display purposes
+            # Profitability range (use all accounts)
             pnls = [s.total_pnl for s in all_accounts]
             ranges['pnl_min'] = min(pnls)
             ranges['pnl_max'] = max(pnls)
-            ranges['most_profitable'] = max([p for p in pnls if p > 0]) if any(p > 0 for p in pnls) else 0
-            ranges['most_unprofitable'] = min([p for p in pnls if p < 0]) if any(p < 0 for p in pnls) else 0
+            ranges['pnl_range'] = ranges['pnl_max'] - ranges['pnl_min']
+            
+            # Separate positive and negative PnL for different scoring
+            positive_pnls = [p for p in pnls if p > 0]
+            negative_pnls = [p for p in pnls if p < 0]
+            ranges['has_profitable'] = len(positive_pnls) > 0
+            ranges['has_unprofitable'] = len(negative_pnls) > 0
+            ranges['most_profitable'] = max(positive_pnls) if positive_pnls else 0
+            ranges['most_unprofitable'] = min(negative_pnls) if negative_pnls else 0
             
             # Win rate range (use all accounts)
             win_rates = [s.win_rate for s in all_accounts]
@@ -989,27 +936,27 @@ class HyperliquidAccountAnalyzer:
             
             score += copyability_score
             
-            # 2. PROFITABILITY (30% weight) - FAIR COMPARISON using percentage returns
-            if stats.pnl_percentage < 0:
-                # Severe punishment for unprofitable accounts (based on percentage loss)
-                if ranges['has_unprofitable'] and ranges['most_unprofitable_pct'] < stats.pnl_percentage:
+            # 2. PROFITABILITY (30% weight) - HARSH PUNISHMENT for losses
+            if stats.total_pnl < 0:
+                # Severe punishment for unprofitable accounts
+                if ranges['has_unprofitable'] and ranges['most_unprofitable'] < stats.total_pnl:
                     # Scale from -15 (worst) to 0 (break-even)
-                    loss_severity = abs(stats.pnl_percentage) / abs(ranges['most_unprofitable_pct'])
+                    loss_severity = abs(stats.total_pnl) / abs(ranges['most_unprofitable'])
                     profitability_score = -15 * loss_severity  # Negative score for losses!
                 else:
                     profitability_score = -15  # Maximum penalty
-                score_breakdown['profitability'] = f"❌ LOSING ({profitability_score:.1f} points - {stats.pnl_percentage:.1f}% LOSS, ${stats.total_pnl:.0f})"
-            elif stats.pnl_percentage == 0:
+                score_breakdown['profitability'] = f"❌ LOSING ({profitability_score:.1f} points - ${stats.total_pnl:.0f} LOSS)"
+            elif stats.total_pnl == 0:
                 profitability_score = 0  # Breakeven gets no points
-                score_breakdown['profitability'] = f"⚖️ Breakeven (0 points - {stats.pnl_percentage:.1f}%, ${stats.total_pnl:.0f})"
+                score_breakdown['profitability'] = f"⚖️ Breakeven (0 points - ${stats.total_pnl:.0f})"
             else:
-                # Positive percentage returns get full scoring - FAIR comparison regardless of account size
-                if ranges['has_profitable'] and ranges['most_profitable_pct'] > 0:
-                    profit_ratio = stats.pnl_percentage / ranges['most_profitable_pct']
+                # Positive PnL gets full scoring
+                if ranges['has_profitable'] and ranges['most_profitable'] > 0:
+                    profit_ratio = stats.total_pnl / ranges['most_profitable']
                     profitability_score = profit_ratio * 30
                 else:
                     profitability_score = 15  # Average score if only one profitable account
-                score_breakdown['profitability'] = f"✅ Profitable ({profitability_score:.1f} points - {stats.pnl_percentage:.1f}% return, ${stats.total_pnl:.0f})"
+                score_breakdown['profitability'] = f"✅ Profitable ({profitability_score:.1f} points - ${stats.total_pnl:.0f})"
             
             score += profitability_score
             
@@ -1077,18 +1024,16 @@ class HyperliquidAccountAnalyzer:
         
         # Print data ranges for context
         print(f"\n📊 COHORT ANALYSIS (for relative scoring):")
-        print(f"   📊 Return Range: {ranges['pnl_pct_min']:.1f}% to {ranges['pnl_pct_max']:.1f}% (FAIR COMPARISON)")
+        print(f"   💰 PnL Range: ${ranges['pnl_min']:.0f} to ${ranges['pnl_max']:.0f}")
         if ranges['has_unprofitable']:
-            print(f"   ❌ Worst Loss: {ranges['most_unprofitable_pct']:.1f}% (${ranges['most_unprofitable']:.0f})")
+            print(f"   ❌ Worst Loss: ${ranges['most_unprofitable']:.0f}")
         if ranges['has_profitable']:
-            print(f"   ✅ Best Return: {ranges['most_profitable_pct']:.1f}% (${ranges['most_profitable']:.0f})")
-        print(f"   💰 Absolute PnL Range: ${ranges['pnl_min']:.0f} to ${ranges['pnl_max']:.0f}")
+            print(f"   ✅ Best Profit: ${ranges['most_profitable']:.0f}")
         print(f"   📈 Win Rate Range: {ranges['winrate_min']:.1%} to {ranges['winrate_max']:.1%}")
         print(f"   🔄 Frequency Range: {ranges['freq_min']:.1f} to {ranges['freq_max']:.1f} trades/day")
         print(f"   📉 Drawdown Range: {ranges['drawdown_min']:.1%} to {ranges['drawdown_max']:.1%}")
         print(f"   📅 Account Age Range: {ranges['age_min']} to {ranges['age_max']} days")
-        print(f"\n⚠️ NOTE: Scoring now uses PERCENTAGE RETURNS for fair comparison across account sizes!")
-        print(f"⚠️ WARNING: Accounts with losses or high drawdown receive NEGATIVE scores!")
+        print(f"\n⚠️ WARNING: Accounts with losses or high drawdown receive NEGATIVE scores!")
         
         # Print results (top 10 only)
         total_accounts = len(scored_accounts)
@@ -1102,8 +1047,7 @@ class HyperliquidAccountAnalyzer:
             for metric, description in breakdown.items():
                 print(f"      {description}")
             
-            print(f"   📊 Return: {stats.pnl_percentage:.2f}% (${stats.total_pnl:.2f})")
-            print(f"   🏦 Account Balance: ${stats.account_balance:.2f}")
+            print(f"   💰 Total PnL: ${stats.total_pnl:.2f}")
             print(f"   📈 Win Rate: {stats.win_rate:.1%}")
             print(f"   🕒 Avg Trade Duration: {stats.avg_trade_duration_hours:.1f} hours")
             print(f"   📉 Max Drawdown: {stats.max_drawdown:.1%}")
@@ -1161,11 +1105,11 @@ class HyperliquidAccountAnalyzer:
             else:
                 evaluation.append("⚠️ QUESTIONABLE - Check frequency")
             
-            # Profitability check (using percentage returns for fairness)
-            if stats.pnl_percentage > 0:
-                evaluation.append(f"✅ Profitable ({stats.pnl_percentage:.1f}% return)")
+            # Profitability check
+            if stats.total_pnl > 0:
+                evaluation.append("✅ Profitable")
             else:
-                evaluation.append(f"❌ Not profitable ({stats.pnl_percentage:.1f}% loss)")
+                evaluation.append("❌ Not profitable")
             
             # Trade duration evaluation for copyable accounts
             if is_copyable:
@@ -1287,7 +1231,7 @@ class HyperliquidAccountAnalyzer:
                 risk_indicator = "⛔ DANGEROUS" if score < 0 else "🔴 Risky" if score < 20 else "⚠️ Caution" if score < 40 else "✅ Good"
                 print(f"   {i}. {stats.address[:10]}... - {stats.short_percentage:.1f}% shorts ({short_capability} short capability)")
                 print(f"      Score: {score:.1f}/100 ({risk_indicator}) | Style: {stats.trading_style}")
-                print(f"      Age: {stats.analysis_period_days} days | Return: {stats.pnl_percentage:.1f}% (${stats.total_pnl:.0f}) | Drawdown: {stats.max_drawdown:.1%}")
+                print(f"      Age: {stats.analysis_period_days} days | PnL: ${stats.total_pnl:.0f} | Drawdown: {stats.max_drawdown:.1%}")
                 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]]: