فهرست منبع

Update Hyperliquid API configuration to include wallet address - Added support for specifying a wallet address in the configuration and documentation, enhancing compatibility with CCXT implementation. Improved logging and validation for wallet address usage, ensuring better user guidance and error handling.

Carles Sentis 5 روز پیش
والد
کامیت
efa4c4a664
5فایلهای تغییر یافته به همراه73 افزوده شده و 21 حذف شده
  1. 1 0
      README.md
  2. 9 4
      config/env.example
  3. 6 2
      docs/setup.md
  4. 39 12
      src/config.py
  5. 18 3
      src/hyperliquid_client.py

+ 1 - 0
README.md

@@ -180,6 +180,7 @@ Following [CCXT standards](https://github.com/ccxt/ccxt) for exchange compatibil
 ```env
 # Hyperliquid API (CCXT Style)
 HYPERLIQUID_PRIVATE_KEY=your_api_generator_key_here  # ← Use API Generator Key from app.hyperliquid.xyz/API
+HYPERLIQUID_WALLET_ADDRESS=your_wallet_address_here  # ← Your wallet address (0x...)
 HYPERLIQUID_SECRET_KEY=your_secret_key_here
 HYPERLIQUID_TESTNET=true
 

+ 9 - 4
config/env.example

@@ -1,8 +1,13 @@
 # ========================================
 # Hyperliquid API Configuration (CCXT Style)
 # ========================================
-# Your Hyperliquid private key (required)
-HYPERLIQUID_PRIVATE_KEY=your_private_key_here
+# Your Hyperliquid API Generator Key (SECURE - from https://app.hyperliquid.xyz/API)
+# NEVER use your wallet's private key directly!
+HYPERLIQUID_PRIVATE_KEY=your_api_generator_key_here
+
+# Your wallet address (required by CCXT Hyperliquid implementation)
+# Get this from your wallet interface (0x...)
+HYPERLIQUID_WALLET_ADDRESS=your_wallet_address_here
 
 # Your Hyperliquid secret key (may be optional depending on implementation)
 # Some CCXT exchanges require both apiKey and secret, others only one
@@ -37,10 +42,10 @@ TELEGRAM_ENABLED=true
 # Bot Monitoring Configuration
 # ========================================
 # Heartbeat interval for monitoring orders, positions, and price alarms (in seconds)
-# Default: 30 seconds - good balance between responsiveness and API usage
+# Default: 10 seconds - good balance between responsiveness and API usage
 # Minimum recommended: 10 seconds (to avoid rate limiting)
 # Maximum recommended: 300 seconds (5 minutes)
-BOT_HEARTBEAT_SECONDS=30
+BOT_HEARTBEAT_SECONDS=10
 
 # ========================================
 # Logging

+ 6 - 2
docs/setup.md

@@ -45,6 +45,7 @@ nano .env  # Or use your preferred editor
 ```env
 # Use API Generator Key from https://app.hyperliquid.xyz/API (NOT your wallet private key)
 HYPERLIQUID_PRIVATE_KEY=your_api_generator_key_here
+HYPERLIQUID_WALLET_ADDRESS=your_wallet_address_here
 HYPERLIQUID_SECRET_KEY=your_secret_key_here
 HYPERLIQUID_TESTNET=true
 
@@ -67,12 +68,15 @@ python trading_bot.py
 1. Go to [Hyperliquid API Panel](https://app.hyperliquid.xyz/API)
 2. Generate a dedicated API key for trading
 3. **NEVER use your wallet's private key directly**
-4. Use the generated API key in your `.env` file
+4. Copy your wallet address (0x...) from your wallet interface
+5. Use both the generated API key and wallet address in your `.env` file
 
 ### Testnet (Recommended First)
 1. Go to [Hyperliquid Testnet](https://app.hyperliquid-testnet.xyz/)
 2. Connect/create wallet
-3. Generate API key from API panel
+3. Note your wallet address from the wallet interface
+4. Generate API key from API panel
+5. Use testnet settings in your `.env` file
 
 ### Mainnet (Real Money)
 1. Go to [Hyperliquid](https://app.hyperliquid.xyz/)

+ 39 - 12
src/config.py

@@ -14,6 +14,7 @@ class Config:
     # Hyperliquid API Configuration
     HYPERLIQUID_PRIVATE_KEY: Optional[str] = os.getenv('HYPERLIQUID_PRIVATE_KEY')
     HYPERLIQUID_SECRET_KEY: Optional[str] = os.getenv('HYPERLIQUID_SECRET_KEY')
+    HYPERLIQUID_WALLET_ADDRESS: Optional[str] = os.getenv('HYPERLIQUID_WALLET_ADDRESS')
     HYPERLIQUID_TESTNET: bool = os.getenv('HYPERLIQUID_TESTNET', 'true').lower() == 'true'
     
     # Trading Bot Configuration
@@ -50,6 +51,14 @@ class Config:
             logger.error("❌ HYPERLIQUID_PRIVATE_KEY is required")
             is_valid = False
         
+        # Validate wallet address or private key format
+        if not cls.HYPERLIQUID_WALLET_ADDRESS and cls.HYPERLIQUID_PRIVATE_KEY:
+            # Check if private key looks like an address
+            if not cls.HYPERLIQUID_PRIVATE_KEY.startswith('0x') and len(cls.HYPERLIQUID_PRIVATE_KEY) < 40:
+                logger.warning("⚠️ HYPERLIQUID_WALLET_ADDRESS not set - will attempt to use private key as address")
+            elif len(cls.HYPERLIQUID_PRIVATE_KEY) < 64:
+                logger.warning("⚠️ HYPERLIQUID_WALLET_ADDRESS not set and private key appears short - consider setting explicit wallet address")
+        
         # Validate Telegram settings (if enabled)
         if cls.TELEGRAM_ENABLED:
             if not cls.TELEGRAM_BOT_TOKEN:
@@ -96,11 +105,21 @@ class Config:
         }
         
         # Add authentication if available
-        # Hyperliquid CCXT implementation expects 'privateKey' credential
+        # Hyperliquid CCXT implementation expects 'privateKey' and 'walletAddress' credentials
         if cls.HYPERLIQUID_PRIVATE_KEY:
             config['privateKey'] = cls.HYPERLIQUID_PRIVATE_KEY
             config['apiKey'] = cls.HYPERLIQUID_PRIVATE_KEY  # Keep for backward compatibility
             
+        if cls.HYPERLIQUID_WALLET_ADDRESS:
+            config['walletAddress'] = cls.HYPERLIQUID_WALLET_ADDRESS
+        elif cls.HYPERLIQUID_PRIVATE_KEY:
+            # If no explicit wallet address, try to use the private key as address
+            # (This might work if the private key is actually the wallet address)
+            wallet_addr = cls.HYPERLIQUID_PRIVATE_KEY
+            if not wallet_addr.startswith('0x'):
+                wallet_addr = f"0x{wallet_addr}"
+            config['walletAddress'] = wallet_addr
+            
         if cls.HYPERLIQUID_SECRET_KEY:
             config['secret'] = cls.HYPERLIQUID_SECRET_KEY
             
@@ -109,14 +128,22 @@ class Config:
     @classmethod
     def print_config(cls):
         """Print current configuration (hiding sensitive data)."""
-        print("🔧 Current Configuration:")
-        print(f"  HYPERLIQUID_TESTNET: {cls.HYPERLIQUID_TESTNET}")
-        print(f"  DEFAULT_TRADING_TOKEN: {cls.DEFAULT_TRADING_TOKEN}")
-        print(f"  RISK_MANAGEMENT_ENABLED: {cls.RISK_MANAGEMENT_ENABLED}")
-        print(f"  STOP_LOSS_PERCENTAGE: {cls.STOP_LOSS_PERCENTAGE}%")
-        print(f"  TELEGRAM_ENABLED: {cls.TELEGRAM_ENABLED}")
-        print(f"  LOG_LEVEL: {cls.LOG_LEVEL}")
-        print(f"  PRIVATE_KEY: {'✅ Set' if cls.HYPERLIQUID_PRIVATE_KEY else '❌ Not Set'}")
-        print(f"  SECRET_KEY: {'✅ Set' if cls.HYPERLIQUID_SECRET_KEY else '❌ Not Set'}")
-        print(f"  TELEGRAM_BOT_TOKEN: {'✅ Set' if cls.TELEGRAM_BOT_TOKEN else '❌ Not Set'}")
-        print(f"  TELEGRAM_CHAT_ID: {'✅ Set' if cls.TELEGRAM_CHAT_ID else '❌ Not Set'}") 
+        logger.info("🔧 Configuration:")
+        logger.info(f"  📡 Hyperliquid Testnet: {cls.HYPERLIQUID_TESTNET}")
+        logger.info(f"  🔑 Private Key: {'✅ Set' if cls.HYPERLIQUID_PRIVATE_KEY else '❌ Missing'}")
+        logger.info(f"  🏠 Wallet Address: {'✅ Set' if cls.HYPERLIQUID_WALLET_ADDRESS else '⚠️ Will derive from private key'}")
+        logger.info(f"  🔐 Secret Key: {'✅ Set' if cls.HYPERLIQUID_SECRET_KEY else '⚠️ Missing (may be optional)'}")
+        logger.info(f"  📱 Telegram: {'✅ Enabled' if cls.TELEGRAM_ENABLED else '❌ Disabled'}")
+        logger.info(f"  🔍 Log Level: {cls.LOG_LEVEL}")
+        logger.info(f"  💾 Log to File: {cls.LOG_TO_FILE}")
+        logger.info(f"  ⏱️ Heartbeat: {cls.BOT_HEARTBEAT_SECONDS}s")
+        logger.info(f"  💰 DEFAULT_TRADING_TOKEN: {cls.DEFAULT_TRADING_TOKEN}")
+        logger.info(f"  🧮 RISK_MANAGEMENT_ENABLED: {cls.RISK_MANAGEMENT_ENABLED}")
+        logger.info(f"  🔄 STOP_LOSS_PERCENTAGE: {cls.STOP_LOSS_PERCENTAGE}%")
+        logger.info(f"  🤖 TELEGRAM_BOT_TOKEN: {'✅ Set' if cls.TELEGRAM_BOT_TOKEN else '❌ Not Set'}")
+        logger.info(f"  💬 TELEGRAM_CHAT_ID: {'✅ Set' if cls.TELEGRAM_CHAT_ID else '❌ Not Set'}")
+        logger.info(f"  🔍 LOG_FILE_PATH: {cls.LOG_FILE_PATH}")
+        logger.info(f"  🔄 LOG_MAX_SIZE_MB: {cls.LOG_MAX_SIZE_MB} MB")
+        logger.info(f"  🔄 LOG_BACKUP_COUNT: {cls.LOG_BACKUP_COUNT}")
+        logger.info(f"  🔄 LOG_ROTATION_TYPE: {cls.LOG_ROTATION_TYPE}")
+        logger.info(f"  🔄 LOG_ROTATION_INTERVAL: {cls.LOG_ROTATION_INTERVAL}") 

+ 18 - 3
src/hyperliquid_client.py

@@ -38,6 +38,17 @@ class HyperliquidClient:
         if not self.config.get('apiKey') and Config.HYPERLIQUID_PRIVATE_KEY:
             self.config['apiKey'] = Config.HYPERLIQUID_PRIVATE_KEY
             
+        if not self.config.get('walletAddress'):
+            if Config.HYPERLIQUID_WALLET_ADDRESS:
+                self.config['walletAddress'] = Config.HYPERLIQUID_WALLET_ADDRESS
+            elif Config.HYPERLIQUID_PRIVATE_KEY:
+                # Fallback: try to use private key as wallet address
+                wallet_addr = Config.HYPERLIQUID_PRIVATE_KEY
+                if not wallet_addr.startswith('0x'):
+                    wallet_addr = f"0x{wallet_addr}"
+                self.config['walletAddress'] = wallet_addr
+                logger.warning(f"⚠️ Using private key as wallet address: {wallet_addr[:8]}...")
+            
         if not self.config.get('secret') and Config.HYPERLIQUID_SECRET_KEY:
             self.config['secret'] = Config.HYPERLIQUID_SECRET_KEY
         
@@ -86,6 +97,8 @@ class HyperliquidClient:
             safe_config['apiKey'] = f"{safe_config['apiKey'][:8]}..."
         if 'privateKey' in safe_config and safe_config['privateKey']:
             safe_config['privateKey'] = f"{safe_config['privateKey'][:8]}..."
+        if 'walletAddress' in safe_config and safe_config['walletAddress']:
+            safe_config['walletAddress'] = f"{safe_config['walletAddress'][:8]}..."
         if 'secret' in safe_config and safe_config['secret']:
             safe_config['secret'] = f"{safe_config['secret'][:8]}..."
         return safe_config
@@ -94,11 +107,13 @@ class HyperliquidClient:
         """Return CCXT config with sensitive data masked for logging."""
         safe_config = config.copy()
         if 'apiKey' in safe_config and safe_config['apiKey']:
-            safe_config['apiKey'] = f"{safe_config['apiKey'][:10]}..."
+            safe_config['apiKey'] = f"{safe_config['apiKey'][:8]}..."
         if 'privateKey' in safe_config and safe_config['privateKey']:
-            safe_config['privateKey'] = f"{safe_config['privateKey'][:10]}..."
+            safe_config['privateKey'] = f"{safe_config['privateKey'][:8]}..."
+        if 'walletAddress' in safe_config and safe_config['walletAddress']:
+            safe_config['walletAddress'] = f"{safe_config['walletAddress'][:8]}..."
         if 'secret' in safe_config and safe_config['secret']:
-            safe_config['secret'] = f"{safe_config['secret'][:10]}..."
+            safe_config['secret'] = f"{safe_config['secret'][:8]}..."
         return safe_config
     
     def _test_connection(self):