config.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. import os
  2. from dotenv import load_dotenv
  3. from typing import Optional
  4. import logging
  5. # Load environment variables from .env file
  6. load_dotenv()
  7. logger = logging.getLogger(__name__)
  8. class Config:
  9. """Configuration class for the Hyperliquid trading bot."""
  10. # Hyperliquid API Configuration
  11. HYPERLIQUID_SECRET_KEY: Optional[str] = os.getenv('HYPERLIQUID_SECRET_KEY') # API generator key
  12. HYPERLIQUID_WALLET_ADDRESS: Optional[str] = os.getenv('HYPERLIQUID_WALLET_ADDRESS') # Wallet address
  13. HYPERLIQUID_TESTNET: bool = os.getenv('HYPERLIQUID_TESTNET', 'true').lower() == 'true'
  14. # Trading Bot Configuration
  15. DEFAULT_TRADING_TOKEN: str = os.getenv('DEFAULT_TRADING_TOKEN', 'BTC')
  16. RISK_MANAGEMENT_ENABLED: bool = os.getenv('RISK_MANAGEMENT_ENABLED', 'true').lower() == 'true'
  17. STOP_LOSS_PERCENTAGE: float = float(os.getenv('STOP_LOSS_PERCENTAGE', '10.0'))
  18. # Telegram Bot Configuration
  19. TELEGRAM_BOT_TOKEN: Optional[str] = os.getenv('TELEGRAM_BOT_TOKEN')
  20. TELEGRAM_CHAT_ID: Optional[str] = os.getenv('TELEGRAM_CHAT_ID')
  21. TELEGRAM_ENABLED: bool = os.getenv('TELEGRAM_ENABLED', 'true').lower() == 'true'
  22. TELEGRAM_DROP_PENDING_UPDATES: bool = os.getenv('TELEGRAM_DROP_PENDING_UPDATES', 'true').lower() == 'true'
  23. # Custom Keyboard Configuration
  24. TELEGRAM_CUSTOM_KEYBOARD_ENABLED: bool = os.getenv('TELEGRAM_CUSTOM_KEYBOARD_ENABLED', 'true').lower() == 'true'
  25. TELEGRAM_CUSTOM_KEYBOARD_LAYOUT: str = os.getenv('TELEGRAM_CUSTOM_KEYBOARD_LAYOUT', '/daily,/performance,/balance|/stats,/positions,/orders|/price,/market,/help,/commands')
  26. # Bot settings
  27. BOT_HEARTBEAT_SECONDS = int(os.getenv('BOT_HEARTBEAT_SECONDS', '5'))
  28. # Market Monitor settings
  29. MARKET_MONITOR_CLEANUP_INTERVAL_HEARTBEATS = 120 # Approx every 10 minutes if heartbeat is 5s
  30. # Order settings
  31. DEFAULT_SLIPPAGE = 0.005 # 0.5%
  32. # Logging
  33. LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO').upper()
  34. # Log file configuration
  35. LOG_TO_FILE: bool = os.getenv('LOG_TO_FILE', 'true').lower() == 'true'
  36. LOG_FILE_PATH: str = os.getenv('LOG_FILE_PATH', 'logs/trading_bot.log')
  37. LOG_MAX_SIZE_MB: int = int(os.getenv('LOG_MAX_SIZE_MB', '10'))
  38. LOG_BACKUP_COUNT: int = int(os.getenv('LOG_BACKUP_COUNT', '5'))
  39. LOG_ROTATION_TYPE: str = os.getenv('LOG_ROTATION_TYPE', 'size') # 'size' or 'time'
  40. LOG_ROTATION_INTERVAL: str = os.getenv('LOG_ROTATION_INTERVAL', 'midnight') # for time rotation
  41. @classmethod
  42. def validate(cls) -> bool:
  43. """Validate all configuration settings."""
  44. is_valid = True
  45. # Validate Hyperliquid settings
  46. if not cls.HYPERLIQUID_WALLET_ADDRESS:
  47. logger.error("❌ HYPERLIQUID_WALLET_ADDRESS is required")
  48. is_valid = False
  49. if not cls.HYPERLIQUID_SECRET_KEY:
  50. logger.error("❌ HYPERLIQUID_SECRET_KEY (API generator key) is required")
  51. is_valid = False
  52. # Validate Telegram settings (if enabled)
  53. if cls.TELEGRAM_ENABLED:
  54. if not cls.TELEGRAM_BOT_TOKEN:
  55. logger.error("❌ TELEGRAM_BOT_TOKEN is required when Telegram is enabled")
  56. is_valid = False
  57. if not cls.TELEGRAM_CHAT_ID:
  58. logger.error("❌ TELEGRAM_CHAT_ID is required when Telegram is enabled")
  59. is_valid = False
  60. # Validate heartbeat interval
  61. if cls.BOT_HEARTBEAT_SECONDS < 5:
  62. logger.error("❌ BOT_HEARTBEAT_SECONDS must be at least 5 seconds to avoid rate limiting")
  63. is_valid = False
  64. elif cls.BOT_HEARTBEAT_SECONDS > 600:
  65. logger.warning("⚠️ BOT_HEARTBEAT_SECONDS is very high (>10 minutes), monitoring may be slow")
  66. # Validate trading settings
  67. if cls.DEFAULT_TRADING_TOKEN == '':
  68. logger.error("❌ DEFAULT_TRADING_TOKEN must be set")
  69. is_valid = False
  70. # Validate logging settings
  71. if cls.LOG_MAX_SIZE_MB <= 0:
  72. logger.error("❌ LOG_MAX_SIZE_MB must be positive")
  73. is_valid = False
  74. if cls.LOG_BACKUP_COUNT < 0:
  75. logger.error("❌ LOG_BACKUP_COUNT must be non-negative")
  76. is_valid = False
  77. if cls.LOG_ROTATION_TYPE not in ['size', 'time']:
  78. logger.error("❌ LOG_ROTATION_TYPE must be 'size' or 'time'")
  79. is_valid = False
  80. return is_valid
  81. @classmethod
  82. def get_hyperliquid_config(cls) -> dict:
  83. """Get Hyperliquid configuration in CCXT format."""
  84. config = {
  85. 'testnet': cls.HYPERLIQUID_TESTNET,
  86. 'sandbox': cls.HYPERLIQUID_TESTNET, # CCXT uses sandbox for testnet
  87. }
  88. # Add authentication if available
  89. # Hyperliquid CCXT implementation expects:
  90. # - apiKey: API generator key (SECRET_KEY)
  91. # - walletAddress: wallet address (WALLET_ADDRESS)
  92. # - secret: (optional, set to wallet address for compatibility)
  93. if cls.HYPERLIQUID_SECRET_KEY:
  94. config['apiKey'] = cls.HYPERLIQUID_SECRET_KEY # API generator key
  95. if cls.HYPERLIQUID_WALLET_ADDRESS:
  96. config['walletAddress'] = cls.HYPERLIQUID_WALLET_ADDRESS # Wallet address
  97. config['secret'] = cls.HYPERLIQUID_WALLET_ADDRESS # Also set as secret for backward compatibility
  98. return config
  99. @classmethod
  100. def print_config(cls):
  101. """Print current configuration (hiding sensitive data)."""
  102. logger.info("🔧 Configuration:")
  103. logger.info(f" 📡 Hyperliquid Testnet: {cls.HYPERLIQUID_TESTNET}")
  104. logger.info(f" 🏠 Wallet Address: {'✅ Set' if cls.HYPERLIQUID_WALLET_ADDRESS else '❌ Missing'}")
  105. logger.info(f" 🔑 API Generator Key: {'✅ Set' if cls.HYPERLIQUID_SECRET_KEY else '❌ Missing'}")
  106. logger.info(f" 📱 Telegram: {'✅ Enabled' if cls.TELEGRAM_ENABLED else '❌ Disabled'}")
  107. logger.info(f" 🔍 Log Level: {cls.LOG_LEVEL}")
  108. logger.info(f" 💾 Log to File: {cls.LOG_TO_FILE}")
  109. logger.info(f" ⏱️ Heartbeat: {cls.BOT_HEARTBEAT_SECONDS}s")
  110. logger.info(f" 💰 DEFAULT_TRADING_TOKEN: {cls.DEFAULT_TRADING_TOKEN}")
  111. logger.info(f" 🧮 RISK_MANAGEMENT_ENABLED: {cls.RISK_MANAGEMENT_ENABLED}")
  112. logger.info(f" 🔄 STOP_LOSS_PERCENTAGE: {cls.STOP_LOSS_PERCENTAGE}%")
  113. logger.info(f" 🤖 TELEGRAM_BOT_TOKEN: {'✅ Set' if cls.TELEGRAM_BOT_TOKEN else '❌ Not Set'}")
  114. logger.info(f" 💬 TELEGRAM_CHAT_ID: {'✅ Set' if cls.TELEGRAM_CHAT_ID else '❌ Not Set'}")
  115. logger.info(f" ⌨️ CUSTOM_KEYBOARD: {'✅ Enabled' if cls.TELEGRAM_CUSTOM_KEYBOARD_ENABLED else '❌ Disabled'}")
  116. logger.info(f" 🔍 LOG_FILE_PATH: {cls.LOG_FILE_PATH}")
  117. logger.info(f" 🔄 LOG_MAX_SIZE_MB: {cls.LOG_MAX_SIZE_MB} MB")
  118. logger.info(f" 🔄 LOG_BACKUP_COUNT: {cls.LOG_BACKUP_COUNT}")
  119. logger.info(f" 🔄 LOG_ROTATION_TYPE: {cls.LOG_ROTATION_TYPE}")
  120. logger.info(f" 🔄 LOG_ROTATION_INTERVAL: {cls.LOG_ROTATION_INTERVAL}")