β ΠΠ°Π·Π°Π΄"""
WT Bot v3 β Main Entry Point
================================
ΠΠ»Π°Π²Π½ΡΠΉ ΡΠΈΠΊΠ»:
1. Nuclear cleanup ΠΏΡΠΈ ΡΡΠ°ΡΡΠ΅
2. Recovery ΠΏΠΎΠ·ΠΈΡΠΈΠΉ
3. ΠΠ°ΠΆΠ΄ΡΠ΅ 5 ΠΌΠΈΠ½ β ΡΠΊΠ°Π½ ΡΡΠ½ΠΊΠ°
4. ΠΠ°ΠΆΠ΄ΡΠ΅ 5 ΡΠ΅ΠΊ β ΠΏΡΠΎΠ²Π΅ΡΠΊΠ° Π²Π°ΠΉΡΠ»ΠΈΡΡΠ° Π½Π° cross + ΠΌΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ ΠΏΠΎΠ·ΠΈΡΠΈΠΉ
"""
import asyncio
import logging
import sys
import os
import time
# Add project root to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.config import SCAN_INTERVAL_SEC, DATA_DIR
from src.exchange import Exchange
from src.screener import Screener
from src.manager import TradeManager
from src.bot import TelegramBot
from src.tmm_client import TMMClient
# ============================================================
# LOGGING
# ============================================================
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
logger = logging.getLogger("main")
# Suppress noisy libs
logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("telegram").setLevel(logging.WARNING)
# ============================================================
# MAIN
# ============================================================
async def main():
logger.info("=" * 50)
logger.info("WT Bot v3 starting...")
logger.info("Strategy: S3_EMA_Filter | TF: 5m | SL 2% / TP 3%")
logger.info("=" * 50)
# Ensure data dir exists
os.makedirs(DATA_DIR, exist_ok=True)
# Init components
exchange = Exchange()
notify_queue = asyncio.Queue()
def sync_notify(msg):
"""Sync wrapper β ΠΊΠ»Π°Π΄ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅ Π² ΠΎΡΠ΅ΡΠ΅Π΄Ρ Π΄Π»Ρ async ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ."""
try:
notify_queue.put_nowait(msg)
except Exception:
pass
screener = Screener(exchange, notifier=sync_notify)
tmm = TMMClient()
bot = TelegramBot(screener=screener, exchange=exchange, tmm=tmm)
manager = TradeManager(exchange, screener, notifier=sync_notify, tmm=tmm)
screener.get_open_positions = lambda: manager.positions # skip WL for open positions
bot.manager = manager
# Start Telegram bot
await bot.start()
logger.info("Telegram bot started")
# Startup notification
balance = exchange.get_balance()
await bot.send_message(
f"π *WT Bot v3 started*\n"
f"Balance: ${balance:.2f}\n"
f"Positions: {len(manager.positions)}\n"
f"Strategy: S3\\_EMA\\_Filter 5m\n"
f"SL 2% / TP 3% | $5Γ10x"
)
# Nuclear cleanup
logger.info("Nuclear cleanup...")
exchange.nuclear_cleanup()
# Recovery
logger.info("Recovery check...")
manager.recovery()
# Main loop
last_scan = 0
check_interval = 5 # ΡΠ΅ΠΊΡΠ½Π΄ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΎΠ²Π΅ΡΠΊΠ°ΠΌΠΈ cross/positions
logger.info("Entering main loop...")
try:
while True:
now = time.time()
# === SCAN (ΠΊΠ°ΠΆΠ΄ΡΠ΅ 5 ΠΌΠΈΠ½) ===
if now - last_scan >= SCAN_INTERVAL_SEC:
try:
screener.run_scan()
last_scan = now
except Exception as e:
logger.error(f"Scan error: {e}")
last_scan = now # ΠΠ΅ ΡΠΏΠ°ΠΌΠΈΠΌ ΠΏΡΠΈ ΠΎΡΠΈΠ±ΠΊΠ΅
# === CHECK WHITELIST FOR ENTRIES ===
try:
manager.check_whitelist_for_entries()
except Exception as e:
logger.error(f"Entry check error: {e}")
# === MONITOR POSITIONS ===
try:
manager.check_positions()
except Exception as e:
logger.error(f"Position check error: {e}")
# === TMM RETRY PENDING TAGS ===
try:
tmm.retry_pending_tags()
except Exception:
pass
# === PROCESS NOTIFY QUEUE ===
while not notify_queue.empty():
try:
msg = notify_queue.get_nowait()
await bot.send_message(msg)
except Exception:
break
# Sleep
await asyncio.sleep(check_interval)
except KeyboardInterrupt:
logger.info("Shutting down...")
except Exception as e:
logger.error(f"Fatal error: {e}", exc_info=True)
await bot.send_message(f"π *Bot crashed:* {str(e)[:200]}")
finally:
await bot.stop()
logger.info("Bot stopped")
if __name__ == "__main__":
asyncio.run(main())