import asyncio
import json
import websockets
import aiohttp
import time

# ===========================
# CONFIGURACIÓN
# ===========================

SPOT_PAIRS = [
    "btcusdc",
    "ethusdc",
    "solusdc",
    "dogeusdc",
    "ordiusdc",
    "arbisdc",
    "bomeusdc",
    "1000bonkusdc",
    "neirousdc",
]

FUTURES_PAIRS = SPOT_PAIRS.copy()

# Thresholds
SPREAD_THRESHOLD = 0.1
FUNDING_THRESHOLD = 0.02
VOLATILITY_THRESHOLD = 0.1

latest_spot = {}
latest_futures = {}
funding_rates = {}
price_history = {}

# ===========================
# WebSocket Spot
# ===========================
async def listen_spot(symbol):
    uri = f"wss://stream.binance.com:9443/ws/{symbol}@bookTicker"
    async with websockets.connect(uri) as ws:
        async for msg in ws:
            data = json.loads(msg)
            bid = float(data["b"])
            ask = float(data["a"])
            last = (bid + ask) / 2
            qty = float(data["B"])
            latest_spot[symbol] = {
                "bid": bid,
                "ask": ask,
                "last": last,
                "qty": qty,
            }
            # Guardar histórico para volatilidad
            price_history.setdefault(symbol, []).append(last)
            if len(price_history[symbol]) > 60:
                price_history[symbol].pop(0)

# ===========================
# WebSocket Futures
# ===========================
async def listen_futures(symbol):
    uri = f"wss://fstream.binance.com/ws/{symbol}@bookTicker"
    async with websockets.connect(uri) as ws:
        async for msg in ws:
            data = json.loads(msg)
            bid = float(data["b"])
            ask = float(data["a"])
            last = (bid + ask) / 2
            qty = float(data["B"])
            latest_futures[symbol] = {
                "bid": bid,
                "ask": ask,
                "last": last,
                "qty": qty,
            }

# ===========================
# Funding Monitor
# ===========================
async def monitor_funding():
    url = "https://fapi.binance.com/fapi/v1/premiumIndex"
    async with aiohttp.ClientSession() as session:
        while True:
            async with session.get(url) as resp:
                data = await resp.json()
                for item in data:
                    symbol = item["symbol"].lower()
                    if symbol in FUTURES_PAIRS:
                        funding = float(item["lastFundingRate"]) * 100
                        funding_rates[symbol] = funding
            await asyncio.sleep(60)

# ===========================
# Monitor de arbitraje y volatilidad
# ===========================
async def monitor_opportunities():
    while True:
        alerts = []
        for symbol in SPOT_PAIRS:
            spot = latest_spot.get(symbol)
            futures = latest_futures.get(symbol)
            funding = funding_rates.get(symbol, 0)

            if not spot or not futures:
                continue

            # Spread
            spread = ((futures["bid"] - spot["bid"]) / spot["bid"]) * 100

            # Volatilidad
            hist = price_history.get(symbol, [])
            if len(hist) >= 2:
                vol = (max(hist) - min(hist)) / min(hist) * 100
            else:
                vol = 0

            # Chequear si hay señales
            signals = []
            if abs(spread) > SPREAD_THRESHOLD:
                signals.append("Spread")
            if abs(funding) > FUNDING_THRESHOLD:
                signals.append("Funding")
            if vol > VOLATILITY_THRESHOLD:
                signals.append("Volatility")

            # Mostrar resumen si hay algo
            if signals:
                alerts.append(
                    f"{symbol.upper()} Signals: {', '.join(signals)} | "
                    f"Spread: {spread:+.4f}% | Funding: {funding:+.4f}% | Volatility: {vol:.4f}% | "
                    f"SpotBid: {spot['bid']:.6f} (Qty {spot['qty']:.2f}) | FuturesBid: {futures['bid']:.6f} (Qty {futures['qty']:.2f})"
                )


        # Triangular arbitrage básico BTC/ETH/SOL
        btc = latest_spot.get("btcusdc")
        eth = latest_spot.get("ethusdc")
        sol = latest_spot.get("solusdc")
        if btc and eth and sol:
            ratio1 = btc["last"] / eth["last"]
            ratio2 = eth["last"] / sol["last"]
            ratio3 = sol["last"] / btc["last"]
            cycle = ratio1 * ratio2 * ratio3
            triangle_dev = (cycle - 1) * 100

            if abs(triangle_dev) > SPREAD_THRESHOLD:
                alerts.append(
                    f"Triangular Arbitrage BTC/ETH/SOL Δ: {triangle_dev:+.4f}%"
                )

        # Mostrar
        if alerts:
            print("=" * 80)
            for line in alerts:
                print(line)
            print("=" * 80)

        await asyncio.sleep(5)

# ===========================
# MAIN
# ===========================
async def main():
    tasks = []
    for symbol in SPOT_PAIRS:
        tasks.append(listen_spot(symbol))
    for symbol in FUTURES_PAIRS:
        tasks.append(listen_futures(symbol))
    tasks.append(monitor_funding())
    tasks.append(monitor_opportunities())
    await asyncio.gather(*tasks)

if __name__ == "__main__":
    asyncio.run(main())
