"""Entry point for the ICT Smart Money Concepts Trading Bot. Usage: python main.py # Start live/sandbox trading python main.py --paper # Paper trading mode (no API keys needed) python main.py --backtest # Run backtest python main.py --dashboard # Launch Streamlit dashboard only """ from __future__ import annotations import argparse import asyncio import os import subprocess import sys import threading from pathlib import Path # Suppress SMC startup message (avoids encoding issues on non-UTF8 terminals) os.environ.setdefault("SMC_CREDIT", "0") os.environ.setdefault("PYTHONIOENCODING", "utf-8") from loguru import logger # Ensure project root on path sys.path.insert(0, str(Path(__file__).resolve().parent)) def setup_logging(): """Configure loguru logging.""" from config import settings logger.remove() logger.add(sys.stderr, level=settings.LOG_LEVEL) log_path = Path(settings.LOG_FILE) log_path.parent.mkdir(parents=True, exist_ok=True) logger.add( str(log_path), rotation="10 MB", retention="30 days", level=settings.LOG_LEVEL, ) def ensure_dirs(): """Create required directories.""" Path("data").mkdir(exist_ok=True) Path("logs").mkdir(exist_ok=True) async def run_bot(paper_mode: bool = False): """Start the trading bot.""" from core.bot import ICTBot bot = ICTBot(paper_mode=paper_mode) await bot.start() async def run_backtest(): """Run a backtest using historical data.""" from backtest.backtester import Backtester from backtest.data_loader import DataLoader from execution.paper_exchange import PaperExchangeClient logger.info("Starting backtest...") client = PaperExchangeClient() await client.connect() loader = DataLoader(client) data = await loader.fetch_from_exchange( symbol="BTC/USDT", timeframe="1h", since="2025-01-01", limit=2000, ) await client.disconnect() if data.empty: logger.error("No data loaded for backtest") return bt = Backtester() result = bt.run(data, initial_balance=1000.0) print(Backtester.generate_report(result)) def run_dashboard(): """Launch the Streamlit dashboard.""" dashboard_path = Path(__file__).parent / "dashboard" / "app.py" subprocess.run([sys.executable, "-m", "streamlit", "run", str(dashboard_path), "--server.port", "8501", "--server.headless", "true"]) def launch_dashboard_background(): """Launch dashboard in a background thread.""" t = threading.Thread(target=run_dashboard, daemon=True) t.start() logger.info("Dashboard launched at http://localhost:8501") return t def main(): parser = argparse.ArgumentParser( description="ICT Smart Money Concepts Crypto Trading Bot" ) parser.add_argument( "--backtest", action="store_true", help="Run backtest mode" ) parser.add_argument( "--dashboard", action="store_true", help="Launch Streamlit dashboard only" ) parser.add_argument( "--paper", action="store_true", help="Paper trading mode (no API keys needed)" ) parser.add_argument( "--no-dashboard", action="store_true", help="Disable auto-launching dashboard" ) args = parser.parse_args() setup_logging() ensure_dirs() if args.paper: os.environ["SANDBOX_MODE"] = "true" if args.backtest: asyncio.run(run_backtest()) elif args.dashboard: run_dashboard() else: # Launch dashboard alongside the bot unless disabled if not args.no_dashboard: launch_dashboard_background() asyncio.run(run_bot(paper_mode=args.paper)) if __name__ == "__main__": main()