import asyncio, logging, joblib, time from datetime import datetime from src.config import get_config from src.bot.binance_client import BinanceClientWrapper from src.integrations.telegram_notifier import TelegramNotifier from src.integrations.obsidian_logger import ObsidianLogger from src.strategies.ml_strategy import MLStrategy logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class MLTradingBot: def __init__(self, config, binance, telegram, obsidian, model, scaler): self.config = config self.binance = binance self.telegram = telegram self.obsidian = obsidian self.model = model self.scaler = scaler self.strategy = MLStrategy(trading_pair=config.trading_pair) self.last_report_time = time.time() self.report_interval = 10800 self.trades_today = 0 self.wins_today = 0 self.losses_today = 0 self.daily_pnl = 0.0 self.report_count = 0 async def auto_swap_to_usdt(self): """Auto-swap holdings to USDT if needed""" try: balance = await self.binance.get_balance() usdt_free = float(balance.get('USDT', {}).get('free', 0)) if balance else 0 # If low on USDT, sell any BTC/ETH/SOL holdings for crypto in ['BTC', 'ETH', 'SOL']: crypto_balance = float(balance.get(crypto, {}).get('free', 0)) if balance else 0 if usdt_free < 20 and crypto_balance > 0.0001: pair = crypto + 'USDT' logger.info(f'SWAP: Selling {crypto_balance:.6f} {crypto} for USDT') try: await self.binance.place_order(pair, 'SELL', 'MARKET', crypto_balance * 0.95) await self.telegram.send_alert(f'SWAP: Sold {crypto_balance:.6f} {crypto}') return True except Exception as e: logger.error(f'Swap failed: {e}') except Exception as e: logger.error(f'Auto-swap error: {e}') return False async def find_best_trade(self): """Scan multiple pairs for best signal""" pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'] for pair in pairs: try: price = await self.binance.get_ticker_price(pair) signal = self.strategy.predict(price) if hasattr(self.strategy, 'predict') else 'HOLD' if signal == 'BUY': logger.info(f'BUY signal: {pair} at {price:.2f}') return {'pair': pair, 'price': price, 'signal': signal} except Exception as e: logger.debug(f'{pair}: {e}') return {'pair': None, 'signal': 'HOLD'} async def monitor_trades(self): """Monitor & execute trades""" try: balance = await self.binance.get_balance() usdt = float(balance.get('USDT', {}).get('free', 0)) if balance else 0 # Auto-swap if needed if usdt < 15: await self.auto_swap_to_usdt() return # Find best trade trade = await self.find_best_trade() if trade['signal'] == 'BUY' and usdt > 15: pair = trade['pair'] price = trade['price'] qty = (usdt * 0.7) / price logger.info(f'EXECUTE BUY: {qty:.6f} {pair} @ {price:.2f}') try: await self.binance.place_order(pair, 'BUY', 'MARKET', qty) self.trades_today += 1 await self.telegram.send_alert(f'BUY {pair}\n{qty:.6f} @ {price:.2f}') except Exception as e: logger.error(f'Trade failed: {e}') except Exception as e: logger.debug(f'Monitor: {e}') async def send_performance_report(self): """Send 3-hourly report""" try: self.report_count += 1 price = await self.binance.get_ticker_price(self.config.trading_pair) balance = await self.binance.get_balance() usdt = float(balance.get('USDT', {}).get('free', 0)) if balance else 0 report = f'''REPORT #{self.report_count} BTC: {price:.2f} Balance: {usdt:.2f} USDT Trades: {self.trades_today} Wins: {self.wins_today}''' logger.info(report) await self.telegram.send_alert(report) except Exception as e: logger.error(f'Report error: {e}') async def run(self): """Main bot loop""" logger.info('BOT STARTED - Multi-Crypto Auto-Trading') await self.telegram.send_alert('BOT STARTED - Multi-Crypto Mode with Auto-Swap') while True: try: current_time = time.time() if (current_time - self.last_report_time) >= self.report_interval: await self.send_performance_report() self.last_report_time = current_time await self.monitor_trades() await asyncio.sleep(60) except Exception as e: logger.error(f'Bot error: {e}') await asyncio.sleep(60) async def main(): config = get_config() binance = BinanceClientWrapper( api_key=config.binance_api_key_live, api_secret=config.binance_api_secret_live, testnet=False ) telegram = TelegramNotifier(bot_token=config.telegram_bot_token, chat_id=config.telegram_chat_id) obsidian = ObsidianLogger(vault_path=config.obsidian_vault_path, trade_log_file=config.obsidian_trade_log_file) model = joblib.load(config.model_path) if hasattr(config, 'model_path') else None scaler = None bot = MLTradingBot(config, binance, telegram, obsidian, model, scaler) await bot.run() if __name__ == '__main__': asyncio.run(main())