trading_bot.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #!/usr/bin/env python3
  2. """
  3. Hyperliquid Manual Trading Bot - Main Launcher
  4. A simple launcher for systemd deployment.
  5. This is the ONLY file you need to run - it handles everything.
  6. """
  7. import sys
  8. import os
  9. import asyncio
  10. import logging
  11. from datetime import datetime
  12. from pathlib import Path
  13. # Bot version
  14. BOT_VERSION = "2.4.271"
  15. # Add src directory to Python path
  16. sys.path.insert(0, str(Path(__file__).parent / "src"))
  17. try:
  18. from src.config.config import Config
  19. from src.bot.core import TelegramTradingBot
  20. from src.stats import TradingStats
  21. except ImportError as e:
  22. print(f"❌ Import error: {e}")
  23. print("💡 Make sure you're in the correct directory and dependencies are installed")
  24. sys.exit(1)
  25. # Global variables for graceful shutdown
  26. bot_instance = None
  27. class BotManager:
  28. """Manages the trading bot with simple startup and shutdown."""
  29. def __init__(self):
  30. self.bot = None
  31. self.setup_logging()
  32. # Ensure logs directory exists
  33. os.makedirs("logs", exist_ok=True)
  34. def setup_logging(self):
  35. """Set up comprehensive logging."""
  36. # Create logs directory
  37. os.makedirs("logs", exist_ok=True)
  38. # Set up file logging
  39. log_file = f"logs/trading_bot_{datetime.now().strftime('%Y%m%d')}.log"
  40. try:
  41. from src.config.logging_config import setup_logging
  42. setup_logging()
  43. self.logger = logging.getLogger(__name__)
  44. self.logger.info(f"Logging initialized - Log file: {log_file}")
  45. except Exception as e:
  46. # Fallback logging setup
  47. logging.basicConfig(
  48. level=logging.INFO,
  49. format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
  50. handlers=[
  51. logging.FileHandler(log_file),
  52. logging.StreamHandler()
  53. ]
  54. )
  55. self.logger = logging.getLogger(__name__)
  56. self.logger.warning(f"Failed to setup advanced logging, using basic setup: {e}")
  57. def print_banner(self):
  58. """Print startup banner."""
  59. # Get network and database status
  60. network_status = 'Testnet' if Config.HYPERLIQUID_TESTNET else '🚨 MAINNET 🚨'
  61. db_path = "data/trading_stats.sqlite"
  62. db_status = "✅ Found" if os.path.exists(db_path) else "❌ Not Found"
  63. banner = f"""
  64. \033[1;35m
  65. +-------------------------------------------------------------+
  66. | |
  67. | 📱 H Y P E R L I Q U I D T R A D I N G B O T 📱 |
  68. | |
  69. | Version {BOT_VERSION} |
  70. | |
  71. +-------------------------------------------------------------+
  72. \033[0m
  73. \033[1;34m▶ System Status\033[0m
  74. +--------------------+----------------------------------------+
  75. | \033[1;36mStart Time\033[0m | {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} |
  76. | \033[1;36mWorking Dir\033[0m | {os.getcwd()} |
  77. | \033[1;36mNetwork\033[0m | {network_status} |
  78. | \033[1;36mDatabase\033[0m | {db_status} at {db_path} |
  79. +--------------------+----------------------------------------+
  80. \033[1;34m▶ Key Features\033[0m
  81. +-------------------------------------------------------------+
  82. | |
  83. | 🤖 Control your trades from your phone via Telegram |
  84. | 📊 Get comprehensive, persistent trading statistics |
  85. | 🛡️ Managed as a systemd service for reliability |
  86. | 💾 Data is persistent between restarts |
  87. | 📱 Enjoy a professional, mobile-friendly interface |
  88. | |
  89. +-------------------------------------------------------------+
  90. """
  91. print(banner)
  92. def validate_configuration(self):
  93. """Validate bot configuration."""
  94. self.logger.info("🔍 Validating configuration...")
  95. # Define required configuration attributes
  96. required_configs = {
  97. "HYPERLIQUID_WALLET_ADDRESS": "Your Hyperliquid wallet address",
  98. "TELEGRAM_BOT_TOKEN": "Your Telegram bot token",
  99. "TELEGRAM_CHAT_ID": "Your Telegram chat ID",
  100. "TELEGRAM_ENABLED": "Must be set to true to enable Telegram features"
  101. }
  102. missing_items = []
  103. # Check for missing attributes in the Config class
  104. for attr, description in required_configs.items():
  105. if not getattr(Config, attr, None):
  106. missing_items.append(f"- {attr}: {description}")
  107. # If there are missing items, log and print an error
  108. if missing_items:
  109. error_message = "❌ Missing or invalid configuration:"
  110. detailed_errors = "\n".join(missing_items)
  111. self.logger.error(f"{error_message}\n{detailed_errors}")
  112. # Print a user-friendly guide for fixing the configuration
  113. print(f"\n{error_message}")
  114. print(detailed_errors)
  115. print("\n💡 To fix this, please follow these steps:")
  116. print(" 1. Copy the example config: cp config/env.example .env")
  117. print(" 2. For Telegram setup, run: python utils/get_telegram_chat_id.py")
  118. print(" 3. Edit the .env file with your credentials.")
  119. print(" 4. For more help, see the SETUP_GUIDE.md.")
  120. return False
  121. self.logger.info("✅ Configuration validation passed")
  122. return True
  123. def check_stats_persistence(self):
  124. """Check and report on statistics persistence."""
  125. self.logger.info("📊 Checking for persistent statistics...")
  126. db_file = "data/trading_stats.sqlite"
  127. if not os.path.exists(db_file):
  128. self.logger.warning(f"⚠️ No database found at {db_file}. New statistics will be tracked from scratch.")
  129. print(f"📊 No persistent database found. A new one will be created at {db_file}.")
  130. return
  131. try:
  132. # Attempt to connect and retrieve basic stats
  133. stats = TradingStats()
  134. basic_stats = stats.get_basic_stats()
  135. total_trades = basic_stats.get('total_trades', 0)
  136. start_date = basic_stats.get('start_date', 'N/A')
  137. # Log and print success message
  138. success_message = f"✅ Found existing database with {total_trades} trades since {start_date}."
  139. self.logger.info(success_message)
  140. print(success_message)
  141. except Exception as e:
  142. # Log and print a detailed error message if the database is corrupt or inaccessible
  143. error_message = f"❌ Error loading stats from {db_file}: {e}"
  144. self.logger.error(error_message, exc_info=True)
  145. print(error_message)
  146. print(" - The database file might be corrupted.")
  147. print(" - Consider backing up and deleting the file to start fresh.")
  148. async def run_bot(self):
  149. """Run the main bot."""
  150. try:
  151. self.logger.info("🤖 Creating TelegramTradingBot instance...")
  152. self.bot = TelegramTradingBot()
  153. # Set version for bot to use in messages
  154. self.bot.version = BOT_VERSION
  155. self.logger.info("🚀 Starting Telegram bot...")
  156. # Run the bot
  157. await self.bot.run()
  158. except KeyboardInterrupt:
  159. self.logger.info("👋 Bot stopped by user (Ctrl+C in BotManager.run_bot)")
  160. except Exception as e:
  161. self.logger.error(f"❌ Bot error in BotManager.run_bot: {e}", exc_info=True)
  162. # Ensure cleanup is attempted
  163. if self.bot and self.bot.application and self.bot.application._running:
  164. self.logger.info("Attempting to stop application due to error in run_bot...")
  165. await self.bot.application.stop()
  166. raise # Re-raise the exception to be caught by main()
  167. async def start(self):
  168. """Main entry point for BotManager."""
  169. try:
  170. # Check stats persistence before printing the banner
  171. self.check_stats_persistence()
  172. self.print_banner()
  173. if not self.validate_configuration():
  174. return False
  175. self.logger.info("🎯 All systems ready - starting trading bot...")
  176. print("💡 Send /start to your Telegram bot for quick actions")
  177. print("🛑 Press Ctrl+C to stop\n")
  178. await self.run_bot()
  179. return True
  180. except Exception as e:
  181. self.logger.error(f"❌ Fatal error in BotManager.start: {e}", exc_info=True)
  182. print(f"\n💥 Fatal error during bot start: {e}")
  183. return False
  184. async def main():
  185. bot_manager = BotManager()
  186. await bot_manager.start()
  187. if __name__ == "__main__":
  188. asyncio.run(main())