123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- #!/usr/bin/env python3
- """
- Hyperliquid Manual Trading Bot - Main Launcher
- A simple launcher for systemd deployment.
- This is the ONLY file you need to run - it handles everything.
- """
- import sys
- import os
- import asyncio
- import logging
- from datetime import datetime
- from pathlib import Path
- # Bot version
- BOT_VERSION = "2.3.160"
- # Add src directory to Python path
- sys.path.insert(0, str(Path(__file__).parent / "src"))
- try:
- from src.config.config import Config
- from src.bot.core import TelegramTradingBot
- from src.stats import TradingStats
- except ImportError as e:
- print(f"โ Import error: {e}")
- print("๐ก Make sure you're in the correct directory and dependencies are installed")
- sys.exit(1)
- # Global variables for graceful shutdown
- bot_instance = None
- class BotManager:
- """Manages the trading bot with simple startup and shutdown."""
-
- def __init__(self):
- self.bot = None
- self.setup_logging()
-
- # Ensure logs directory exists
- os.makedirs("logs", exist_ok=True)
-
- def setup_logging(self):
- """Set up comprehensive logging."""
- # Create logs directory
- os.makedirs("logs", exist_ok=True)
-
- # Set up file logging
- log_file = f"logs/trading_bot_{datetime.now().strftime('%Y%m%d')}.log"
-
- try:
- from src.config.logging_config import setup_logging
- setup_logging()
- self.logger = logging.getLogger(__name__)
- self.logger.info(f"Logging initialized - Log file: {log_file}")
- except Exception as e:
- # Fallback logging setup
- logging.basicConfig(
- level=logging.INFO,
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
- handlers=[
- logging.FileHandler(log_file),
- logging.StreamHandler()
- ]
- )
- self.logger = logging.getLogger(__name__)
- self.logger.warning(f"Failed to setup advanced logging, using basic setup: {e}")
-
- def print_banner(self):
- """Print startup banner."""
- banner = f"""
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- โ ๐ฑ HYPERLIQUID TRADING BOT โ
- โ Version {BOT_VERSION} โ
- โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฃ
- โ โ
- โ ๐ค Manual phone control via Telegram โ
- โ ๐ Comprehensive trading statistics โ
- โ ๐ก๏ธ Systemd managed service โ
- โ ๐พ Persistent data between restarts โ
- โ ๐ฑ Professional mobile interface โ
- โ โ
- โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- ๐ Starting at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
- ๐ Working directory: {os.getcwd()}
- ๐ Network: {'Testnet' if Config.HYPERLIQUID_TESTNET else '๐จ MAINNET ๐จ'}
- """
- print(banner)
-
- def validate_configuration(self):
- """Validate bot configuration."""
- self.logger.info("๐ Validating configuration...")
-
- missing_config = []
-
- if not hasattr(Config, 'HYPERLIQUID_WALLET_ADDRESS') or not Config.HYPERLIQUID_WALLET_ADDRESS:
- missing_config.append("HYPERLIQUID_WALLET_ADDRESS")
-
- if not hasattr(Config, 'TELEGRAM_BOT_TOKEN') or not Config.TELEGRAM_BOT_TOKEN:
- missing_config.append("TELEGRAM_BOT_TOKEN")
-
- if not hasattr(Config, 'TELEGRAM_CHAT_ID') or not Config.TELEGRAM_CHAT_ID:
- missing_config.append("TELEGRAM_CHAT_ID")
-
- if not hasattr(Config, 'TELEGRAM_ENABLED') or not Config.TELEGRAM_ENABLED:
- missing_config.append("TELEGRAM_ENABLED (must be true)")
-
- if missing_config:
- error_msg = f"โ Missing configuration: {', '.join(missing_config)}"
- self.logger.error(error_msg)
- print(f"\n{error_msg}")
- print("\n๐ก Setup steps:")
- print("1. Copy config: cp config/env.example .env")
- print("2. Get Telegram setup: python utils/get_telegram_chat_id.py")
- print("3. Edit .env with your details")
- print("4. See: SETUP_GUIDE.md for detailed instructions")
- return False
-
- self.logger.info("โ
Configuration validation passed")
- return True
-
- def check_stats_persistence(self):
- """Check and report on statistics persistence."""
- # Check if we have persistent statistics
- self.logger.info("๐ Checking statistics persistence...")
- sqlite_file = "data/trading_stats.sqlite"
- if os.path.exists(sqlite_file):
- try:
- # Quick check to see if database has data
- stats = TradingStats()
- basic_stats = stats.get_basic_stats()
- total_trades = basic_stats.get('total_trades', 0)
- start_date = basic_stats.get('start_date', 'unknown')
- self.logger.info(f"๐ Existing SQLite database found - {total_trades} trades since {start_date}")
- return True
- except Exception as e:
- self.logger.warning(f"โ ๏ธ SQLite database {sqlite_file} exists but couldn't load: {e}")
- return False
- else:
- self.logger.info(f"๐ No existing SQLite database at {sqlite_file} - will create new tracking from launch")
- return False
-
- async def run_bot(self):
- """Run the main bot."""
- try:
- self.logger.info("๐ค Creating TelegramTradingBot instance...")
- self.bot = TelegramTradingBot()
-
- # Set version for bot to use in messages
- self.bot.version = BOT_VERSION
-
- self.logger.info("๐ Checking statistics persistence...")
- self.check_stats_persistence()
-
- self.logger.info("๐ Starting Telegram bot...")
-
- # Run the bot
- await self.bot.run()
-
- except KeyboardInterrupt:
- self.logger.info("๐ Bot stopped by user (Ctrl+C in BotManager.run_bot)")
-
- except Exception as e:
- self.logger.error(f"โ Bot error in BotManager.run_bot: {e}", exc_info=True)
- # Ensure cleanup is attempted
- if self.bot and self.bot.application and self.bot.application._running:
- self.logger.info("Attempting to stop application due to error in run_bot...")
- await self.bot.application.stop()
- raise # Re-raise the exception to be caught by main()
-
- async def start(self):
- """Main entry point for BotManager."""
- try:
- self.print_banner()
-
- if not self.validate_configuration():
- return False
-
- self.logger.info("๐ฏ All systems ready - starting trading bot...")
- print("๐ก Send /start to your Telegram bot for quick actions")
- print("๐ Press Ctrl+C to stop\n")
-
- await self.run_bot()
-
- return True
-
- except Exception as e:
- self.logger.error(f"โ Fatal error in BotManager.start: {e}", exc_info=True)
- print(f"\n๐ฅ Fatal error during bot start: {e}")
- return False
- def main():
- """Main function."""
- global bot_instance
-
- bot_manager = BotManager()
- bot_instance = bot_manager
-
- success = False
- try:
- success = asyncio.run(bot_manager.start())
-
- except KeyboardInterrupt:
- logging.getLogger(__name__).info("๐ Bot stopped by user (Ctrl+C in main).")
- print("\n๐ Bot stopped by user.")
- except Exception as e:
- logging.getLogger(__name__).critical(f"๐ฅ Unexpected critical error in main: {e}", exc_info=True)
- print(f"\n๐ฅ Unexpected critical error: {e}")
- finally:
- logging.getLogger(__name__).info("BotManager main function finished.")
- print("๐ Your trading statistics should have been saved by the bot's internal shutdown.")
- if bot_manager and bot_manager.bot and bot_manager.bot.application:
- if hasattr(bot_manager.bot.application, '_running') and bot_manager.bot.application._running:
- logging.getLogger(__name__).warning("Application was still marked as running in main finally block. Attempting forced synchronous stop. This may not work if loop is closed.")
-
- if not success:
- print("\nโ Bot session ended with errors.")
- if __name__ == "__main__":
- main()
|