import requests import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import ccxt # --- GLOBAL REUSABLE EXCHANGE CONTEXTS (INSTANTIATED ONCE) --- # Reuses long-lived sockets to completely prevent API network connection rate-limits UTIL_EXCHANGES = { 'binance_us': ccxt.binanceus({'enableRateLimit': True}), 'bitget': ccxt.bitget({'enableRateLimit': True}), 'kraken': ccxt.kraken({'enableRateLimit': True}) } def get_live_usdt_dominance(): """Fetches global USDT Dominance to act as a Macro Kill Switch.""" try: url = "https://api.coingecko.com/api/v3/global" response = requests.get(url, timeout=10).json() return response['data']['market_cap_percentage']['usdt'] except Exception as e: print(f"Error fetching macro data: {e}") return 100.0 def send_email_alert(sender_email, sender_password, receiver_email, symbol, message): """Packages and sends the AI trade signal directly to an email inbox.""" try: msg = MIMEMultipart() msg['From'] = sender_email msg['To'] = receiver_email msg['Subject'] = f"🎯 AI TRADE ALERT: Prime Setup on {symbol}" msg.attach(MIMEText(message, 'plain')) server = smtplib.SMTP('smtp.gmail.com', 587) server.starttls() server.login(sender_email, sender_password) server.send_message(msg) server.quit() except Exception as e: print(f"Failed to send email to {receiver_email}: {e}") def get_global_imbalance(symbol): """ Scans persistent live order books to calculate a normalized global imbalance score. Converts native (-1.0 to +1.0) matrix outputs into a standard percentage scale (0.0 to 1.0). """ total_bids_vol = 0 total_asks_vol = 0 successful_exchanges = 0 for name, exchange in UTIL_EXCHANGES.items(): try: # Fetch the top 50 orders for depth analysis using optimized global engine orderbook = exchange.fetch_order_book(symbol, limit=50) bids_vol = sum([bid[1] for bid in orderbook['bids']]) asks_vol = sum([ask[1] for ask in orderbook['asks']]) total_bids_vol += bids_vol total_asks_vol += asks_vol successful_exchanges += 1 except Exception: continue # Return 0.0 to safely fail-close the trade gate if no exchanges answer the socket call if successful_exchanges == 0: return 0.0 # Raw Delta Matrix Formula: Outputs between -1.0 and +1.0 raw_delta_ratio = (total_bids_vol - total_asks_vol) / (total_bids_vol + total_asks_vol + 1e-9) # Mathematical Normalization: Converts raw ratio smoothly onto a strict 0.0 to 1.0 scale # Example: -0.20 becomes 0.40 (40% buy weight) | +0.10 becomes 0.55 (55% buy weight) normalized_percentage = (raw_delta_ratio + 1) / 2 return normalized_percentage